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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
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/10.1/sys/dev/pdq/pdq_ifsubr.c 243857 2012-12-04 09:32:43Z glebius $");
   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_arp.h>
   60 #include <net/if_dl.h>
   61 #include <net/if_media.h> 
   62 #include <net/if_types.h> 
   63 #include <net/fddi.h>
   64 
   65 #include <net/bpf.h>
   66 
   67 #include <dev/pdq/pdq_freebsd.h>
   68 #include <dev/pdq/pdqreg.h>
   69 
   70 devclass_t pdq_devclass;
   71 
   72 static void     pdq_watchdog(void *);
   73 
   74 static void
   75 pdq_ifstop(pdq_softc_t *sc)
   76 {
   77 
   78     PDQ_IFNET(sc)->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
   79     sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
   80     pdq_stop(sc->sc_pdq);
   81     callout_stop(&sc->watchdog);
   82 }
   83 
   84 static void
   85 pdq_ifinit_locked(pdq_softc_t *sc)
   86 {
   87 
   88     PDQ_LOCK_ASSERT(sc);
   89     if (PDQ_IFNET(sc)->if_flags & IFF_UP) {
   90         PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_RUNNING;
   91         if (PDQ_IFNET(sc)->if_flags & IFF_PROMISC) {
   92             sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
   93         } else {
   94             sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
   95         }
   96         if (PDQ_IFNET(sc)->if_flags & IFF_LINK1) {
   97             sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
   98         } else {
   99             sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
  100         }
  101         sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
  102         pdq_run(sc->sc_pdq);
  103         callout_reset(&sc->watchdog, hz, pdq_watchdog, sc);
  104     } else
  105         pdq_ifstop(sc);
  106 }
  107 
  108 static void
  109 pdq_ifinit(void *arg)
  110 {
  111     pdq_softc_t *sc;
  112 
  113     sc = arg;
  114     PDQ_LOCK(sc);
  115     pdq_ifinit_locked(sc);
  116     PDQ_UNLOCK(sc);
  117 }
  118 
  119 static void
  120 pdq_watchdog(void *arg)
  121 {
  122     pdq_softc_t *sc;
  123     struct ifnet *ifp;
  124 
  125     sc = arg;
  126     PDQ_LOCK_ASSERT(sc);
  127     callout_reset(&sc->watchdog, hz, pdq_watchdog, sc);
  128     if (sc->timer == 0 || --sc->timer > 0)
  129         return;
  130 
  131     /*
  132      * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
  133      * seconds.  Remove all queued packets.
  134      */
  135     ifp = PDQ_IFNET(sc);
  136     ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  137     for (;;) {
  138         struct mbuf *m;
  139         IFQ_DEQUEUE(&ifp->if_snd, m);
  140         if (m == NULL)
  141             return;
  142         PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m);
  143     }
  144 }
  145 
  146 static void
  147 pdq_ifstart_locked(struct ifnet *ifp)
  148 {
  149     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  150     struct mbuf *m;
  151     int tx = 0;
  152 
  153     PDQ_LOCK_ASSERT(sc);
  154     if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  155         return;
  156 
  157     if (sc->timer == 0)
  158         sc->timer = PDQ_OS_TX_TIMEOUT;
  159 
  160     if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
  161         PDQ_IFNET(sc)->if_drv_flags |= IFF_DRV_OACTIVE;
  162         return;
  163     }
  164     sc->sc_flags |= PDQIF_DOWNCALL;
  165     for (;; tx = 1) {
  166         IF_DEQUEUE(&ifp->if_snd, m);
  167         if (m == NULL)
  168             break;
  169 #if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX)
  170         if ((m->m_flags & M_HASTXDMAMAP) == 0) {
  171             bus_dmamap_t map;
  172             if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
  173                 m->m_data[0] = PDQ_FDDI_PH0;
  174                 m->m_data[1] = PDQ_FDDI_PH1;
  175                 m->m_data[2] = PDQ_FDDI_PH2;
  176             }
  177             if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255,
  178                                    m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) {
  179                 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
  180                                           BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
  181                     bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len,
  182                                     BUS_DMASYNC_PREWRITE);
  183                     M_SETCTX(m, map);
  184                     m->m_flags |= M_HASTXDMAMAP;
  185                 }
  186             }
  187             if ((m->m_flags & M_HASTXDMAMAP) == 0)
  188                 break;
  189         }
  190 #else
  191         if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
  192             m->m_data[0] = PDQ_FDDI_PH0;
  193             m->m_data[1] = PDQ_FDDI_PH1;
  194             m->m_data[2] = PDQ_FDDI_PH2;
  195         }
  196 #endif
  197 
  198         if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE)
  199             break;
  200     }
  201     if (m != NULL) {
  202         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  203         IF_PREPEND(&ifp->if_snd, m);
  204     }
  205     if (tx)
  206         PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
  207     sc->sc_flags &= ~PDQIF_DOWNCALL;
  208 }
  209 
  210 static void
  211 pdq_ifstart(struct ifnet *ifp)
  212 {
  213     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  214 
  215     PDQ_LOCK(sc);
  216     pdq_ifstart_locked(ifp);
  217     PDQ_UNLOCK(sc);
  218 }
  219 
  220 void
  221 pdq_os_receive_pdu(
  222     pdq_t *pdq,
  223     struct mbuf *m,
  224     size_t pktlen,
  225     int drop)
  226 {
  227     pdq_softc_t *sc = pdq->pdq_os_ctx;
  228     struct ifnet *ifp = PDQ_IFNET(sc);
  229     struct fddi_header *fh;
  230 
  231     ifp->if_ipackets++;
  232 #if defined(PDQ_BUS_DMA)
  233     {
  234         /*
  235          * Even though the first mbuf start at the first fddi header octet,
  236          * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier.  Any additional
  237          * mbufs will start normally.
  238          */
  239         int offset = PDQ_OS_HDR_OFFSET;
  240         struct mbuf *m0;
  241         for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) {
  242             pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD);
  243             bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
  244             bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
  245             m0->m_flags &= ~M_HASRXDMAMAP;
  246             M_SETCTX(m0, NULL);
  247         }
  248     }
  249 #endif
  250     m->m_pkthdr.len = pktlen;
  251     fh = mtod(m, struct fddi_header *);
  252     if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
  253         ifp->if_iqdrops++;
  254         ifp->if_ierrors++;
  255         PDQ_OS_DATABUF_FREE(pdq, m);
  256         return;
  257     }
  258 
  259     m->m_pkthdr.rcvif = ifp;
  260     PDQ_UNLOCK(sc);
  261     (*ifp->if_input)(ifp, m);
  262     PDQ_LOCK(sc);
  263 }
  264 
  265 void
  266 pdq_os_restart_transmitter(
  267     pdq_t *pdq)
  268 {
  269     pdq_softc_t *sc = pdq->pdq_os_ctx;
  270     PDQ_IFNET(sc)->if_drv_flags &= ~IFF_DRV_OACTIVE;
  271     if (IFQ_IS_EMPTY(&PDQ_IFNET(sc)->if_snd) == 0) {
  272         sc->timer = PDQ_OS_TX_TIMEOUT;
  273         if ((sc->sc_flags & PDQIF_DOWNCALL) == 0)
  274             pdq_ifstart_locked(PDQ_IFNET(sc));
  275     } else {
  276         sc->timer = 0;
  277     }
  278 }
  279 
  280 void
  281 pdq_os_transmit_done(
  282     pdq_t *pdq,
  283     struct mbuf *m)
  284 {
  285     pdq_softc_t *sc = pdq->pdq_os_ctx;
  286 #if defined(NBPFILTER) && NBPFILTER > 0
  287     if (PQD_IFNET(sc)->if_bpf != NULL)
  288         PDQ_BPF_MTAP(sc, m);
  289 #endif
  290     PDQ_OS_DATABUF_FREE(pdq, m);
  291     PDQ_IFNET(sc)->if_opackets++;
  292 }
  293 
  294 void
  295 pdq_os_addr_fill(
  296     pdq_t *pdq,
  297     pdq_lanaddr_t *addr,
  298     size_t num_addrs)
  299 {
  300     pdq_softc_t *sc = pdq->pdq_os_ctx;
  301     struct ifnet *ifp;
  302     struct ifmultiaddr *ifma;
  303 
  304     ifp = sc->ifp;
  305 
  306     /*
  307      * ADDR_FILTER_SET is always issued before FILTER_SET so
  308      * we can play with PDQ_ALLMULTI and not worry about 
  309      * queueing a FILTER_SET ourselves.
  310      */
  311 
  312     pdq->pdq_flags &= ~PDQ_ALLMULTI;
  313 #if defined(IFF_ALLMULTI)
  314     PDQ_IFNET(sc)->if_flags &= ~IFF_ALLMULTI;
  315 #endif
  316 
  317     if_maddr_rlock(PDQ_IFNET(sc));
  318     for (ifma = TAILQ_FIRST(&PDQ_IFNET(sc)->if_multiaddrs); ifma && num_addrs > 0;
  319          ifma = TAILQ_NEXT(ifma, ifma_link)) {
  320             char *mcaddr;
  321             if (ifma->ifma_addr->sa_family != AF_LINK)
  322                     continue;
  323             mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
  324             ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0];
  325             ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1];
  326             ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2];
  327             addr++;
  328             num_addrs--;
  329     }
  330     if_maddr_runlock(PDQ_IFNET(sc));
  331     /*
  332      * If not all the address fit into the CAM, turn on all-multicast mode.
  333      */
  334     if (ifma != NULL) {
  335         pdq->pdq_flags |= PDQ_ALLMULTI;
  336 #if defined(IFF_ALLMULTI)
  337         PDQ_IFNET(sc)->if_flags |= IFF_ALLMULTI;
  338 #endif
  339     }
  340 }
  341 
  342 #if defined(IFM_FDDI)
  343 static int
  344 pdq_ifmedia_change(
  345     struct ifnet *ifp)
  346 {
  347     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  348 
  349     PDQ_LOCK(sc);
  350     if (sc->sc_ifmedia.ifm_media & IFM_FDX) {
  351         if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) {
  352             sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX;
  353             if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
  354                 pdq_run(sc->sc_pdq);
  355         }
  356     } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) {
  357         sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX;
  358         if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
  359             pdq_run(sc->sc_pdq);
  360     }
  361     PDQ_UNLOCK(sc);
  362 
  363     return 0;
  364 }
  365 
  366 static void
  367 pdq_ifmedia_status(
  368     struct ifnet *ifp,
  369     struct ifmediareq *ifmr)
  370 {
  371     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  372 
  373     PDQ_LOCK(sc);
  374     ifmr->ifm_status = IFM_AVALID;
  375     if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING)
  376         ifmr->ifm_status |= IFM_ACTIVE;
  377 
  378     ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX);
  379     if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX)
  380         ifmr->ifm_active |= IFM_FDX;
  381     PDQ_UNLOCK(sc);
  382 }
  383 
  384 void
  385 pdq_os_update_status(
  386     pdq_t *pdq,
  387     const void *arg)
  388 {
  389     pdq_softc_t * const sc = pdq->pdq_os_ctx;
  390     const pdq_response_status_chars_get_t *rsp = arg;
  391     int media = 0;
  392 
  393     switch (rsp->status_chars_get.pmd_type[0]) {
  394         case PDQ_PMD_TYPE_ANSI_MUTLI_MODE:         media = IFM_FDDI_MMF; break;
  395         case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break;
  396         case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break;
  397         case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break;
  398         default: media |= IFM_MANUAL;
  399     }
  400 
  401     if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
  402         media |= IFM_FDDI_DA;
  403 
  404     sc->sc_ifmedia.ifm_media = media | IFM_FDDI;
  405 }
  406 #endif /* defined(IFM_FDDI) */
  407 
  408 static int
  409 pdq_ifioctl(
  410     struct ifnet *ifp,
  411     u_long cmd,
  412     caddr_t data)
  413 {
  414     pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  415     int error = 0;
  416 
  417     switch (cmd) {
  418         case SIOCSIFFLAGS: {
  419             pdq_ifinit(sc);
  420             break;
  421         }
  422 
  423         case SIOCADDMULTI:
  424         case SIOCDELMULTI: {
  425             PDQ_LOCK(sc);
  426             if (PDQ_IFNET(sc)->if_drv_flags & IFF_DRV_RUNNING) {
  427                     pdq_run(sc->sc_pdq);
  428                 error = 0;
  429             }
  430             PDQ_UNLOCK(sc);
  431             break;
  432         }
  433 
  434 #if defined(IFM_FDDI) && defined(SIOCSIFMEDIA)
  435         case SIOCSIFMEDIA:
  436         case SIOCGIFMEDIA: {
  437             struct ifreq *ifr = (struct ifreq *)data;
  438             error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
  439             break;
  440         }
  441 #endif
  442 
  443         default: {
  444             error = fddi_ioctl(ifp, cmd, data);
  445             break;
  446         }
  447     }
  448 
  449     return error;
  450 }
  451 
  452 #ifndef IFF_NOTRAILERS
  453 #define IFF_NOTRAILERS  0
  454 #endif
  455 
  456 int
  457 pdq_ifattach(pdq_softc_t *sc, const pdq_uint8_t *llc, pdq_type_t type)
  458 {
  459     struct ifnet *ifp;
  460 
  461     ifp = PDQ_IFNET(sc) = if_alloc(IFT_FDDI);
  462     if (ifp == NULL) {
  463         device_printf(sc->dev, "can not if_alloc()\n");
  464         return (ENOSPC);
  465     }
  466 
  467     mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK,
  468         MTX_DEF);
  469     callout_init_mtx(&sc->watchdog, &sc->mtx, 0);
  470 
  471     if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev));
  472     ifp->if_softc = sc;
  473     ifp->if_init = pdq_ifinit;
  474     ifp->if_snd.ifq_maxlen = ifqmaxlen;
  475     ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
  476 
  477     ifp->if_ioctl = pdq_ifioctl;
  478     ifp->if_start = pdq_ifstart;
  479 
  480 #if defined(IFM_FDDI)
  481     {
  482         const int media = sc->sc_ifmedia.ifm_media;
  483         ifmedia_init(&sc->sc_ifmedia, IFM_FDX,
  484                      pdq_ifmedia_change, pdq_ifmedia_status);
  485         ifmedia_add(&sc->sc_ifmedia, media, 0, 0);
  486         ifmedia_set(&sc->sc_ifmedia, media);
  487     }
  488 #endif
  489   
  490     sc->sc_pdq = pdq_initialize(sc->mem_bst, sc->mem_bsh, ifp->if_xname, -1,
  491         sc, type);
  492     if (sc->sc_pdq == NULL) {
  493         device_printf(sc->dev, "Initialization failed.\n");
  494         return (ENXIO);
  495     }
  496 
  497     fddi_ifattach(ifp, llc, FDDI_BPF_SUPPORTED);
  498     return (0);
  499 }
  500 
  501 void
  502 pdq_ifdetach (pdq_softc_t *sc)
  503 {
  504     struct ifnet *ifp;
  505 
  506     ifp = sc->ifp;
  507 
  508     fddi_ifdetach(ifp, FDDI_BPF_SUPPORTED);
  509     PDQ_LOCK(sc);
  510     pdq_ifstop(sc);
  511     PDQ_UNLOCK(sc);
  512     callout_drain(&sc->watchdog);
  513     pdq_free(sc->dev);
  514 
  515     return;
  516 }
  517 
  518 void
  519 pdq_free (device_t dev)
  520 {
  521         pdq_softc_t *sc;
  522 
  523         sc = device_get_softc(dev);
  524 
  525         if (sc->io)
  526                 bus_release_resource(dev, sc->io_type, sc->io_rid, sc->io);
  527         if (sc->mem)
  528                 bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem);
  529         if (sc->irq_ih)
  530                 bus_teardown_intr(dev, sc->irq, sc->irq_ih);
  531         if (sc->irq)
  532                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
  533         if (sc->ifp)
  534                 if_free(sc->ifp);
  535 
  536         /*
  537          * Destroy the mutex.
  538          */
  539         if (mtx_initialized(&sc->mtx) != 0) {
  540                 mtx_destroy(&sc->mtx);
  541         }
  542 
  543         return;
  544 }
  545 
  546 #if defined(PDQ_BUS_DMA) 
  547 int
  548 pdq_os_memalloc_contig(
  549     pdq_t *pdq)
  550 {
  551     pdq_softc_t * const sc = pdq->pdq_os_ctx;
  552     bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1];
  553     int db_nsegs = 0, ui_nsegs = 0;
  554     int steps = 0;
  555     int not_ok;
  556 
  557     not_ok = bus_dmamem_alloc(sc->sc_dmatag,
  558                          sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp),
  559                          sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs,
  560                          BUS_DMA_NOWAIT);
  561     if (!not_ok) {
  562         steps = 1;
  563         not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs,
  564                                 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp,
  565                                 BUS_DMA_NOWAIT);
  566     }
  567     if (!not_ok) {
  568         steps = 2;
  569         not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1,
  570                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap);
  571     }
  572     if (!not_ok) {
  573         steps = 3;
  574         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap,
  575                                  pdq->pdq_dbp, sizeof(*pdq->pdq_dbp),
  576                                  NULL, BUS_DMA_NOWAIT);
  577     }
  578     if (!not_ok) {
  579         steps = 4;
  580         pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr;
  581         not_ok = bus_dmamem_alloc(sc->sc_dmatag,
  582                          PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE,
  583                          ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT);
  584     }
  585     if (!not_ok) {
  586         steps = 5;
  587         not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs,
  588                             PDQ_OS_PAGESIZE,
  589                             (caddr_t *) &pdq->pdq_unsolicited_info.ui_events,
  590                             BUS_DMA_NOWAIT);
  591     }
  592     if (!not_ok) {
  593         steps = 6;
  594         not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1,
  595                                    PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT,
  596                                    &sc->sc_uimap);
  597     }
  598     if (!not_ok) {
  599         steps = 7;
  600         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap,
  601                                  pdq->pdq_unsolicited_info.ui_events,
  602                                  PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT);
  603     }
  604     if (!not_ok) {
  605         steps = 8;
  606         pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr;
  607         cb_segs[0] = db_segs[0];
  608         cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer);
  609         cb_segs[0].ds_len = sizeof(pdq_consumer_block_t);
  610         not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1,
  611                                 sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp,
  612                                 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
  613     }
  614     if (!not_ok) {
  615         steps = 9;
  616         not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1,
  617                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap);
  618     }
  619     if (!not_ok) {
  620         steps = 10;
  621         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap,
  622                                  (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp),
  623                                  NULL, BUS_DMA_NOWAIT);
  624     }
  625     if (!not_ok) {
  626         pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr;
  627         return not_ok;
  628     }
  629 
  630     switch (steps) {
  631         case 11: {
  632             bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap);
  633             /* FALL THROUGH */
  634         }
  635         case 10: {
  636             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap);
  637             /* FALL THROUGH */
  638         }
  639         case 9: {
  640             bus_dmamem_unmap(sc->sc_dmatag,
  641                              (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp));
  642             /* FALL THROUGH */
  643         }
  644         case 8: {
  645             bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap);
  646             /* FALL THROUGH */
  647         }
  648         case 7: {
  649             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap);
  650             /* FALL THROUGH */
  651         }
  652         case 6: {
  653             bus_dmamem_unmap(sc->sc_dmatag,
  654                              (caddr_t) pdq->pdq_unsolicited_info.ui_events,
  655                              PDQ_OS_PAGESIZE);
  656             /* FALL THROUGH */
  657         }
  658         case 5: {
  659             bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs);
  660             /* FALL THROUGH */
  661         }
  662         case 4: {
  663             bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap);
  664             /* FALL THROUGH */
  665         }
  666         case 3: {
  667             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap);
  668             /* FALL THROUGH */
  669         }
  670         case 2: {
  671             bus_dmamem_unmap(sc->sc_dmatag,
  672                              (caddr_t) pdq->pdq_dbp,
  673                              sizeof(*pdq->pdq_dbp));
  674             /* FALL THROUGH */
  675         }
  676         case 1: {
  677             bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs);
  678             /* FALL THROUGH */
  679         }
  680     }
  681 
  682     return not_ok;
  683 }
  684 
  685 extern void
  686 pdq_os_descriptor_block_sync(
  687     pdq_os_ctx_t *sc,
  688     size_t offset,
  689     size_t length,
  690     int ops)
  691 {
  692     bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops);
  693 }
  694 
  695 extern void
  696 pdq_os_consumer_block_sync(
  697     pdq_os_ctx_t *sc,
  698     int ops)
  699 {
  700     bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops);
  701 }
  702 
  703 extern void
  704 pdq_os_unsolicited_event_sync(
  705     pdq_os_ctx_t *sc,
  706     size_t offset,
  707     size_t length,
  708     int ops)
  709 {
  710     bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops);
  711 }
  712 
  713 extern void
  714 pdq_os_databuf_sync(
  715     pdq_os_ctx_t *sc,
  716     struct mbuf *m,
  717     size_t offset,
  718     size_t length,
  719     int ops)
  720 {
  721     bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops);
  722 }
  723 
  724 extern void
  725 pdq_os_databuf_free(
  726     pdq_os_ctx_t *sc,
  727     struct mbuf *m)
  728 {
  729     if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) {
  730         bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
  731         bus_dmamap_unload(sc->sc_dmatag, map);
  732         bus_dmamap_destroy(sc->sc_dmatag, map);
  733         m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP);
  734     }
  735     m_freem(m);
  736 }
  737 
  738 extern struct mbuf *
  739 pdq_os_databuf_alloc(
  740     pdq_os_ctx_t *sc)
  741 {
  742     struct mbuf *m;
  743     bus_dmamap_t map;
  744 
  745     MGETHDR(m, M_NOWAIT, MT_DATA);
  746     if (m == NULL) {
  747         printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname);
  748         return NULL;
  749     }
  750     MCLGET(m, M_NOWAIT);
  751     if ((m->m_flags & M_EXT) == 0) {
  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: a99a990758a720d0bb232e5957177688


[ 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.