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/ic/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.47 2006/11/16 01:32:52 christos 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  * Id: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp
   27  *
   28  */
   29 
   30 /*
   31  * DEC PDQ FDDI Controller; code for BSD derived operating systems
   32  *
   33  *      This module provide bus independent BSD specific O/S functions.
   34  *      (ie. it provides an ifnet interface to the rest of the system)
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: pdq_ifsubr.c,v 1.47 2006/11/16 01:32:52 christos Exp $");
   39 
   40 #ifdef __NetBSD__
   41 #include "opt_inet.h"
   42 #endif
   43 
   44 #include <sys/param.h>
   45 #include <sys/kernel.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/protosw.h>
   48 #include <sys/socket.h>
   49 #include <sys/ioctl.h>
   50 #include <sys/errno.h>
   51 #include <sys/malloc.h>
   52 #if defined(__FreeBSD__) && BSD < 199401
   53 #include <sys/devconf.h>
   54 #elif defined(__bsdi__) || defined(__NetBSD__)
   55 #include <sys/device.h>
   56 #endif
   57 
   58 #include <net/if.h>
   59 #include <net/if_types.h>
   60 #include <net/if_dl.h>
   61 #if !defined(__NetBSD__)
   62 #include <net/route.h>
   63 #endif
   64 
   65 #include "bpfilter.h"
   66 #if NBPFILTER > 0
   67 #include <net/bpf.h>
   68 #include <net/bpfdesc.h>
   69 #endif
   70 
   71 #ifdef INET
   72 #include <netinet/in.h>
   73 #include <netinet/in_systm.h>
   74 #include <netinet/in_var.h>
   75 #include <netinet/ip.h>
   76 #if defined(__NetBSD__)
   77 #include <netinet/if_inarp.h>
   78 #endif
   79 #endif
   80 #if defined(__FreeBSD__)
   81 #include <netinet/if_ether.h>
   82 #include <netinet/if_fddi.h>
   83 #else
   84 #include <net/if_fddi.h>
   85 #endif
   86 
   87 #if defined(__bsdi__)
   88 #include <netinet/if_ether.h>
   89 #include <i386/isa/isavar.h>
   90 #endif
   91 
   92 
   93 #ifndef __NetBSD__
   94 #include <vm/vm.h>
   95 #endif
   96 
   97 #if defined(__FreeBSD__)
   98 /*
   99  * Yet another specific ifdef for FreeBSD as it diverges...
  100  */
  101 #include <dev/pdq/pdqvar.h>
  102 #include <dev/pdq/pdqreg.h>
  103 #else
  104 #include "pdqvar.h"
  105 #include "pdqreg.h"
  106 #endif
  107 
  108 #if defined(__bsdi__) && _BSDI_VERSION < 199506 /* XXX */
  109 static void
  110 arp_ifinit(
  111     struct arpcom *ac,
  112     struct ifaddr *ifa)
  113 {
  114     sc->sc_ac.ac_ipaddr = IA_SIN(ifa)->sin_addr;
  115     arpwhohas(&sc->sc_ac, &IA_SIN(ifa)->sin_addr);
  116 #if _BSDI_VERSION >= 199401
  117     ifa->ifa_rtrequest = arp_rtrequest;
  118     ifa->ifa_flags |= RTF_CLONING;
  119 #endif
  120 #endif
  121 
  122 
  123 void
  124 pdq_ifinit(
  125     pdq_softc_t *sc)
  126 {
  127     if (sc->sc_if.if_flags & IFF_UP) {
  128         sc->sc_if.if_flags |= IFF_RUNNING;
  129 #if NBPFILTER > 0
  130         if (sc->sc_if.if_flags & IFF_PROMISC) {
  131             sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
  132         } else {
  133             sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
  134         }
  135 #endif
  136         if (sc->sc_if.if_flags & IFF_LINK1) {
  137             sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
  138         } else {
  139             sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
  140         }
  141         sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
  142         pdq_run(sc->sc_pdq);
  143     } else {
  144         sc->sc_if.if_flags &= ~IFF_RUNNING;
  145         sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
  146         pdq_stop(sc->sc_pdq);
  147     }
  148 }
  149 
  150 void
  151 pdq_ifwatchdog(
  152     struct ifnet *ifp)
  153 {
  154     /*
  155      * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
  156      * seconds.  Remove all queued packets.
  157      */
  158 
  159     ifp->if_flags &= ~IFF_OACTIVE;
  160     ifp->if_timer = 0;
  161     for (;;) {
  162         struct mbuf *m;
  163         IFQ_DEQUEUE(&ifp->if_snd, m);
  164         if (m == NULL)
  165             return;
  166         PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m);
  167     }
  168 }
  169 
  170 ifnet_ret_t
  171 pdq_ifstart(
  172     struct ifnet *ifp)
  173 {
  174     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  175     struct mbuf *m;
  176     int tx = 0;
  177 
  178     if ((ifp->if_flags & IFF_RUNNING) == 0)
  179         return;
  180 
  181     if (sc->sc_if.if_timer == 0)
  182         sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
  183 
  184     if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
  185         sc->sc_if.if_flags |= IFF_OACTIVE;
  186         return;
  187     }
  188     sc->sc_flags |= PDQIF_DOWNCALL;
  189     for (;; tx = 1) {
  190         IFQ_POLL(&ifp->if_snd, m);
  191         if (m == NULL)
  192             break;
  193 #if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX)
  194         if ((m->m_flags & M_HASTXDMAMAP) == 0) {
  195             bus_dmamap_t map;
  196             if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
  197                 m->m_data[0] = PDQ_FDDI_PH0;
  198                 m->m_data[1] = PDQ_FDDI_PH1;
  199                 m->m_data[2] = PDQ_FDDI_PH2;
  200             }
  201             if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255,
  202                                    m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) {
  203                 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
  204                                           BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
  205                     bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len,
  206                                     BUS_DMASYNC_PREWRITE);
  207                     M_SETCTX(m, map);
  208                     m->m_flags |= M_HASTXDMAMAP;
  209                 }
  210             }
  211             if ((m->m_flags & M_HASTXDMAMAP) == 0)
  212                 break;
  213         }
  214 #else
  215         if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
  216             m->m_data[0] = PDQ_FDDI_PH0;
  217             m->m_data[1] = PDQ_FDDI_PH1;
  218             m->m_data[2] = PDQ_FDDI_PH2;
  219         }
  220 #endif
  221 
  222         if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE)
  223             break;
  224         IFQ_DEQUEUE(&ifp->if_snd, m);
  225     }
  226     if (m != NULL)
  227         ifp->if_flags |= IFF_OACTIVE;
  228     if (tx)
  229         PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
  230     sc->sc_flags &= ~PDQIF_DOWNCALL;
  231 }
  232 
  233 void
  234 pdq_os_receive_pdu(
  235     pdq_t *pdq,
  236     struct mbuf *m,
  237     size_t pktlen,
  238     int drop)
  239 {
  240     pdq_softc_t *sc = pdq->pdq_os_ctx;
  241     struct fddi_header *fh;
  242 
  243     sc->sc_if.if_ipackets++;
  244 #if defined(PDQ_BUS_DMA)
  245     {
  246         /*
  247          * Even though the first mbuf start at the first fddi header octet,
  248          * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier.  Any additional
  249          * mbufs will start normally.
  250          */
  251         int offset = PDQ_OS_HDR_OFFSET;
  252         struct mbuf *m0;
  253         for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) {
  254             pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD);
  255             bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
  256             bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
  257             m0->m_flags &= ~M_HASRXDMAMAP;
  258             M_SETCTX(m0, NULL);
  259         }
  260     }
  261 #endif
  262     m->m_pkthdr.len = pktlen;
  263 #if NBPFILTER > 0
  264     if (sc->sc_bpf != NULL)
  265         PDQ_BPF_MTAP(sc, m);
  266 #endif
  267     fh = mtod(m, struct fddi_header *);
  268     if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
  269         PDQ_OS_DATABUF_FREE(pdq, m);
  270         return;
  271     }
  272 
  273     m->m_pkthdr.rcvif = &sc->sc_if;
  274     (*sc->sc_if.if_input)(&sc->sc_if, m);
  275 }
  276 
  277 void
  278 pdq_os_restart_transmitter(
  279     pdq_t *pdq)
  280 {
  281     pdq_softc_t *sc = pdq->pdq_os_ctx;
  282     sc->sc_if.if_flags &= ~IFF_OACTIVE;
  283     if (IFQ_IS_EMPTY(&sc->sc_if.if_snd) == 0) {
  284         sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
  285         if ((sc->sc_flags & PDQIF_DOWNCALL) == 0)
  286             pdq_ifstart(&sc->sc_if);
  287     } else {
  288         sc->sc_if.if_timer = 0;
  289     }
  290 }
  291 
  292 void
  293 pdq_os_transmit_done(
  294     pdq_t *pdq,
  295     struct mbuf *m)
  296 {
  297     pdq_softc_t *sc = pdq->pdq_os_ctx;
  298 #if NBPFILTER > 0
  299     if (sc->sc_bpf != NULL)
  300         PDQ_BPF_MTAP(sc, m);
  301 #endif
  302     PDQ_OS_DATABUF_FREE(pdq, m);
  303     sc->sc_if.if_opackets++;
  304 }
  305 
  306 void
  307 pdq_os_addr_fill(
  308     pdq_t *pdq,
  309     pdq_lanaddr_t *addr,
  310     size_t num_addrs)
  311 {
  312     pdq_softc_t *sc = pdq->pdq_os_ctx;
  313     struct ether_multistep step;
  314     struct ether_multi *enm;
  315 
  316     /*
  317      * ADDR_FILTER_SET is always issued before FILTER_SET so
  318      * we can play with PDQ_ALLMULTI and not worry about
  319      * queueing a FILTER_SET ourselves.
  320      */
  321 
  322     pdq->pdq_flags &= ~PDQ_ALLMULTI;
  323 #if defined(IFF_ALLMULTI)
  324     sc->sc_if.if_flags &= ~IFF_ALLMULTI;
  325 #endif
  326 
  327     ETHER_FIRST_MULTI(step, PDQ_FDDICOM(sc), enm);
  328     while (enm != NULL && num_addrs > 0) {
  329         if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) == 0) {
  330             ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) enm->enm_addrlo)[0];
  331             ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) enm->enm_addrlo)[1];
  332             ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) enm->enm_addrlo)[2];
  333             addr++;
  334             num_addrs--;
  335         } else {
  336             pdq->pdq_flags |= PDQ_ALLMULTI;
  337 #if defined(IFF_ALLMULTI)
  338             sc->sc_if.if_flags |= IFF_ALLMULTI;
  339 #endif
  340         }
  341         ETHER_NEXT_MULTI(step, enm);
  342     }
  343     /*
  344      * If not all the address fit into the CAM, turn on all-multicast mode.
  345      */
  346     if (enm != NULL) {
  347         pdq->pdq_flags |= PDQ_ALLMULTI;
  348 #if defined(IFF_ALLMULTI)
  349         sc->sc_if.if_flags |= IFF_ALLMULTI;
  350 #endif
  351     }
  352 }
  353 
  354 #if defined(IFM_FDDI)
  355 static int
  356 pdq_ifmedia_change(
  357     struct ifnet *ifp)
  358 {
  359     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  360 
  361     if (sc->sc_ifmedia.ifm_media & IFM_FDX) {
  362         if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) {
  363             sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX;
  364             if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
  365                 pdq_run(sc->sc_pdq);
  366         }
  367     } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) {
  368         sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX;
  369         if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
  370             pdq_run(sc->sc_pdq);
  371     }
  372 
  373     return 0;
  374 }
  375 
  376 static void
  377 pdq_ifmedia_status(
  378     struct ifnet *ifp,
  379     struct ifmediareq *ifmr)
  380 {
  381     pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  382 
  383     ifmr->ifm_status = IFM_AVALID;
  384     if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING)
  385         ifmr->ifm_status |= IFM_ACTIVE;
  386 
  387     ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX);
  388     if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX)
  389         ifmr->ifm_active |= IFM_FDX;
  390 }
  391 
  392 void
  393 pdq_os_update_status(
  394     pdq_t *pdq,
  395     const void *arg)
  396 {
  397     pdq_softc_t * const sc = pdq->pdq_os_ctx;
  398     const pdq_response_status_chars_get_t *rsp = arg;
  399     int media = 0;
  400 
  401     switch (rsp->status_chars_get.pmd_type[0]) {
  402         case PDQ_PMD_TYPE_ANSI_MUTLI_MODE:         media = IFM_FDDI_MMF; break;
  403         case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break;
  404         case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break;
  405         case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break;
  406         default: media |= IFM_MANUAL;
  407     }
  408 
  409     if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
  410         media |= IFM_FDDI_DA;
  411 
  412     sc->sc_ifmedia.ifm_media = media | IFM_FDDI;
  413 }
  414 #endif /* defined(IFM_FDDI) */
  415 
  416 int
  417 pdq_ifioctl(
  418     struct ifnet *ifp,
  419     ioctl_cmd_t cmd,
  420     caddr_t data)
  421 {
  422     pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp);
  423     int s, error = 0;
  424 
  425     s = PDQ_OS_SPL_RAISE();
  426 
  427     switch (cmd) {
  428         case SIOCSIFADDR: {
  429             struct ifaddr *ifa = (struct ifaddr *)data;
  430 
  431             ifp->if_flags |= IFF_UP;
  432             switch(ifa->ifa_addr->sa_family) {
  433 #if defined(INET)
  434                 case AF_INET: {
  435                     pdq_ifinit(sc);
  436                     PDQ_ARP_IFINIT(sc, ifa);
  437                     break;
  438                 }
  439 #endif /* INET */
  440 
  441 
  442                 default: {
  443                     pdq_ifinit(sc);
  444                     break;
  445                 }
  446             }
  447             break;
  448         }
  449         case SIOCGIFADDR: {
  450             struct ifreq *ifr = (struct ifreq *)data;
  451             memcpy((caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data,
  452                 (caddr_t) PDQ_LANADDR(sc), 6);
  453             break;
  454         }
  455 
  456         case SIOCSIFFLAGS: {
  457             pdq_ifinit(sc);
  458             break;
  459         }
  460 
  461         case SIOCADDMULTI:
  462         case SIOCDELMULTI: {
  463             /*
  464              * Update multicast listeners
  465              */
  466             if (cmd == SIOCADDMULTI)
  467                 error = ether_addmulti((struct ifreq *)data, PDQ_FDDICOM(sc));
  468             else
  469                 error = ether_delmulti((struct ifreq *)data, PDQ_FDDICOM(sc));
  470 
  471             if (error == ENETRESET) {
  472                 if (sc->sc_if.if_flags & IFF_RUNNING)
  473                     pdq_run(sc->sc_pdq);
  474                 error = 0;
  475             }
  476             break;
  477         }
  478 
  479 #if defined(SIOCSIFMTU)
  480 #if !defined(ifr_mtu)
  481 #define ifr_mtu ifr_metric
  482 #endif
  483         case SIOCSIFMTU: {
  484             struct ifreq *ifr = (struct ifreq *)data;
  485             /*
  486              * Set the interface MTU.
  487              */
  488             if (ifr->ifr_mtu > FDDIMTU) {
  489                 error = EINVAL;
  490                 break;
  491             }
  492             ifp->if_mtu = ifr->ifr_mtu;
  493             break;
  494         }
  495 #endif /* SIOCSIFMTU */
  496 
  497 #if defined(IFM_FDDI) && defined(SIOCSIFMEDIA)
  498         case SIOCSIFMEDIA:
  499         case SIOCGIFMEDIA: {
  500             struct ifreq *ifr = (struct ifreq *)data;
  501             error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
  502             break;
  503         }
  504 #endif
  505 
  506         default: {
  507             error = EINVAL;
  508             break;
  509         }
  510     }
  511 
  512     PDQ_OS_SPL_LOWER(s);
  513     return error;
  514 }
  515 
  516 #ifndef IFF_NOTRAILERS
  517 #define IFF_NOTRAILERS  0
  518 #endif
  519 
  520 void
  521 pdq_ifattach(
  522     pdq_softc_t *sc,
  523     ifnet_ret_t (*ifwatchdog)(int unit))
  524 {
  525     struct ifnet *ifp = &sc->sc_if;
  526 
  527     ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
  528 
  529 #if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__)
  530     ifp->if_watchdog = pdq_ifwatchdog;
  531 #else
  532     ifp->if_watchdog = ifwatchdog;
  533 #endif
  534 
  535     ifp->if_ioctl = pdq_ifioctl;
  536 #if !defined(__NetBSD__)
  537     ifp->if_output = fddi_output;
  538 #endif
  539     ifp->if_start = pdq_ifstart;
  540     IFQ_SET_READY(&ifp->if_snd);
  541 
  542 #if defined(IFM_FDDI)
  543     {
  544         const int media = sc->sc_ifmedia.ifm_media;
  545         ifmedia_init(&sc->sc_ifmedia, IFM_FDX,
  546                      pdq_ifmedia_change, pdq_ifmedia_status);
  547         ifmedia_add(&sc->sc_ifmedia, media, 0, 0);
  548         ifmedia_set(&sc->sc_ifmedia, media);
  549     }
  550 #endif
  551 
  552     if_attach(ifp);
  553 #if defined(__NetBSD__)
  554     fddi_ifattach(ifp, (caddr_t)&sc->sc_pdq->pdq_hwaddr);
  555 #else
  556     fddi_ifattach(ifp);
  557 #endif
  558 }
  559 
  560 #if defined(PDQ_BUS_DMA)
  561 int
  562 pdq_os_memalloc_contig(
  563     pdq_t *pdq)
  564 {
  565     pdq_softc_t * const sc = pdq->pdq_os_ctx;
  566     bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1];
  567     int db_nsegs = 0, ui_nsegs = 0;
  568     int steps = 0;
  569     int not_ok;
  570 
  571     not_ok = bus_dmamem_alloc(sc->sc_dmatag,
  572                          sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp),
  573                          sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs,
  574 #if defined(__sparc__) || defined(__sparc64__)
  575                         BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
  576 #else
  577                         BUS_DMA_NOWAIT);
  578 #endif
  579     if (!not_ok) {
  580         steps = 1;
  581         not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs,
  582                                 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp,
  583                                 BUS_DMA_NOWAIT);
  584     }
  585     if (!not_ok) {
  586         steps = 2;
  587         not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1,
  588                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap);
  589     }
  590     if (!not_ok) {
  591         steps = 3;
  592         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap,
  593                                  pdq->pdq_dbp, sizeof(*pdq->pdq_dbp),
  594                                  NULL, BUS_DMA_NOWAIT);
  595     }
  596     if (!not_ok) {
  597         steps = 4;
  598         pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr;
  599         not_ok = bus_dmamem_alloc(sc->sc_dmatag,
  600                          PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE,
  601                          ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT);
  602     }
  603     if (!not_ok) {
  604         steps = 5;
  605         not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs,
  606                             PDQ_OS_PAGESIZE,
  607                             (caddr_t *) &pdq->pdq_unsolicited_info.ui_events,
  608                             BUS_DMA_NOWAIT);
  609     }
  610     if (!not_ok) {
  611         steps = 6;
  612         not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1,
  613                                    PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT,
  614                                    &sc->sc_uimap);
  615     }
  616     if (!not_ok) {
  617         steps = 7;
  618         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap,
  619                                  pdq->pdq_unsolicited_info.ui_events,
  620                                  PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT);
  621     }
  622     if (!not_ok) {
  623         steps = 8;
  624         pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr;
  625         cb_segs[0] = db_segs[0];
  626         cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer);
  627         cb_segs[0].ds_len = sizeof(pdq_consumer_block_t);
  628 #if defined(__sparc__) || defined(__sparc64__)
  629         pdq->pdq_cbp = (pdq_consumer_block_t*)((unsigned long int)pdq->pdq_dbp +
  630             (unsigned long int)offsetof(pdq_descriptor_block_t,pdqdb_consumer));
  631 #else
  632         not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1,
  633                                 sizeof(*pdq->pdq_cbp),
  634                                 (caddr_t *)&pdq->pdq_cbp,
  635                                 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
  636 #endif
  637     }
  638     if (!not_ok) {
  639         steps = 9;
  640         not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1,
  641                                    0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap);
  642     }
  643     if (!not_ok) {
  644         steps = 10;
  645         not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap,
  646                                  pdq->pdq_cbp, sizeof(*pdq->pdq_cbp),
  647                                  NULL, BUS_DMA_NOWAIT);
  648     }
  649     if (!not_ok) {
  650         pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr;
  651         return not_ok;
  652     }
  653 
  654     switch (steps) {
  655         case 11: {
  656             bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap);
  657             /* FALL THROUGH */
  658         }
  659         case 10: {
  660             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap);
  661             /* FALL THROUGH */
  662         }
  663         case 9: {
  664             bus_dmamem_unmap(sc->sc_dmatag,
  665                              (caddr_t)pdq->pdq_cbp, sizeof(*pdq->pdq_cbp));
  666             /* FALL THROUGH */
  667         }
  668         case 8: {
  669             bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap);
  670             /* FALL THROUGH */
  671         }
  672         case 7: {
  673             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap);
  674             /* FALL THROUGH */
  675         }
  676         case 6: {
  677             bus_dmamem_unmap(sc->sc_dmatag,
  678                              (caddr_t) pdq->pdq_unsolicited_info.ui_events,
  679                              PDQ_OS_PAGESIZE);
  680             /* FALL THROUGH */
  681         }
  682         case 5: {
  683             bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs);
  684             /* FALL THROUGH */
  685         }
  686         case 4: {
  687             bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap);
  688             /* FALL THROUGH */
  689         }
  690         case 3: {
  691             bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap);
  692             /* FALL THROUGH */
  693         }
  694         case 2: {
  695             bus_dmamem_unmap(sc->sc_dmatag,
  696                              (caddr_t) pdq->pdq_dbp,
  697                              sizeof(*pdq->pdq_dbp));
  698             /* FALL THROUGH */
  699         }
  700         case 1: {
  701             bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs);
  702             /* FALL THROUGH */
  703         }
  704     }
  705 
  706     return not_ok;
  707 }
  708 
  709 extern void
  710 pdq_os_descriptor_block_sync(
  711     pdq_os_ctx_t *sc,
  712     size_t offset,
  713     size_t length,
  714     int ops)
  715 {
  716     bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops);
  717 }
  718 
  719 extern void
  720 pdq_os_consumer_block_sync(
  721     pdq_os_ctx_t *sc,
  722     int ops)
  723 {
  724     bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops);
  725 }
  726 
  727 extern void
  728 pdq_os_unsolicited_event_sync(
  729     pdq_os_ctx_t *sc,
  730     size_t offset,
  731     size_t length,
  732     int ops)
  733 {
  734     bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops);
  735 }
  736 
  737 extern void
  738 pdq_os_databuf_sync(
  739     pdq_os_ctx_t *sc,
  740     struct mbuf *m,
  741     size_t offset,
  742     size_t length,
  743     int ops)
  744 {
  745     bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops);
  746 }
  747 
  748 extern void
  749 pdq_os_databuf_free(
  750     pdq_os_ctx_t *sc,
  751     struct mbuf *m)
  752 {
  753     if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) {
  754         bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
  755         bus_dmamap_unload(sc->sc_dmatag, map);
  756         bus_dmamap_destroy(sc->sc_dmatag, map);
  757         m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP);
  758     }
  759     m_freem(m);
  760 }
  761 
  762 extern struct mbuf *
  763 pdq_os_databuf_alloc(
  764     pdq_os_ctx_t *sc)
  765 {
  766     struct mbuf *m;
  767     bus_dmamap_t map;
  768 
  769     MGETHDR(m, M_DONTWAIT, MT_DATA);
  770     if (m == NULL) {
  771         printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname);
  772         return NULL;
  773     }
  774     MCLGET(m, M_DONTWAIT);
  775     if ((m->m_flags & M_EXT) == 0) {
  776         printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname);
  777         m_free(m);
  778         return NULL;
  779     }
  780     MCLAIM(m, &PDQ_FDDICOM(sc)->ec_rx_mowner);
  781     m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE;
  782 
  783     if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE,
  784                            1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) {
  785         printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname);
  786         m_free(m);
  787         return NULL;
  788     }
  789     if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
  790                              BUS_DMA_READ|BUS_DMA_NOWAIT)) {
  791         printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname);
  792         bus_dmamap_destroy(sc->sc_dmatag, map);
  793         m_free(m);
  794         return NULL;
  795     }
  796     m->m_flags |= M_HASRXDMAMAP;
  797     M_SETCTX(m, map);
  798     return m;
  799 }
  800 #endif

Cache object: 34693b6583493f0352e888957a4b8dcb


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