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

Cache object: 85877d0a6f99c344a9352b4a0dacec66


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