193383Smdodd/* $NetBSD: pdq_ifsubr.c,v 1.38 2001/12/21 23:21:47 matt Exp $ */ 293383Smdodd 321826Sjoerg/*- 421826Sjoerg * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com> 521826Sjoerg * All rights reserved. 621826Sjoerg * 721826Sjoerg * Redistribution and use in source and binary forms, with or without 821826Sjoerg * modification, are permitted provided that the following conditions 921826Sjoerg * are met: 1021826Sjoerg * 1. Redistributions of source code must retain the above copyright 1121826Sjoerg * notice, this list of conditions and the following disclaimer. 1221826Sjoerg * 2. The name of the author may not be used to endorse or promote products 1393383Smdodd * derived from this software without specific prior written permission 1421826Sjoerg * 1521826Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1621826Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1721826Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1821826Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1921826Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2021826Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2121826Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2221826Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2321826Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2421826Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2521826Sjoerg * 2693383Smdodd * $NetBSD: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp$ 2721826Sjoerg */ 2821826Sjoerg 29119418Sobrien#include <sys/cdefs.h> 30119418Sobrien__FBSDID("$FreeBSD$"); 31119418Sobrien 3221826Sjoerg/* 3321826Sjoerg * DEC PDQ FDDI Controller; code for BSD derived operating systems 3421826Sjoerg * 3521826Sjoerg * This module provide bus independent BSD specific O/S functions. 3621826Sjoerg * (ie. it provides an ifnet interface to the rest of the system) 3721826Sjoerg */ 3821826Sjoerg 3921826Sjoerg 4093383Smdodd#define PDQ_OSSUPPORT 4132350Seivind 4221826Sjoerg#include <sys/param.h> 4393383Smdodd#include <sys/systm.h> 4493383Smdodd#include <sys/kernel.h> 4593383Smdodd#include <sys/lock.h> 4693383Smdodd#include <sys/mutex.h> 4793383Smdodd#include <sys/malloc.h> 4821826Sjoerg#include <sys/socket.h> 4924204Sbde#include <sys/sockio.h> 5021826Sjoerg 5193383Smdodd#include <sys/module.h> 5293383Smdodd#include <sys/bus.h> 5393383Smdodd 5493383Smdodd#include <machine/bus.h> 5593383Smdodd#include <machine/resource.h> 5693383Smdodd#include <sys/rman.h> 5793383Smdodd 5821826Sjoerg#include <net/if.h> 5993383Smdodd#include <net/if_arp.h> 6021826Sjoerg#include <net/if_dl.h> 6193383Smdodd#include <net/if_media.h> 62147256Sbrooks#include <net/if_types.h> 6393383Smdodd#include <net/fddi.h> 6421826Sjoerg 6521826Sjoerg#include <net/bpf.h> 6621826Sjoerg 6793383Smdodd#include <dev/pdq/pdq_freebsd.h> 6893383Smdodd#include <dev/pdq/pdqreg.h> 6921826Sjoerg 7093383Smdodddevclass_t pdq_devclass; 7121826Sjoerg 72199542Sjhbstatic void pdq_watchdog(void *); 73199542Sjhb 7421826Sjoergstatic void 75199542Sjhbpdq_ifstop(pdq_softc_t *sc) 7621826Sjoerg{ 77199542Sjhb 78199542Sjhb PDQ_IFNET(sc)->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 79199542Sjhb sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING; 80199542Sjhb pdq_stop(sc->sc_pdq); 81199542Sjhb callout_stop(&sc->watchdog); 82199542Sjhb} 83199542Sjhb 84199542Sjhbstatic void 85199542Sjhbpdq_ifinit_locked(pdq_softc_t *sc) 86199542Sjhb{ 87199542Sjhb 88199542Sjhb PDQ_LOCK_ASSERT(sc); 89147256Sbrooks if (PDQ_IFNET(sc)->if_flags & IFF_UP) { 90148887Srwatson PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_RUNNING; 91147256Sbrooks if (PDQ_IFNET(sc)->if_flags & IFF_PROMISC) { 9221826Sjoerg sc->sc_pdq->pdq_flags |= PDQ_PROMISC; 9321826Sjoerg } else { 9421826Sjoerg sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC; 9521826Sjoerg } 96147256Sbrooks if (PDQ_IFNET(sc)->if_flags & IFF_LINK1) { 9721826Sjoerg sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT; 9821826Sjoerg } else { 9921826Sjoerg sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT; 10021826Sjoerg } 10121826Sjoerg sc->sc_pdq->pdq_flags |= PDQ_RUNNING; 10221826Sjoerg pdq_run(sc->sc_pdq); 103199542Sjhb callout_reset(&sc->watchdog, hz, pdq_watchdog, sc); 104199542Sjhb } else 105199542Sjhb pdq_ifstop(sc); 10621826Sjoerg} 107199542Sjhb 108199542Sjhbstatic void 109199542Sjhbpdq_ifinit(void *arg) 110199542Sjhb{ 111199542Sjhb pdq_softc_t *sc; 112199542Sjhb 113199542Sjhb sc = arg; 114199542Sjhb PDQ_LOCK(sc); 115199542Sjhb pdq_ifinit_locked(sc); 116199542Sjhb PDQ_UNLOCK(sc); 117199542Sjhb} 11821826Sjoerg 11993383Smdoddstatic void 120199542Sjhbpdq_watchdog(void *arg) 12121826Sjoerg{ 122199542Sjhb pdq_softc_t *sc; 123199542Sjhb struct ifnet *ifp; 124199542Sjhb 125199542Sjhb sc = arg; 126199542Sjhb PDQ_LOCK_ASSERT(sc); 127199542Sjhb callout_reset(&sc->watchdog, hz, pdq_watchdog, sc); 128199542Sjhb if (sc->timer == 0 || --sc->timer > 0) 129199542Sjhb return; 130199542Sjhb 13121826Sjoerg /* 13221826Sjoerg * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT 13321826Sjoerg * seconds. Remove all queued packets. 13421826Sjoerg */ 135199542Sjhb ifp = PDQ_IFNET(sc); 136148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 13793383Smdodd for (;;) { 13893383Smdodd struct mbuf *m; 13993383Smdodd IFQ_DEQUEUE(&ifp->if_snd, m); 14093383Smdodd if (m == NULL) 14193383Smdodd return; 14293383Smdodd PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m); 14393383Smdodd } 14421826Sjoerg} 14521826Sjoerg 14693383Smdoddstatic void 147199542Sjhbpdq_ifstart_locked(struct ifnet *ifp) 14821826Sjoerg{ 14993383Smdodd pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 15021826Sjoerg struct mbuf *m; 15121826Sjoerg int tx = 0; 15221826Sjoerg 153199542Sjhb PDQ_LOCK_ASSERT(sc); 154148887Srwatson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 15521826Sjoerg return; 15621826Sjoerg 157199542Sjhb if (sc->timer == 0) 158199542Sjhb sc->timer = PDQ_OS_TX_TIMEOUT; 15921826Sjoerg 16021826Sjoerg if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) { 161148887Srwatson PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_OACTIVE; 16221826Sjoerg return; 16321826Sjoerg } 16493383Smdodd sc->sc_flags |= PDQIF_DOWNCALL; 16521826Sjoerg for (;; tx = 1) { 16693383Smdodd IF_DEQUEUE(&ifp->if_snd, m); 16721826Sjoerg if (m == NULL) 16821826Sjoerg break; 16993383Smdodd#if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX) 17093383Smdodd if ((m->m_flags & M_HASTXDMAMAP) == 0) { 17193383Smdodd bus_dmamap_t map; 17293383Smdodd if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) { 17393383Smdodd m->m_data[0] = PDQ_FDDI_PH0; 17493383Smdodd m->m_data[1] = PDQ_FDDI_PH1; 17593383Smdodd m->m_data[2] = PDQ_FDDI_PH2; 17693383Smdodd } 17793383Smdodd if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255, 17893383Smdodd m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) { 17993383Smdodd if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m, 18093383Smdodd BUS_DMA_WRITE|BUS_DMA_NOWAIT)) { 18193383Smdodd bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len, 18293383Smdodd BUS_DMASYNC_PREWRITE); 18393383Smdodd M_SETCTX(m, map); 18493383Smdodd m->m_flags |= M_HASTXDMAMAP; 18593383Smdodd } 18693383Smdodd } 18793383Smdodd if ((m->m_flags & M_HASTXDMAMAP) == 0) 18893383Smdodd break; 18993383Smdodd } 19093383Smdodd#else 19193383Smdodd if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) { 19293383Smdodd m->m_data[0] = PDQ_FDDI_PH0; 19393383Smdodd m->m_data[1] = PDQ_FDDI_PH1; 19493383Smdodd m->m_data[2] = PDQ_FDDI_PH2; 19593383Smdodd } 19693383Smdodd#endif 19721826Sjoerg 19893383Smdodd if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) 19921826Sjoerg break; 20021826Sjoerg } 20193383Smdodd if (m != NULL) { 202148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 20393383Smdodd IF_PREPEND(&ifp->if_snd, m); 20493383Smdodd } 20521826Sjoerg if (tx) 20621826Sjoerg PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq); 20793383Smdodd sc->sc_flags &= ~PDQIF_DOWNCALL; 20821826Sjoerg} 209199542Sjhb 210199542Sjhbstatic void 211199542Sjhbpdq_ifstart(struct ifnet *ifp) 212199542Sjhb{ 213199542Sjhb pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 214199542Sjhb 215199542Sjhb PDQ_LOCK(sc); 216199542Sjhb pdq_ifstart_locked(ifp); 217199542Sjhb PDQ_UNLOCK(sc); 218199542Sjhb} 21921826Sjoerg 22021826Sjoergvoid 22121826Sjoergpdq_os_receive_pdu( 22221826Sjoerg pdq_t *pdq, 22321826Sjoerg struct mbuf *m, 22493383Smdodd size_t pktlen, 22593383Smdodd int drop) 22621826Sjoerg{ 22793383Smdodd pdq_softc_t *sc = pdq->pdq_os_ctx; 228147256Sbrooks struct ifnet *ifp = PDQ_IFNET(sc); 22993383Smdodd struct fddi_header *fh; 23021826Sjoerg 231106937Ssam ifp->if_ipackets++; 23293383Smdodd#if defined(PDQ_BUS_DMA) 23393383Smdodd { 23493383Smdodd /* 23593383Smdodd * Even though the first mbuf start at the first fddi header octet, 23693383Smdodd * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier. Any additional 23793383Smdodd * mbufs will start normally. 23893383Smdodd */ 23993383Smdodd int offset = PDQ_OS_HDR_OFFSET; 24093383Smdodd struct mbuf *m0; 24193383Smdodd for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) { 24293383Smdodd pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD); 24393383Smdodd bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t)); 24493383Smdodd bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t)); 24593383Smdodd m0->m_flags &= ~M_HASRXDMAMAP; 24693383Smdodd M_SETCTX(m0, NULL); 24793383Smdodd } 24893383Smdodd } 24993383Smdodd#endif 25093383Smdodd m->m_pkthdr.len = pktlen; 25193383Smdodd fh = mtod(m, struct fddi_header *); 25293383Smdodd if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) { 253106937Ssam ifp->if_iqdrops++; 254106937Ssam ifp->if_ierrors++; 25593383Smdodd PDQ_OS_DATABUF_FREE(pdq, m); 25621826Sjoerg return; 25721826Sjoerg } 25821826Sjoerg 259106937Ssam m->m_pkthdr.rcvif = ifp; 260199542Sjhb PDQ_UNLOCK(sc); 261106937Ssam (*ifp->if_input)(ifp, m); 262199542Sjhb PDQ_LOCK(sc); 26321826Sjoerg} 26421826Sjoerg 26521826Sjoergvoid 26621826Sjoergpdq_os_restart_transmitter( 26721826Sjoerg pdq_t *pdq) 26821826Sjoerg{ 26993383Smdodd pdq_softc_t *sc = pdq->pdq_os_ctx; 270148887Srwatson PDQ_IFNET(sc)->if_drv_flags &= ~IFF_DRV_OACTIVE; 271147256Sbrooks if (IFQ_IS_EMPTY(&PDQ_IFNET(sc)->if_snd) == 0) { 272199542Sjhb sc->timer = PDQ_OS_TX_TIMEOUT; 27393383Smdodd if ((sc->sc_flags & PDQIF_DOWNCALL) == 0) 274199542Sjhb pdq_ifstart_locked(PDQ_IFNET(sc)); 27521826Sjoerg } else { 276199542Sjhb sc->timer = 0; 27721826Sjoerg } 27821826Sjoerg} 27921826Sjoerg 28021826Sjoergvoid 28121826Sjoergpdq_os_transmit_done( 28221826Sjoerg pdq_t *pdq, 28321826Sjoerg struct mbuf *m) 28421826Sjoerg{ 28593383Smdodd pdq_softc_t *sc = pdq->pdq_os_ctx; 286170414Smjacob#if defined(NBPFILTER) && NBPFILTER > 0 287147256Sbrooks if (PQD_IFNET(sc)->if_bpf != NULL) 28821826Sjoerg PDQ_BPF_MTAP(sc, m); 28993383Smdodd#endif 29093383Smdodd PDQ_OS_DATABUF_FREE(pdq, m); 291147256Sbrooks PDQ_IFNET(sc)->if_opackets++; 29221826Sjoerg} 29321826Sjoerg 29421826Sjoergvoid 29521826Sjoergpdq_os_addr_fill( 29621826Sjoerg pdq_t *pdq, 29721826Sjoerg pdq_lanaddr_t *addr, 29821826Sjoerg size_t num_addrs) 29921826Sjoerg{ 30093383Smdodd pdq_softc_t *sc = pdq->pdq_os_ctx; 30193383Smdodd struct ifnet *ifp; 30221846Sjoerg struct ifmultiaddr *ifma; 30321826Sjoerg 304147256Sbrooks ifp = sc->ifp; 30593383Smdodd 30693383Smdodd /* 30793383Smdodd * ADDR_FILTER_SET is always issued before FILTER_SET so 30893383Smdodd * we can play with PDQ_ALLMULTI and not worry about 30993383Smdodd * queueing a FILTER_SET ourselves. 31093383Smdodd */ 31193383Smdodd 31293383Smdodd pdq->pdq_flags &= ~PDQ_ALLMULTI; 31393383Smdodd#if defined(IFF_ALLMULTI) 314147256Sbrooks PDQ_IFNET(sc)->if_flags &= ~IFF_ALLMULTI; 31593383Smdodd#endif 31693383Smdodd 317195049Srwatson if_maddr_rlock(PDQ_IFNET(sc)); 318147256Sbrooks for (ifma = TAILQ_FIRST(&PDQ_IFNET(sc)->if_multiaddrs); ifma && num_addrs > 0; 31972084Sphk ifma = TAILQ_NEXT(ifma, ifma_link)) { 32021846Sjoerg char *mcaddr; 32121846Sjoerg if (ifma->ifma_addr->sa_family != AF_LINK) 32221846Sjoerg continue; 32321846Sjoerg mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 32421846Sjoerg ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0]; 32521846Sjoerg ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1]; 32621846Sjoerg ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2]; 32721846Sjoerg addr++; 32821846Sjoerg num_addrs--; 32921826Sjoerg } 330195049Srwatson if_maddr_runlock(PDQ_IFNET(sc)); 33193383Smdodd /* 33293383Smdodd * If not all the address fit into the CAM, turn on all-multicast mode. 33393383Smdodd */ 33493383Smdodd if (ifma != NULL) { 33593383Smdodd pdq->pdq_flags |= PDQ_ALLMULTI; 33693383Smdodd#if defined(IFF_ALLMULTI) 337147256Sbrooks PDQ_IFNET(sc)->if_flags |= IFF_ALLMULTI; 33893383Smdodd#endif 33993383Smdodd } 34021826Sjoerg} 34121826Sjoerg 34293383Smdodd#if defined(IFM_FDDI) 34393383Smdoddstatic int 34493383Smdoddpdq_ifmedia_change( 34593383Smdodd struct ifnet *ifp) 34693383Smdodd{ 34793383Smdodd pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 34893383Smdodd 349199542Sjhb PDQ_LOCK(sc); 35093383Smdodd if (sc->sc_ifmedia.ifm_media & IFM_FDX) { 35193383Smdodd if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) { 35293383Smdodd sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX; 35393383Smdodd if (sc->sc_pdq->pdq_flags & PDQ_RUNNING) 35493383Smdodd pdq_run(sc->sc_pdq); 35593383Smdodd } 35693383Smdodd } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) { 35793383Smdodd sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX; 35893383Smdodd if (sc->sc_pdq->pdq_flags & PDQ_RUNNING) 35993383Smdodd pdq_run(sc->sc_pdq); 36093383Smdodd } 361199542Sjhb PDQ_UNLOCK(sc); 36293383Smdodd 36393383Smdodd return 0; 36493383Smdodd} 36593383Smdodd 36693383Smdoddstatic void 36793383Smdoddpdq_ifmedia_status( 36893383Smdodd struct ifnet *ifp, 36993383Smdodd struct ifmediareq *ifmr) 37093383Smdodd{ 37193383Smdodd pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp); 37293383Smdodd 373199542Sjhb PDQ_LOCK(sc); 37493383Smdodd ifmr->ifm_status = IFM_AVALID; 37593383Smdodd if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING) 37693383Smdodd ifmr->ifm_status |= IFM_ACTIVE; 37793383Smdodd 37893383Smdodd ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX); 37993383Smdodd if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX) 38093383Smdodd ifmr->ifm_active |= IFM_FDX; 381199542Sjhb PDQ_UNLOCK(sc); 38293383Smdodd} 38393383Smdodd 38493383Smdoddvoid 38593383Smdoddpdq_os_update_status( 38693383Smdodd pdq_t *pdq, 38793383Smdodd const void *arg) 38893383Smdodd{ 38993383Smdodd pdq_softc_t * const sc = pdq->pdq_os_ctx; 39093383Smdodd const pdq_response_status_chars_get_t *rsp = arg; 39193383Smdodd int media = 0; 39293383Smdodd 39393383Smdodd switch (rsp->status_chars_get.pmd_type[0]) { 39493383Smdodd case PDQ_PMD_TYPE_ANSI_MUTLI_MODE: media = IFM_FDDI_MMF; break; 39593383Smdodd case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break; 39693383Smdodd case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break; 39793383Smdodd case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break; 39893383Smdodd default: media |= IFM_MANUAL; 39993383Smdodd } 40093383Smdodd 40193383Smdodd if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS) 40293383Smdodd media |= IFM_FDDI_DA; 40393383Smdodd 40493383Smdodd sc->sc_ifmedia.ifm_media = media | IFM_FDDI; 40593383Smdodd} 40693383Smdodd#endif /* defined(IFM_FDDI) */ 40793383Smdodd 40893383Smdoddstatic int 40921826Sjoergpdq_ifioctl( 41021826Sjoerg struct ifnet *ifp, 41193383Smdodd u_long cmd, 41221826Sjoerg caddr_t data) 41321826Sjoerg{ 41493383Smdodd pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp); 41593383Smdodd int error = 0; 41621826Sjoerg 41721826Sjoerg switch (cmd) { 41821826Sjoerg case SIOCSIFFLAGS: { 41921826Sjoerg pdq_ifinit(sc); 42021826Sjoerg break; 42121826Sjoerg } 42221826Sjoerg 42321826Sjoerg case SIOCADDMULTI: 42493383Smdodd case SIOCDELMULTI: { 425199542Sjhb PDQ_LOCK(sc); 426148887Srwatson if (PDQ_IFNET(sc)->if_drv_flags & IFF_DRV_RUNNING) { 42793383Smdodd pdq_run(sc->sc_pdq); 42821826Sjoerg error = 0; 42993383Smdodd } 430199542Sjhb PDQ_UNLOCK(sc); 43193383Smdodd break; 43293383Smdodd } 43321826Sjoerg 43493383Smdodd#if defined(IFM_FDDI) && defined(SIOCSIFMEDIA) 43593383Smdodd case SIOCSIFMEDIA: 43693383Smdodd case SIOCGIFMEDIA: { 43721826Sjoerg struct ifreq *ifr = (struct ifreq *)data; 43893383Smdodd error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); 43921826Sjoerg break; 44021826Sjoerg } 44193383Smdodd#endif 44221826Sjoerg 44321826Sjoerg default: { 444144044Smdodd error = fddi_ioctl(ifp, cmd, data); 44521826Sjoerg break; 44621826Sjoerg } 44721826Sjoerg } 44821826Sjoerg 44921826Sjoerg return error; 45021826Sjoerg} 45121826Sjoerg 45221826Sjoerg#ifndef IFF_NOTRAILERS 45321826Sjoerg#define IFF_NOTRAILERS 0 45421826Sjoerg#endif 45521826Sjoerg 456199542Sjhbint 457199542Sjhbpdq_ifattach(pdq_softc_t *sc, const pdq_uint8_t *llc, pdq_type_t type) 45821826Sjoerg{ 459147256Sbrooks struct ifnet *ifp; 46021826Sjoerg 461147256Sbrooks ifp = PDQ_IFNET(sc) = if_alloc(IFT_FDDI); 462199542Sjhb if (ifp == NULL) { 463199542Sjhb device_printf(sc->dev, "can not if_alloc()\n"); 464199542Sjhb return (ENOSPC); 465199542Sjhb } 466147256Sbrooks 46793818Sjhb mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK, 468199542Sjhb MTX_DEF); 469199542Sjhb callout_init_mtx(&sc->watchdog, &sc->mtx, 0); 47093383Smdodd 471199542Sjhb if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); 47293383Smdodd ifp->if_softc = sc; 473199542Sjhb ifp->if_init = pdq_ifinit; 474207554Ssobomax ifp->if_snd.ifq_maxlen = ifqmaxlen; 47521826Sjoerg ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST; 47621826Sjoerg 47721826Sjoerg ifp->if_ioctl = pdq_ifioctl; 47821826Sjoerg ifp->if_start = pdq_ifstart; 47993383Smdodd 48093383Smdodd#if defined(IFM_FDDI) 48193383Smdodd { 48293383Smdodd const int media = sc->sc_ifmedia.ifm_media; 48393383Smdodd ifmedia_init(&sc->sc_ifmedia, IFM_FDX, 48493383Smdodd pdq_ifmedia_change, pdq_ifmedia_status); 48593383Smdodd ifmedia_add(&sc->sc_ifmedia, media, 0, 0); 48693383Smdodd ifmedia_set(&sc->sc_ifmedia, media); 48793383Smdodd } 48893383Smdodd#endif 48921826Sjoerg 490199542Sjhb sc->sc_pdq = pdq_initialize(sc->mem_bst, sc->mem_bsh, ifp->if_xname, -1, 491199542Sjhb sc, type); 492199542Sjhb if (sc->sc_pdq == NULL) { 493199542Sjhb device_printf(sc->dev, "Initialization failed.\n"); 494199542Sjhb return (ENXIO); 495199542Sjhb } 496199542Sjhb 497152296Sru fddi_ifattach(ifp, llc, FDDI_BPF_SUPPORTED); 498199542Sjhb return (0); 49921826Sjoerg} 50093383Smdodd 50193383Smdoddvoid 50293383Smdoddpdq_ifdetach (pdq_softc_t *sc) 50393383Smdodd{ 50493383Smdodd struct ifnet *ifp; 50593383Smdodd 506147256Sbrooks ifp = sc->ifp; 50793383Smdodd 50893383Smdodd fddi_ifdetach(ifp, FDDI_BPF_SUPPORTED); 509199542Sjhb PDQ_LOCK(sc); 510199542Sjhb pdq_ifstop(sc); 511199542Sjhb PDQ_UNLOCK(sc); 512199542Sjhb callout_drain(&sc->watchdog); 51393383Smdodd pdq_free(sc->dev); 51493383Smdodd 51593383Smdodd return; 51693383Smdodd} 51793383Smdodd 51893383Smdoddvoid 51993383Smdoddpdq_free (device_t dev) 52093383Smdodd{ 52193383Smdodd pdq_softc_t *sc; 52293383Smdodd 52393383Smdodd sc = device_get_softc(dev); 52493383Smdodd 52593383Smdodd if (sc->io) 52693383Smdodd bus_release_resource(dev, sc->io_type, sc->io_rid, sc->io); 52793383Smdodd if (sc->mem) 52893383Smdodd bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem); 52993383Smdodd if (sc->irq_ih) 53093383Smdodd bus_teardown_intr(dev, sc->irq, sc->irq_ih); 53193383Smdodd if (sc->irq) 53293383Smdodd bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); 533199542Sjhb if (sc->ifp) 534199542Sjhb if_free(sc->ifp); 53593383Smdodd 53693383Smdodd /* 53793383Smdodd * Destroy the mutex. 53893383Smdodd */ 53993383Smdodd if (mtx_initialized(&sc->mtx) != 0) { 54093383Smdodd mtx_destroy(&sc->mtx); 54193383Smdodd } 54293383Smdodd 54393383Smdodd return; 54493383Smdodd} 54593383Smdodd 54693383Smdodd#if defined(PDQ_BUS_DMA) 54793383Smdoddint 54893383Smdoddpdq_os_memalloc_contig( 54993383Smdodd pdq_t *pdq) 55093383Smdodd{ 55193383Smdodd pdq_softc_t * const sc = pdq->pdq_os_ctx; 55293383Smdodd bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1]; 55393383Smdodd int db_nsegs = 0, ui_nsegs = 0; 55493383Smdodd int steps = 0; 55593383Smdodd int not_ok; 55693383Smdodd 55793383Smdodd not_ok = bus_dmamem_alloc(sc->sc_dmatag, 55893383Smdodd sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp), 55993383Smdodd sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs, 56093383Smdodd BUS_DMA_NOWAIT); 56193383Smdodd if (!not_ok) { 56293383Smdodd steps = 1; 56393383Smdodd not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs, 56493383Smdodd sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp, 56593383Smdodd BUS_DMA_NOWAIT); 56693383Smdodd } 56793383Smdodd if (!not_ok) { 56893383Smdodd steps = 2; 56993383Smdodd not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1, 57093383Smdodd 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap); 57193383Smdodd } 57293383Smdodd if (!not_ok) { 57393383Smdodd steps = 3; 57493383Smdodd not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap, 57593383Smdodd pdq->pdq_dbp, sizeof(*pdq->pdq_dbp), 57693383Smdodd NULL, BUS_DMA_NOWAIT); 57793383Smdodd } 57893383Smdodd if (!not_ok) { 57993383Smdodd steps = 4; 58093383Smdodd pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr; 58193383Smdodd not_ok = bus_dmamem_alloc(sc->sc_dmatag, 58293383Smdodd PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, 58393383Smdodd ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT); 58493383Smdodd } 58593383Smdodd if (!not_ok) { 58693383Smdodd steps = 5; 58793383Smdodd not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs, 58893383Smdodd PDQ_OS_PAGESIZE, 58993383Smdodd (caddr_t *) &pdq->pdq_unsolicited_info.ui_events, 59093383Smdodd BUS_DMA_NOWAIT); 59193383Smdodd } 59293383Smdodd if (!not_ok) { 59393383Smdodd steps = 6; 59493383Smdodd not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1, 59593383Smdodd PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT, 59693383Smdodd &sc->sc_uimap); 59793383Smdodd } 59893383Smdodd if (!not_ok) { 59993383Smdodd steps = 7; 60093383Smdodd not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap, 60193383Smdodd pdq->pdq_unsolicited_info.ui_events, 60293383Smdodd PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT); 60393383Smdodd } 60493383Smdodd if (!not_ok) { 60593383Smdodd steps = 8; 60693383Smdodd pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr; 60793383Smdodd cb_segs[0] = db_segs[0]; 60893383Smdodd cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer); 60993383Smdodd cb_segs[0].ds_len = sizeof(pdq_consumer_block_t); 61093383Smdodd not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1, 61193383Smdodd sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp, 61293383Smdodd BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 61393383Smdodd } 61493383Smdodd if (!not_ok) { 61593383Smdodd steps = 9; 61693383Smdodd not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1, 61793383Smdodd 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap); 61893383Smdodd } 61993383Smdodd if (!not_ok) { 62093383Smdodd steps = 10; 62193383Smdodd not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap, 62293383Smdodd (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp), 62393383Smdodd NULL, BUS_DMA_NOWAIT); 62493383Smdodd } 62593383Smdodd if (!not_ok) { 62693383Smdodd pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr; 62793383Smdodd return not_ok; 62893383Smdodd } 62993383Smdodd 63093383Smdodd switch (steps) { 63193383Smdodd case 11: { 63293383Smdodd bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap); 63393383Smdodd /* FALL THROUGH */ 63493383Smdodd } 63593383Smdodd case 10: { 63693383Smdodd bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap); 63793383Smdodd /* FALL THROUGH */ 63893383Smdodd } 63993383Smdodd case 9: { 64093383Smdodd bus_dmamem_unmap(sc->sc_dmatag, 64193383Smdodd (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp)); 64293383Smdodd /* FALL THROUGH */ 64393383Smdodd } 64493383Smdodd case 8: { 64593383Smdodd bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap); 64693383Smdodd /* FALL THROUGH */ 64793383Smdodd } 64893383Smdodd case 7: { 64993383Smdodd bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap); 65093383Smdodd /* FALL THROUGH */ 65193383Smdodd } 65293383Smdodd case 6: { 65393383Smdodd bus_dmamem_unmap(sc->sc_dmatag, 65493383Smdodd (caddr_t) pdq->pdq_unsolicited_info.ui_events, 65593383Smdodd PDQ_OS_PAGESIZE); 65693383Smdodd /* FALL THROUGH */ 65793383Smdodd } 65893383Smdodd case 5: { 65993383Smdodd bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs); 66093383Smdodd /* FALL THROUGH */ 66193383Smdodd } 66293383Smdodd case 4: { 66393383Smdodd bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap); 66493383Smdodd /* FALL THROUGH */ 66593383Smdodd } 66693383Smdodd case 3: { 66793383Smdodd bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap); 66893383Smdodd /* FALL THROUGH */ 66993383Smdodd } 67093383Smdodd case 2: { 67193383Smdodd bus_dmamem_unmap(sc->sc_dmatag, 67293383Smdodd (caddr_t) pdq->pdq_dbp, 67393383Smdodd sizeof(*pdq->pdq_dbp)); 67493383Smdodd /* FALL THROUGH */ 67593383Smdodd } 67693383Smdodd case 1: { 67793383Smdodd bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs); 67893383Smdodd /* FALL THROUGH */ 67993383Smdodd } 68093383Smdodd } 68193383Smdodd 68293383Smdodd return not_ok; 68393383Smdodd} 68493383Smdodd 68593383Smdoddextern void 68693383Smdoddpdq_os_descriptor_block_sync( 68793383Smdodd pdq_os_ctx_t *sc, 68893383Smdodd size_t offset, 68993383Smdodd size_t length, 69093383Smdodd int ops) 69193383Smdodd{ 69293383Smdodd bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops); 69393383Smdodd} 69493383Smdodd 69593383Smdoddextern void 69693383Smdoddpdq_os_consumer_block_sync( 69793383Smdodd pdq_os_ctx_t *sc, 69893383Smdodd int ops) 69993383Smdodd{ 70093383Smdodd bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops); 70193383Smdodd} 70293383Smdodd 70393383Smdoddextern void 70493383Smdoddpdq_os_unsolicited_event_sync( 70593383Smdodd pdq_os_ctx_t *sc, 70693383Smdodd size_t offset, 70793383Smdodd size_t length, 70893383Smdodd int ops) 70993383Smdodd{ 71093383Smdodd bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops); 71193383Smdodd} 71293383Smdodd 71393383Smdoddextern void 71493383Smdoddpdq_os_databuf_sync( 71593383Smdodd pdq_os_ctx_t *sc, 71693383Smdodd struct mbuf *m, 71793383Smdodd size_t offset, 71893383Smdodd size_t length, 71993383Smdodd int ops) 72093383Smdodd{ 72193383Smdodd bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops); 72293383Smdodd} 72393383Smdodd 72493383Smdoddextern void 72593383Smdoddpdq_os_databuf_free( 72693383Smdodd pdq_os_ctx_t *sc, 72793383Smdodd struct mbuf *m) 72893383Smdodd{ 72993383Smdodd if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) { 73093383Smdodd bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t); 73193383Smdodd bus_dmamap_unload(sc->sc_dmatag, map); 73293383Smdodd bus_dmamap_destroy(sc->sc_dmatag, map); 73393383Smdodd m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP); 73493383Smdodd } 73593383Smdodd m_freem(m); 73693383Smdodd} 73793383Smdodd 73893383Smdoddextern struct mbuf * 73993383Smdoddpdq_os_databuf_alloc( 74093383Smdodd pdq_os_ctx_t *sc) 74193383Smdodd{ 74293383Smdodd struct mbuf *m; 74393383Smdodd bus_dmamap_t map; 74493383Smdodd 745248078Smarius MGETHDR(m, M_NOWAIT, MT_DATA); 74693383Smdodd if (m == NULL) { 74793383Smdodd printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname); 74893383Smdodd return NULL; 74993383Smdodd } 750248078Smarius MCLGET(m, M_NOWAIT); 75193383Smdodd if ((m->m_flags & M_EXT) == 0) { 75293383Smdodd printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname); 75393383Smdodd m_free(m); 75493383Smdodd return NULL; 75593383Smdodd } 75693383Smdodd m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE; 75793383Smdodd 75893383Smdodd if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE, 75993383Smdodd 1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) { 76093383Smdodd printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname); 76193383Smdodd m_free(m); 76293383Smdodd return NULL; 76393383Smdodd } 76493383Smdodd if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m, 76593383Smdodd BUS_DMA_READ|BUS_DMA_NOWAIT)) { 76693383Smdodd printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname); 76793383Smdodd bus_dmamap_destroy(sc->sc_dmatag, map); 76893383Smdodd m_free(m); 76993383Smdodd return NULL; 77093383Smdodd } 77193383Smdodd m->m_flags |= M_HASRXDMAMAP; 77293383Smdodd M_SETCTX(m, map); 77393383Smdodd return m; 77493383Smdodd} 77593383Smdodd#endif 776