The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/pdq/pdq_ifsubr.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: pdq_ifsubr.c,v 1.38 2001/12/21 23:21:47 matt Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  *
   26  * $NetBSD: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp$
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/11.2/sys/dev/pdq/pdq_ifsubr.c 331722 2018-03-29 02:50:57Z eadler $");
   31 
   32 /*
   33  * DEC PDQ FDDI Controller; code for BSD derived operating systems
   34  *
   35  *      This module provide bus independent BSD specific O/S functions.
   36  *      (ie. it provides an ifnet interface to the rest of the system)
   37  */
   38 
   39 
   40 #define PDQ_OSSUPPORT
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/malloc.h>
   48 #include <sys/socket.h>
   49 #include <sys/sockio.h>
   50 
   51 #include <sys/module.h>
   52 #include <sys/bus.h>
   53 
   54 #include <machine/bus.h>
   55 #include <machine/resource.h>
   56 #include <sys/rman.h> 
   57 
   58 #include <net/if.h>
   59 #include <net/if_var.h>
   60 #include <net/if_arp.h>
   61 #include <net/if_dl.h>
   62 #include <net/if_media.h> 
   63 #include <net/if_types.h> 
   64 #include <net/fddi.h>
   65 
   66 #include <net/bpf.h>
   67 
   68 #include <dev/pdq/pdq_freebsd.h>
   69 #include <dev/pdq/pdqreg.h>
   70 
   71 devclass_t pdq_devclass;
   72 
   73 static void     pdq_watchdog(void *);
   74 
   75 static void
   76 pdq_ifstop(pdq_softc_t *sc)
   77 {
   78 
   79     PDQ_IFNET(sc)->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
   80     sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
   81     pdq_stop(sc->sc_pdq);
   82     callout_stop(&sc->watchdog);
   83 }
   84 
   85 static void
   86 pdq_ifinit_locked(pdq_softc_t *sc)
   87 {
   88 
   89     PDQ_LOCK_ASSERT(sc);
   90     if (PDQ_IFNET(sc)->if_flags & IFF_UP) {
   91         PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_RUNNING;
   92         if (PDQ_IFNET(sc)->if_flags & IFF_PROMISC) {
   93             sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
   94         } else {
   95             sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
   96         }
   97         if (PDQ_IFNET(sc)->if_flags & IFF_LINK1) {
   98             sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
   99         } else {
  100             sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
  101         }
  102         sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
  103         pdq_run(sc->sc_pdq);
  104         callout_reset(&sc->watchdog, hz, pdq_watchdog, sc);
  105     } else
  106         pdq_ifstop(sc);
  107 }
  108 
  109 static void
  110 pdq_ifinit(void *arg)
  111 {
  112     pdq_softc_t *sc;
  113 
  114     sc = arg;
  115     PDQ_LOCK(sc);
  116     pdq_ifinit_locked(sc);
  117     PDQ_UNLOCK(sc);
  118 }
  119 
  120 static void
  121 pdq_watchdog(void *arg)
  122 {
  123     pdq_softc_t *sc;
  124     struct ifnet *ifp;
  125 
  126     sc = arg;
  127     PDQ_LOCK_ASSERT(sc);
  128     callout_reset(&sc->watchdog, hz, pdq_watchdog, sc);
  129     if (sc->timer == 0 || --sc->timer > 0)
  130         return;
  131 
  132     /*
  133      * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
  134      * seconds.  Remove all queued packets.
  135      */
  136     ifp = PDQ_IFNET(sc);
  137     ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  138     for (;;) {
  139         struct mbuf *m;
  140         IFQ_DEQUEUE(&ifp->if_snd, m);
  141         if (m == NULL)
  142             return;
  143         PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m);
  144     }
  145 }
  146 
  147 static void
  148 pdq_ifstart_locked(struct ifnet *ifp)
  149 {
  150     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  151     struct mbuf *m;
  152     int tx = 0;
  153 
  154     PDQ_LOCK_ASSERT(sc);
  155     if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  156         return;
  157 
  158     if (sc->timer == 0)
  159         sc->timer = PDQ_OS_TX_TIMEOUT;
  160 
  161     if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
  162         PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_OACTIVE;
  163         return;
  164     }
  165     sc->sc_flags |= PDQIF_DOWNCALL;
  166     for (;; tx = 1) {
  167         IF_DEQUEUE(&ifp->if_snd, m);
  168         if (m == NULL)
  169             break;
  170 #if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX)
  171         if ((m->m_flags & M_HASTXDMAMAP) == 0) {
  172             bus_dmamap_t map;
  173             if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
  174                 m->m_data[0] = PDQ_FDDI_PH0;
  175                 m->m_data[1] = PDQ_FDDI_PH1;
  176                 m->m_data[2] = PDQ_FDDI_PH2;
  177             }
  178             if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255,
  179                                    m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) {
  180                 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
  181                                           BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
  182                     bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len,
  183                                     BUS_DMASYNC_PREWRITE);
  184                     M_SETCTX(m, map);
  185                     m->m_flags |= M_HASTXDMAMAP;
  186                 }
  187             }
  188             if ((m->m_flags & M_HASTXDMAMAP) == 0)
  189                 break;
  190         }
  191 #else
  192         if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
  193             m->m_data[0] = PDQ_FDDI_PH0;
  194             m->m_data[1] = PDQ_FDDI_PH1;
  195             m->m_data[2] = PDQ_FDDI_PH2;
  196         }
  197 #endif
  198 
  199         if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE)
  200             break;
  201     }
  202     if (m != NULL) {
  203         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  204         IF_PREPEND(&ifp->if_snd, m);
  205     }
  206     if (tx)
  207         PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
  208     sc->sc_flags &= ~PDQIF_DOWNCALL;
  209 }
  210 
  211 static void
  212 pdq_ifstart(struct ifnet *ifp)
  213 {
  214     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  215 
  216     PDQ_LOCK(sc);
  217     pdq_ifstart_locked(ifp);
  218     PDQ_UNLOCK(sc);
  219 }
  220 
  221 void
  222 pdq_os_receive_pdu(
  223     pdq_t *pdq,
  224     struct mbuf *m,
  225     size_t pktlen,
  226     int drop)
  227 {
  228     pdq_softc_t *sc = pdq->pdq_os_ctx;
  229     struct ifnet *ifp = PDQ_IFNET(sc);
  230     struct fddi_header *fh;
  231 
  232     if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
  233 #if defined(PDQ_BUS_DMA)
  234     {
  235         /*
  236          * Even though the first mbuf start at the first fddi header octet,
  237          * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier.  Any additional
  238          * mbufs will start normally.
  239          */
  240         int offset = PDQ_OS_HDR_OFFSET;
  241         struct mbuf *m0;
  242         for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) {
  243             pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD);
  244             bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
  245             bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
  246             m0->m_flags &= ~M_HASRXDMAMAP;
  247             M_SETCTX(m0, NULL);
  248         }
  249     }
  250 #endif
  251     m->m_pkthdr.len = pktlen;
  252     fh = mtod(m, struct fddi_header *);
  253     if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
  254         if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
  255         if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
  256         PDQ_OS_DATABUF_FREE(pdq, m);
  257         return;
  258     }
  259 
  260     m->m_pkthdr.rcvif = ifp;
  261     PDQ_UNLOCK(sc);
  262     (*ifp->if_input)(ifp, m);
  263     PDQ_LOCK(sc);
  264 }
  265 
  266 void
  267 pdq_os_restart_transmitter(
  268     pdq_t *pdq)
  269 {
  270     pdq_softc_t *sc = pdq->pdq_os_ctx;
  271     PDQ_IFNET(sc)->if_drv_flags &= ~IFF_DRV_OACTIVE;
  272     if (IFQ_IS_EMPTY(&PDQ_IFNET(sc)->if_snd) == 0) {
  273         sc->timer = PDQ_OS_TX_TIMEOUT;
  274         if ((sc->sc_flags & PDQIF_DOWNCALL) == 0)
  275             pdq_ifstart_locked(PDQ_IFNET(sc));
  276     } else {
  277         sc->timer = 0;
  278     }
  279 }
  280 
  281 void
  282 pdq_os_transmit_done(
  283     pdq_t *pdq,
  284     struct mbuf *m)
  285 {
  286     pdq_softc_t *sc = pdq->pdq_os_ctx;
  287 #if defined(NBPFILTER) && NBPFILTER > 0
  288     if (PQD_IFNET(sc)->if_bpf != NULL)
  289         PDQ_BPF_MTAP(sc, m);
  290 #endif
  291     PDQ_OS_DATABUF_FREE(pdq, m);
  292     if_inc_counter(PDQ_IFNET(sc), IFCOUNTER_OPACKETS, 1);
  293 }
  294 
  295 void
  296 pdq_os_addr_fill(
  297     pdq_t *pdq,
  298     pdq_lanaddr_t *addr,
  299     size_t num_addrs)
  300 {
  301     pdq_softc_t *sc = pdq->pdq_os_ctx;
  302     struct ifnet *ifp;
  303     struct ifmultiaddr *ifma;
  304 
  305     ifp = sc->ifp;
  306 
  307     /*
  308      * ADDR_FILTER_SET is always issued before FILTER_SET so
  309      * we can play with PDQ_ALLMULTI and not worry about 
  310      * queueing a FILTER_SET ourselves.
  311      */
  312 
  313     pdq->pdq_flags &= ~PDQ_ALLMULTI;
  314 #if defined(IFF_ALLMULTI)
  315     PDQ_IFNET(sc)->if_flags &= ~IFF_ALLMULTI;
  316 #endif
  317 
  318     if_maddr_rlock(PDQ_IFNET(sc));
  319     for (ifma = TAILQ_FIRST(&PDQ_IFNET(sc)->if_multiaddrs); ifma && num_addrs > 0;
  320          ifma = TAILQ_NEXT(ifma, ifma_link)) {
  321             char *mcaddr;
  322             if (ifma->ifma_addr->sa_family != AF_LINK)
  323                     continue;
  324             mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
  325             ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0];
  326             ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1];
  327             ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2];
  328             addr++;
  329             num_addrs--;
  330     }
  331     if_maddr_runlock(PDQ_IFNET(sc));
  332     /*
  333      * If not all the address fit into the CAM, turn on all-multicast mode.
  334      */
  335     if (ifma != NULL) {
  336         pdq->pdq_flags |= PDQ_ALLMULTI;
  337 #if defined(IFF_ALLMULTI)
  338         PDQ_IFNET(sc)->if_flags |= IFF_ALLMULTI;
  339 #endif
  340     }
  341 }
  342 
  343 #if defined(IFM_FDDI)
  344 static int
  345 pdq_ifmedia_change(
  346     struct ifnet *ifp)
  347 {
  348     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  349 
  350     PDQ_LOCK(sc);
  351     if (sc->sc_ifmedia.ifm_media & IFM_FDX) {
  352         if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) {
  353             sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX;
  354             if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
  355                 pdq_run(sc->sc_pdq);
  356         }
  357     } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) {
  358         sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX;
  359         if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
  360             pdq_run(sc->sc_pdq);
  361     }
  362     PDQ_UNLOCK(sc);
  363 
  364     return 0;
  365 }
  366 
  367 static void
  368 pdq_ifmedia_status(
  369     struct ifnet *ifp,
  370     struct ifmediareq *ifmr)
  371 {
  372     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  373 
  374     PDQ_LOCK(sc);
  375     ifmr->ifm_status = IFM_AVALID;
  376     if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING)
  377         ifmr->ifm_status |= IFM_ACTIVE;
  378 
  379     ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX);
  380     if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX)
  381         ifmr->ifm_active |= IFM_FDX;
  382     PDQ_UNLOCK(sc);
  383 }
  384 
  385 void
  386 pdq_os_update_status(
  387     pdq_t *pdq,
  388     const void *arg)
  389 {
  390     pdq_softc_t * const sc = pdq->pdq_os_ctx;
  391     const pdq_response_status_chars_get_t *rsp = arg;
  392     int media = 0;
  393 
  394     switch (rsp->status_chars_get.pmd_type[0]) {
  395         case PDQ_PMD_TYPE_ANSI_MUTLI_MODE:         media = IFM_FDDI_MMF; break;
  396         case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break;
  397         case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break;
  398         case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break;
  399         default: media |= IFM_MANUAL;
  400     }
  401 
  402     if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
  403         media |= IFM_FDDI_DA;
  404 
  405     sc->sc_ifmedia.ifm_media = media | IFM_FDDI;
  406 }
  407 #endif /* defined(IFM_FDDI) */
  408 
  409 static int
  410 pdq_ifioctl(
  411     struct ifnet *ifp,
  412     u_long cmd,
  413     caddr_t data)
  414 {
  415     pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  416     int error = 0;
  417 
  418     switch (cmd) {
  419         case SIOCSIFFLAGS: {
  420             pdq_ifinit(sc);
  421             break;
  422         }
  423 
  424         case SIOCADDMULTI:
  425         case SIOCDELMULTI: {
  426             PDQ_LOCK(sc);
  427             if (PDQ_IFNET(sc)->if_drv_flags & IFF_DRV_RUNNING) {
  428                     pdq_run(sc->sc_pdq);
  429                 error = 0;
  430             }
  431             PDQ_UNLOCK(sc);
  432             break;
  433         }
  434 
  435 #if defined(IFM_FDDI) && defined(SIOCSIFMEDIA)
  436         case SIOCSIFMEDIA:
  437         case SIOCGIFMEDIA: {
  438             struct ifreq *ifr = (struct ifreq *)data;
  439             error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
  440             break;
  441         }
  442 #endif
  443 
  444         default: {
  445             error = fddi_ioctl(ifp, cmd, data);
  446             break;
  447         }
  448     }
  449 
  450     return error;
  451 }
  452 
  453 #ifndef IFF_NOTRAILERS
  454 #define IFF_NOTRAILERS  0
  455 #endif
  456 
  457 int
  458 pdq_ifattach(pdq_softc_t *sc, const pdq_uint8_t *llc, pdq_type_t type)
  459 {
  460     struct ifnet *ifp;
  461 
  462     ifp = PDQ_IFNET(sc) = if_alloc(IFT_FDDI);
  463     if (ifp == NULL) {
  464         device_printf(sc->dev, "can not if_alloc()\n");
  465         return (ENOSPC);
  466     }
  467 
  468     mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK,
  469         MTX_DEF);
  470     callout_init_mtx(&sc->watchdog, &sc->mtx, 0);
  471 
  472     if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev));
  473     ifp->if_softc = sc;
  474     ifp->if_init = pdq_ifinit;
  475     ifp->if_snd.ifq_maxlen = ifqmaxlen;
  476     ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
  477 
  478     ifp->if_ioctl = pdq_ifioctl;
  479     ifp->if_start = pdq_ifstart;
  480 
  481 #if defined(IFM_FDDI)
  482     {
  483         const int media = sc->sc_ifmedia.ifm_media;
  484         ifmedia_init(&sc->sc_ifmedia, IFM_FDX,
  485                      pdq_ifmedia_change, pdq_ifmedia_status);
  486         ifmedia_add(&sc->sc_ifmedia, media, 0, 0);
  487         ifmedia_set(&sc->sc_ifmedia, media);
  488     }
  489 #endif
  490   
  491     sc->sc_pdq = pdq_initialize(sc->mem_bst, sc->mem_bsh, ifp->if_xname, -1,
  492         sc, type);
  493     if (sc->sc_pdq == NULL) {
  494         device_printf(sc->dev, "Initialization failed.\n");
  495         return (ENXIO);
  496     }
  497 
  498     fddi_ifattach(ifp, llc, FDDI_BPF_SUPPORTED);
  499     return (0);
  500 }
  501 
  502 void
  503 pdq_ifdetach (pdq_softc_t *sc)
  504 {
  505     struct ifnet *ifp;
  506 
  507     ifp = sc->ifp;
  508 
  509     fddi_ifdetach(ifp, FDDI_BPF_SUPPORTED);
  510     PDQ_LOCK(sc);
  511     pdq_ifstop(sc);
  512     PDQ_UNLOCK(sc);
  513     callout_drain(&sc->watchdog);
  514     pdq_free(sc->dev);
  515 
  516     return;
  517 }
  518 
  519 void
  520 pdq_free (device_t dev)
  521 {
  522         pdq_softc_t *sc;
  523 
  524         sc = device_get_softc(dev);
  525 
  526         if (sc->io)
  527                 bus_release_resource(dev, sc->io_type, sc->io_rid, sc->io);
  528         if (sc->mem)
  529                 bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem);
  530         if (sc->irq_ih)
  531                 bus_teardown_intr(dev, sc->irq, sc->irq_ih);
  532         if (sc->irq)
  533                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
  534         if (sc->ifp)
  535                 if_free(sc->ifp);
  536 
  537         /*
  538          * Destroy the mutex.
  539          */
  540         if (mtx_initialized(&sc->mtx) != 0) {
  541                 mtx_destroy(&sc->mtx);
  542         }
  543 
  544         return;
  545 }
  546 
  547 #if defined(PDQ_BUS_DMA) 
  548 int
  549 pdq_os_memalloc_contig(
  550     pdq_t *pdq)
  551 {
  552     pdq_softc_t * const sc = pdq->pdq_os_ctx;
  553     bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1];
  554     int db_nsegs = 0, ui_nsegs = 0;
  555     int steps = 0;
  556     int not_ok;
  557 
  558     not_ok = bus_dmamem_alloc(sc->sc_dmatag,
  559                          sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp),
  560                          sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs,
  561                          BUS_DMA_NOWAIT);
  562     if (!not_ok) {
  563         steps = 1;
  564         not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs,
  565                                 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp,
  566                                 BUS_DMA_NOWAIT);
  567     }
  568     if (!not_ok) {
  569         steps = 2;
  570         not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1,
  571                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap);
  572     }
  573     if (!not_ok) {
  574         steps = 3;
  575         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap,
  576                                  pdq->pdq_dbp, sizeof(*pdq->pdq_dbp),
  577                                  NULL, BUS_DMA_NOWAIT);
  578     }
  579     if (!not_ok) {
  580         steps = 4;
  581         pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr;
  582         not_ok = bus_dmamem_alloc(sc->sc_dmatag,
  583                          PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE,
  584                          ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT);
  585     }
  586     if (!not_ok) {
  587         steps = 5;
  588         not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs,
  589                             PDQ_OS_PAGESIZE,
  590                             (caddr_t *) &pdq->pdq_unsolicited_info.ui_events,
  591                             BUS_DMA_NOWAIT);
  592     }
  593     if (!not_ok) {
  594         steps = 6;
  595         not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1,
  596                                    PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT,
  597                                    &sc->sc_uimap);
  598     }
  599     if (!not_ok) {
  600         steps = 7;
  601         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap,
  602                                  pdq->pdq_unsolicited_info.ui_events,
  603                                  PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT);
  604     }
  605     if (!not_ok) {
  606         steps = 8;
  607         pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr;
  608         cb_segs[0] = db_segs[0];
  609         cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer);
  610         cb_segs[0].ds_len = sizeof(pdq_consumer_block_t);
  611         not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1,
  612                                 sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp,
  613                                 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
  614     }
  615     if (!not_ok) {
  616         steps = 9;
  617         not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1,
  618                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap);
  619     }
  620     if (!not_ok) {
  621         steps = 10;
  622         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap,
  623                                  (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp),
  624                                  NULL, BUS_DMA_NOWAIT);
  625     }
  626     if (!not_ok) {
  627         pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr;
  628         return not_ok;
  629     }
  630 
  631     switch (steps) {
  632         case 11: {
  633             bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap);
  634             /* FALL THROUGH */
  635         }
  636         case 10: {
  637             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap);
  638             /* FALL THROUGH */
  639         }
  640         case 9: {
  641             bus_dmamem_unmap(sc->sc_dmatag,
  642                              (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp));
  643             /* FALL THROUGH */
  644         }
  645         case 8: {
  646             bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap);
  647             /* FALL THROUGH */
  648         }
  649         case 7: {
  650             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap);
  651             /* FALL THROUGH */
  652         }
  653         case 6: {
  654             bus_dmamem_unmap(sc->sc_dmatag,
  655                              (caddr_t) pdq->pdq_unsolicited_info.ui_events,
  656                              PDQ_OS_PAGESIZE);
  657             /* FALL THROUGH */
  658         }
  659         case 5: {
  660             bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs);
  661             /* FALL THROUGH */
  662         }
  663         case 4: {
  664             bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap);
  665             /* FALL THROUGH */
  666         }
  667         case 3: {
  668             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap);
  669             /* FALL THROUGH */
  670         }
  671         case 2: {
  672             bus_dmamem_unmap(sc->sc_dmatag,
  673                              (caddr_t) pdq->pdq_dbp,
  674                              sizeof(*pdq->pdq_dbp));
  675             /* FALL THROUGH */
  676         }
  677         case 1: {
  678             bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs);
  679             /* FALL THROUGH */
  680         }
  681     }
  682 
  683     return not_ok;
  684 }
  685 
  686 extern void
  687 pdq_os_descriptor_block_sync(
  688     pdq_os_ctx_t *sc,
  689     size_t offset,
  690     size_t length,
  691     int ops)
  692 {
  693     bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops);
  694 }
  695 
  696 extern void
  697 pdq_os_consumer_block_sync(
  698     pdq_os_ctx_t *sc,
  699     int ops)
  700 {
  701     bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops);
  702 }
  703 
  704 extern void
  705 pdq_os_unsolicited_event_sync(
  706     pdq_os_ctx_t *sc,
  707     size_t offset,
  708     size_t length,
  709     int ops)
  710 {
  711     bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops);
  712 }
  713 
  714 extern void
  715 pdq_os_databuf_sync(
  716     pdq_os_ctx_t *sc,
  717     struct mbuf *m,
  718     size_t offset,
  719     size_t length,
  720     int ops)
  721 {
  722     bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops);
  723 }
  724 
  725 extern void
  726 pdq_os_databuf_free(
  727     pdq_os_ctx_t *sc,
  728     struct mbuf *m)
  729 {
  730     if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) {
  731         bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
  732         bus_dmamap_unload(sc->sc_dmatag, map);
  733         bus_dmamap_destroy(sc->sc_dmatag, map);
  734         m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP);
  735     }
  736     m_freem(m);
  737 }
  738 
  739 extern struct mbuf *
  740 pdq_os_databuf_alloc(
  741     pdq_os_ctx_t *sc)
  742 {
  743     struct mbuf *m;
  744     bus_dmamap_t map;
  745 
  746     MGETHDR(m, M_NOWAIT, MT_DATA);
  747     if (m == NULL) {
  748         printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname);
  749         return NULL;
  750     }
  751     if (!(MCLGET(m, M_NOWAIT))) {
  752         printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname);
  753         m_free(m);
  754         return NULL;
  755     }
  756     m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE;
  757 
  758     if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE,
  759                            1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) {
  760         printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname);
  761         m_free(m);
  762         return NULL;
  763     }
  764     if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
  765                              BUS_DMA_READ|BUS_DMA_NOWAIT)) {
  766         printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname);
  767         bus_dmamap_destroy(sc->sc_dmatag, map);
  768         m_free(m);
  769         return NULL;
  770     }
  771     m->m_flags |= M_HASRXDMAMAP;
  772     M_SETCTX(m, map);
  773     return m;
  774 }
  775 #endif

Cache object: 2444a8e2a475c08f432ec11687a6bd65


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.