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/bi/if_ni.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: if_ni.c,v 1.22 2003/11/06 00:25:50 he Exp $ */
    2 /*
    3  * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed at Ludd, University of 
   16  *      Lule}, Sweden and its contributors.
   17  * 4. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Driver for DEBNA/DEBNT/DEBNK ethernet cards.
   34  * Things that is still to do:
   35  *      Collect statistics.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __KERNEL_RCSID(0, "$NetBSD: if_ni.c,v 1.22 2003/11/06 00:25:50 he Exp $");
   40 
   41 #include "opt_inet.h"
   42 #include "bpfilter.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/socket.h>
   47 #include <sys/device.h>
   48 #include <sys/systm.h>
   49 #include <sys/sockio.h>
   50 #include <sys/sched.h>
   51 
   52 #include <uvm/uvm_extern.h>
   53 
   54 #include <net/if.h>
   55 #include <net/if_ether.h>
   56 #include <net/if_dl.h>
   57 
   58 #include <netinet/in.h>
   59 #include <netinet/if_inarp.h>
   60 
   61 #if NBPFILTER > 0
   62 #include <net/bpf.h>
   63 #include <net/bpfdesc.h>
   64 #endif
   65 
   66 #include <machine/bus.h>
   67 #ifdef __vax__
   68 #include <machine/mtpr.h>
   69 #include <machine/pte.h>
   70 #endif
   71 
   72 #include <dev/bi/bireg.h>
   73 #include <dev/bi/bivar.h>
   74 
   75 #include "ioconf.h"
   76 #include "locators.h"
   77 
   78 /*
   79  * Tunable buffer parameters. Good idea to have them as power of 8; then
   80  * they will fit into a logical VAX page.
   81  */
   82 #define NMSGBUF         8       /* Message queue entries */
   83 #define NTXBUF          16      /* Transmit queue entries */
   84 #define NTXFRAGS        8       /* Number of transmit buffer fragments */
   85 #define NRXBUF          24      /* Receive queue entries */
   86 #define NBDESCS         (NTXBUF * NTXFRAGS + NRXBUF)
   87 #define NQUEUES         3       /* RX + TX + MSG */
   88 #define PKTHDR          18      /* Length of (control) packet header */
   89 #define RXADD           18      /* Additional length of receive datagram */
   90 #define TXADD           (10+NTXFRAGS*8) /*      ""      transmit   ""    */
   91 #define MSGADD          134     /*              ""      message    ""    */
   92 
   93 #include <dev/bi/if_nireg.h>    /* XXX include earlier */
   94 
   95 /*
   96  * Macros for (most cases of) insqti/remqhi.
   97  * Retry NRETRIES times to do the operation, if it still fails assume
   98  * a lost lock and panic.
   99  */
  100 #define NRETRIES        100
  101 #define INSQTI(e, h)    ({                                              \
  102         int ret = 0, i;                                                 \
  103         for (i = 0; i < NRETRIES; i++) {                                \
  104                 if ((ret = insqti(e, h)) != ILCK_FAILED)                \
  105                         break;                                          \
  106         }                                                               \
  107         if (i == NRETRIES)                                              \
  108                 panic("ni: insqti failed at %d", __LINE__);             \
  109         ret;                                                            \
  110 })
  111 #define REMQHI(h)       ({                                              \
  112         int i; void *ret = NULL;                                        \
  113         for (i = 0; i < NRETRIES; i++) {                                \
  114                 if ((ret = remqhi(h)) != (void *)ILCK_FAILED)           \
  115                         break;                                          \
  116         }                                                               \
  117         if (i == NRETRIES)                                              \
  118                 panic("ni: remqhi failed at %d", __LINE__);             \
  119         ret;                                                            \
  120 })
  121 
  122 
  123 #define nipqb   (&sc->sc_gvppqb->nc_pqb)
  124 #define gvp     sc->sc_gvppqb
  125 #define fqb     sc->sc_fqb
  126 #define bbd     sc->sc_bbd
  127 
  128 struct  ni_softc {
  129         struct device   sc_dev;         /* Configuration common part    */
  130         struct evcnt    sc_intrcnt;     /* Interrupt coounting          */
  131         struct ethercom sc_ec;          /* Ethernet common part         */
  132 #define sc_if   sc_ec.ec_if             /* network-visible interface    */
  133         bus_space_tag_t sc_iot;
  134         bus_addr_t      sc_ioh;
  135         bus_dma_tag_t   sc_dmat;
  136         struct ni_gvppqb *sc_gvppqb;    /* Port queue block             */
  137         struct ni_gvppqb *sc_pgvppqb;   /* Phys address of PQB          */
  138         struct ni_fqb   *sc_fqb;        /* Free Queue block             */
  139         struct ni_bbd   *sc_bbd;        /* Buffer descriptors           */
  140         u_int8_t        sc_enaddr[ETHER_ADDR_LEN];
  141 };
  142 
  143 static  int     nimatch __P((struct device *, struct cfdata *, void *));
  144 static  void    niattach __P((struct device *, struct device *, void *));
  145 static  void    niinit __P((struct ni_softc *));
  146 static  void    nistart __P((struct ifnet *));
  147 static  void    niintr __P((void *));
  148 static  int     niioctl __P((struct ifnet *, u_long, caddr_t));
  149 static  int     ni_add_rxbuf(struct ni_softc *, struct ni_dg *, int);
  150 static  void    ni_setup __P((struct ni_softc *));
  151 static  void    nitimeout __P((struct ifnet *));
  152 static  void    ni_shutdown(void *);
  153 static  void ni_getpgs(struct ni_softc *sc, int size, caddr_t *v, paddr_t *p);
  154 static  int failtest(struct ni_softc *, int, int, int, char *);
  155 
  156 volatile int endwait, retry;    /* Used during autoconfig */
  157 
  158 CFATTACH_DECL(ni, sizeof(struct ni_softc),
  159     nimatch, niattach, NULL, NULL);
  160 
  161 #define NI_WREG(csr, val) \
  162         bus_space_write_4(sc->sc_iot, sc->sc_ioh, csr, val)
  163 #define NI_RREG(csr) \
  164         bus_space_read_4(sc->sc_iot, sc->sc_ioh, csr)
  165 
  166 #define WAITREG(csr,val) while (NI_RREG(csr) & val);
  167 /*
  168  * Check for present device.
  169  */
  170 int
  171 nimatch(parent, cf, aux)
  172         struct  device *parent;
  173         struct  cfdata *cf;
  174         void    *aux;
  175 {
  176         struct bi_attach_args *ba = aux;
  177         u_short type;
  178 
  179         type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE);
  180         if (type != BIDT_DEBNA && type != BIDT_DEBNT && type != BIDT_DEBNK)
  181                 return 0;
  182 
  183         if (cf->cf_loc[BICF_NODE] != BICF_NODE_DEFAULT &&
  184             cf->cf_loc[BICF_NODE] != ba->ba_nodenr)
  185                 return 0;
  186 
  187         return 1;
  188 }
  189 
  190 /*
  191  * Allocate a bunch of descriptor-safe memory.
  192  * We need to get the structures from the beginning of its own pages.
  193  */
  194 static void
  195 ni_getpgs(struct ni_softc *sc, int size, caddr_t *v, paddr_t *p)
  196 {
  197         bus_dma_segment_t seg;
  198         int nsegs, error;
  199 
  200         if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1,
  201             &nsegs, BUS_DMA_NOWAIT)) != 0)
  202                 panic(" unable to allocate memory: error %d", error);
  203 
  204         if ((error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, size, v,
  205             BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0)
  206                 panic(" unable to map memory: error %d", error);
  207 
  208         if (p)
  209                 *p = seg.ds_addr;
  210         memset(*v, 0, size);
  211 }
  212 
  213 static int
  214 failtest(struct ni_softc *sc, int reg, int mask, int test, char *str)
  215 {
  216         int i = 100;
  217 
  218         do {
  219                 DELAY(100000);
  220         } while (((NI_RREG(reg) & mask) != test) && --i);
  221 
  222         if (i == 0) {
  223                 printf("%s: %s\n", sc->sc_dev.dv_xname, str);
  224                 return 1;
  225         }
  226         return 0;
  227 }
  228 
  229 
  230 /*
  231  * Interface exists: make available by filling in network interface
  232  * record.  System will initialize the interface when it is ready
  233  * to accept packets.
  234  */
  235 void
  236 niattach(parent, self, aux)
  237         struct  device *parent, *self;
  238         void    *aux;
  239 {
  240         struct bi_attach_args *ba = aux;
  241         struct ni_softc *sc = (struct ni_softc *)self;
  242         struct ifnet *ifp = (struct ifnet *)&sc->sc_if;
  243         struct ni_msg *msg;
  244         struct ni_ptdb *ptdb;
  245         caddr_t va;
  246         int i, j, s, res;
  247         u_short type;
  248 
  249         type = bus_space_read_2(ba->ba_iot, ba->ba_ioh, BIREG_DTYPE);
  250         printf(": DEBN%c\n", type == BIDT_DEBNA ? 'A' : type == BIDT_DEBNT ?
  251             'T' : 'K');
  252         sc->sc_iot = ba->ba_iot;
  253         sc->sc_ioh = ba->ba_ioh;
  254         sc->sc_dmat = ba->ba_dmat;
  255 
  256         bi_intr_establish(ba->ba_icookie, ba->ba_ivec,
  257                 niintr, sc, &sc->sc_intrcnt);
  258         evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
  259                 sc->sc_dev.dv_xname, "intr");
  260 
  261         ni_getpgs(sc, sizeof(struct ni_gvppqb), (caddr_t *)&sc->sc_gvppqb, 
  262             (paddr_t *)&sc->sc_pgvppqb);
  263         ni_getpgs(sc, sizeof(struct ni_fqb), (caddr_t *)&sc->sc_fqb, 0);
  264         ni_getpgs(sc, NBDESCS * sizeof(struct ni_bbd),
  265             (caddr_t *)&sc->sc_bbd, 0);
  266         /*
  267          * Zero the newly allocated memory.
  268          */
  269 
  270         nipqb->np_veclvl = (ba->ba_ivec << 2) + 2;
  271         nipqb->np_node = ba->ba_intcpu;
  272         nipqb->np_vpqb = (u_int32_t)gvp;
  273 #ifdef __vax__
  274         nipqb->np_spt = nipqb->np_gpt = mfpr(PR_SBR);
  275         nipqb->np_sptlen = nipqb->np_gptlen = mfpr(PR_SLR);
  276 #else
  277 #error Must fix support for non-vax.
  278 #endif
  279         nipqb->np_bvplvl = 1;
  280         nipqb->np_vfqb = (u_int32_t)fqb;
  281         nipqb->np_vbdt = (u_int32_t)bbd;
  282         nipqb->np_nbdr = NBDESCS;
  283 
  284         /* Free queue block */
  285         nipqb->np_freeq = NQUEUES;
  286         fqb->nf_mlen = PKTHDR+MSGADD;
  287         fqb->nf_dlen = PKTHDR+TXADD;
  288         fqb->nf_rlen = PKTHDR+RXADD;
  289 
  290         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  291         ifp->if_softc = sc;
  292         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  293         ifp->if_start = nistart;
  294         ifp->if_ioctl = niioctl;
  295         ifp->if_watchdog = nitimeout;
  296         IFQ_SET_READY(&ifp->if_snd);
  297 
  298         /*
  299          * Start init sequence.
  300          */
  301 
  302         /* Reset the node */
  303         NI_WREG(BIREG_VAXBICSR, NI_RREG(BIREG_VAXBICSR) | BICSR_NRST);
  304         DELAY(500000);
  305         i = 20;
  306         while ((NI_RREG(BIREG_VAXBICSR) & BICSR_BROKE) && --i)
  307                 DELAY(500000);
  308         if (i == 0) {
  309                 printf("%s: BROKE bit set after reset\n", sc->sc_dev.dv_xname);
  310                 return;
  311         }
  312 
  313         /* Check state */
  314         if (failtest(sc, NI_PSR, PSR_STATE, PSR_UNDEF, "not undefined state"))
  315                 return;
  316 
  317         /* Clear owner bits */
  318         NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
  319         NI_WREG(NI_PCR, NI_RREG(NI_PCR) & ~PCR_OWN);
  320 
  321         /* kick off init */
  322         NI_WREG(NI_PCR, (u_int32_t)sc->sc_pgvppqb | PCR_INIT | PCR_OWN);
  323         while (NI_RREG(NI_PCR) & PCR_OWN)
  324                 DELAY(100000);
  325 
  326         /* Check state */
  327         if (failtest(sc, NI_PSR, PSR_INITED, PSR_INITED, "failed initialize"))
  328                 return;
  329 
  330         NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
  331 
  332         WAITREG(NI_PCR, PCR_OWN);
  333         NI_WREG(NI_PCR, PCR_OWN|PCR_ENABLE);
  334         WAITREG(NI_PCR, PCR_OWN);
  335         WAITREG(NI_PSR, PSR_OWN);
  336 
  337         /* Check state */
  338         if (failtest(sc, NI_PSR, PSR_STATE, PSR_ENABLED, "failed enable"))
  339                 return;
  340 
  341         NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~PSR_OWN);
  342 
  343         /*
  344          * The message queue packets must be located on the beginning
  345          * of a page. A VAX page is 512 bytes, but it clusters 8 pages.
  346          * This knowledge is used here when allocating pages.
  347          * !!! How should this be done on MIPS and Alpha??? !!!
  348          */
  349 #if NBPG < 4096
  350 #error pagesize too small
  351 #endif
  352         s = splvm();
  353         /* Set up message free queue */
  354         ni_getpgs(sc, NMSGBUF * 512, &va, 0);
  355         for (i = 0; i < NMSGBUF; i++) {
  356                 struct ni_msg *msg;
  357 
  358                 msg = (void *)(va + i * 512);
  359 
  360                 res = INSQTI(msg, &fqb->nf_mforw);
  361         }
  362         WAITREG(NI_PCR, PCR_OWN);
  363         NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
  364         WAITREG(NI_PCR, PCR_OWN);
  365 
  366         /* Set up xmit queue */
  367         ni_getpgs(sc, NTXBUF * 512, &va, 0);
  368         for (i = 0; i < NTXBUF; i++) {
  369                 struct ni_dg *data;
  370 
  371                 data = (void *)(va + i * 512);
  372                 data->nd_status = 0;
  373                 data->nd_len = TXADD;
  374                 data->nd_ptdbidx = 1;
  375                 data->nd_opcode = BVP_DGRAM;
  376                 for (j = 0; j < NTXFRAGS; j++) {
  377                         data->bufs[j]._offset = 0;
  378                         data->bufs[j]._key = 1;
  379                         bbd[i * NTXFRAGS + j].nb_key = 1;
  380                         bbd[i * NTXFRAGS + j].nb_status = 0;
  381                         data->bufs[j]._index = i * NTXFRAGS + j;
  382                 }
  383                 res = INSQTI(data, &fqb->nf_dforw);
  384         }
  385         WAITREG(NI_PCR, PCR_OWN);
  386         NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
  387         WAITREG(NI_PCR, PCR_OWN);
  388 
  389         /* recv buffers */
  390         ni_getpgs(sc, NRXBUF * 512, &va, 0);
  391         for (i = 0; i < NRXBUF; i++) {
  392                 struct ni_dg *data;
  393                 int idx;
  394 
  395                 data = (void *)(va + i * 512);
  396                 data->nd_len = RXADD;
  397                 data->nd_opcode = BVP_DGRAMRX;
  398                 data->nd_ptdbidx = 2;
  399                 data->bufs[0]._key = 1;
  400 
  401                 idx = NTXBUF * NTXFRAGS + i;
  402                 if (ni_add_rxbuf(sc, data, idx))
  403                         panic("niattach: ni_add_rxbuf: out of mbufs");
  404 
  405                 res = INSQTI(data, &fqb->nf_rforw);
  406         }
  407         WAITREG(NI_PCR, PCR_OWN);
  408         NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
  409         WAITREG(NI_PCR, PCR_OWN);
  410 
  411         splx(s);
  412 
  413         /* Set initial parameters */
  414         msg = REMQHI(&fqb->nf_mforw);
  415 
  416         msg->nm_opcode = BVP_MSG;
  417         msg->nm_status = 0;
  418         msg->nm_len = sizeof(struct ni_param) + 6;
  419         msg->nm_opcode2 = NI_WPARAM;
  420         ((struct ni_param *)&msg->nm_text[0])->np_flags = NP_PAD;
  421 
  422         endwait = retry = 0;
  423         res = INSQTI(msg, &gvp->nc_forw0);
  424 
  425 retry:  WAITREG(NI_PCR, PCR_OWN);
  426         NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
  427         WAITREG(NI_PCR, PCR_OWN);
  428         i = 1000;
  429         while (endwait == 0 && --i)
  430                 DELAY(10000);
  431 
  432         if (endwait == 0) {
  433                 if (++retry < 3)
  434                         goto retry;
  435                 printf("%s: no response to set params\n", sc->sc_dev.dv_xname);
  436                 return;
  437         }
  438 
  439         /* Clear counters */
  440         msg = REMQHI(&fqb->nf_mforw);
  441         msg->nm_opcode = BVP_MSG;
  442         msg->nm_status = 0;
  443         msg->nm_len = sizeof(struct ni_param) + 6;
  444         msg->nm_opcode2 = NI_RCCNTR;
  445 
  446         res = INSQTI(msg, &gvp->nc_forw0);
  447 
  448         WAITREG(NI_PCR, PCR_OWN);
  449         NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
  450         WAITREG(NI_PCR, PCR_OWN);
  451 
  452         /* Enable transmit logic */
  453         msg = REMQHI(&fqb->nf_mforw);
  454 
  455         msg->nm_opcode = BVP_MSG;
  456         msg->nm_status = 0;
  457         msg->nm_len = 18;
  458         msg->nm_opcode2 = NI_STPTDB;
  459         ptdb = (struct ni_ptdb *)&msg->nm_text[0];
  460         memset(ptdb, 0, sizeof(struct ni_ptdb));
  461         ptdb->np_index = 1;
  462         ptdb->np_fque = 1;
  463 
  464         res = INSQTI(msg, &gvp->nc_forw0);
  465 
  466         WAITREG(NI_PCR, PCR_OWN);
  467         NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
  468         WAITREG(NI_PCR, PCR_OWN);
  469 
  470         /* Wait for everything to finish */
  471         WAITREG(NI_PSR, PSR_OWN);
  472 
  473         printf("%s: hardware address %s\n", sc->sc_dev.dv_xname,
  474             ether_sprintf(sc->sc_enaddr));
  475 
  476         /*
  477          * Attach the interface.
  478          */
  479         if_attach(ifp);
  480         ether_ifattach(ifp, sc->sc_enaddr);
  481         if (shutdownhook_establish(ni_shutdown, sc) == 0)
  482                 printf("%s: WARNING: unable to establish shutdown hook\n",
  483                     sc->sc_dev.dv_xname);
  484 }
  485 
  486 /*
  487  * Initialization of interface.
  488  */
  489 void
  490 niinit(sc)
  491         struct ni_softc *sc;
  492 {
  493         struct ifnet *ifp = (struct ifnet *)&sc->sc_if;
  494 
  495         /*
  496          * Set flags (so ni_setup() do the right thing).
  497          */
  498         ifp->if_flags |= IFF_RUNNING;
  499         ifp->if_flags &= ~IFF_OACTIVE;
  500 
  501         /*
  502          * Send setup messages so that the rx/tx locic starts.
  503          */
  504         ni_setup(sc);
  505 
  506 }
  507 
  508 /*
  509  * Start output on interface.
  510  */
  511 void
  512 nistart(ifp)
  513         struct ifnet *ifp;
  514 {
  515         struct ni_softc *sc = ifp->if_softc;
  516         struct ni_dg *data;
  517         struct ni_bbd *bdp;
  518         struct mbuf *m, *m0;
  519         int i, cnt, res, mlen;
  520 
  521         if (ifp->if_flags & IFF_OACTIVE)
  522                 return;
  523 #ifdef DEBUG
  524         if (ifp->if_flags & IFF_DEBUG)
  525                 printf("%s: nistart\n", sc->sc_dev.dv_xname);
  526 #endif
  527 
  528         while (fqb->nf_dforw) {
  529                 IFQ_POLL(&ifp->if_snd, m);
  530                 if (m == 0)
  531                         break;
  532 
  533                 data = REMQHI(&fqb->nf_dforw);
  534                 if ((int)data == Q_EMPTY) {
  535                         ifp->if_flags |= IFF_OACTIVE;
  536                         break;
  537                 }
  538 
  539                 IFQ_DEQUEUE(&ifp->if_snd, m);
  540 
  541                 /*
  542                  * Count number of mbufs in chain.
  543                  * Always do DMA directly from mbufs, therefore the transmit
  544                  * ring is really big.
  545                  */
  546                 for (m0 = m, cnt = 0; m0; m0 = m0->m_next)
  547                         if (m0->m_len)
  548                                 cnt++;
  549                 if (cnt > NTXFRAGS)
  550                         panic("nistart"); /* XXX */
  551 
  552 #if NBPFILTER > 0
  553                 if (ifp->if_bpf)
  554                         bpf_mtap(ifp->if_bpf, m);
  555 #endif
  556                 bdp = &bbd[(data->bufs[0]._index & 0x7fff)];
  557                 for (m0 = m, i = 0, mlen = 0; m0; m0 = m0->m_next) {
  558                         if (m0->m_len == 0)
  559                                 continue;
  560                         bdp->nb_status = (mtod(m0, u_int32_t) & NIBD_OFFSET) |
  561                             NIBD_VALID;
  562                         bdp->nb_pte = (u_int32_t)kvtopte(mtod(m0, void *));
  563                         bdp->nb_len = m0->m_len;
  564                         data->bufs[i]._offset = 0;
  565                         data->bufs[i]._len = bdp->nb_len;
  566                         data->bufs[i]._index |= NIDG_CHAIN;
  567                         mlen += bdp->nb_len;
  568                         bdp++;
  569                         i++;
  570                 }
  571                 data->nd_opcode = BVP_DGRAM;
  572                 data->nd_pad3 = 1;
  573                 data->nd_ptdbidx = 1;
  574                 data->nd_len = 10 + i * 8;
  575                 data->bufs[i - 1]._index &= ~NIDG_CHAIN;
  576                 data->nd_cmdref = (u_int32_t)m;
  577 #ifdef DEBUG
  578                 if (ifp->if_flags & IFF_DEBUG)
  579                         printf("%s: sending %d bytes (%d segments)\n",
  580                             sc->sc_dev.dv_xname, mlen, i);
  581 #endif
  582 
  583                 res = INSQTI(data, &gvp->nc_forw0);
  584                 if (res == Q_EMPTY) {
  585                         WAITREG(NI_PCR, PCR_OWN);
  586                         NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
  587                 }
  588         }
  589 }
  590 
  591 void
  592 niintr(void *arg)
  593 {
  594         struct ni_softc *sc = arg;
  595         struct ni_dg *data;
  596         struct ni_msg *msg;
  597         struct ifnet *ifp = &sc->sc_if;
  598         struct ni_bbd *bd;
  599         struct mbuf *m;
  600         int idx, res;
  601 
  602         if ((NI_RREG(NI_PSR) & PSR_STATE) != PSR_ENABLED)
  603                 return;
  604 
  605         if ((NI_RREG(NI_PSR) & PSR_ERR))
  606                 printf("%s: PSR %x\n", sc->sc_dev.dv_xname, NI_RREG(NI_PSR));
  607 
  608         KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
  609         /* Got any response packets?  */
  610         while ((NI_RREG(NI_PSR) & PSR_RSQ) && (data = REMQHI(&gvp->nc_forwr))) {
  611 
  612                 switch (data->nd_opcode) {
  613                 case BVP_DGRAMRX: /* Receive datagram */
  614                         idx = data->bufs[0]._index;
  615                         bd = &bbd[idx];
  616                         m = (void *)data->nd_cmdref;
  617                         m->m_pkthdr.len = m->m_len =
  618                             data->bufs[0]._len - ETHER_CRC_LEN;
  619                         m->m_pkthdr.rcvif = ifp;
  620                         if (ni_add_rxbuf(sc, data, idx)) {
  621                                 bd->nb_len = (m->m_ext.ext_size - 2);
  622                                 bd->nb_pte =
  623                                     (long)kvtopte(m->m_ext.ext_buf);
  624                                 bd->nb_status = 2 | NIBD_VALID;
  625                                 bd->nb_key = 1;
  626                         }
  627                         data->nd_len = RXADD;
  628                         data->nd_status = 0;
  629                         res = INSQTI(data, &fqb->nf_rforw);
  630                         if (res == Q_EMPTY) {
  631                                 WAITREG(NI_PCR, PCR_OWN);
  632                                 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_RFREEQ|PCR_OWN);
  633                         }
  634                         if (m == (void *)data->nd_cmdref)
  635                                 break; /* Out of mbufs */
  636 
  637 #if NBPFILTER > 0
  638                         if (ifp->if_bpf)
  639                                 bpf_mtap(ifp->if_bpf, m);
  640 #endif
  641                         (*ifp->if_input)(ifp, m);
  642                         break;
  643 
  644                 case BVP_DGRAM:
  645                         m = (struct mbuf *)data->nd_cmdref;
  646                         ifp->if_flags &= ~IFF_OACTIVE;
  647                         m_freem(m);
  648                         res = INSQTI(data, &fqb->nf_dforw);
  649                         if (res == Q_EMPTY) {
  650                                 WAITREG(NI_PCR, PCR_OWN);
  651                                 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_DFREEQ|PCR_OWN);
  652                         }
  653                         break;
  654 
  655                 case BVP_MSGRX:
  656                         msg = (struct ni_msg *)data;
  657                         switch (msg->nm_opcode2) {
  658                                 case NI_WPARAM:
  659                                         memcpy(sc->sc_enaddr, ((struct ni_param *)&msg->nm_text[0])->np_dpa, ETHER_ADDR_LEN);
  660                                         endwait = 1;
  661                                         break;
  662 
  663                                 case NI_RCCNTR:
  664                                 case NI_CLPTDB:
  665                                 case NI_STPTDB:
  666                                         break;
  667 
  668                                 default:
  669                                         printf("Unkn resp %d\n", 
  670                                             msg->nm_opcode2);
  671                                         break;
  672                         }
  673                         res = INSQTI(data, &fqb->nf_mforw);
  674                         if (res == Q_EMPTY) {
  675                                 WAITREG(NI_PCR, PCR_OWN);
  676                                 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
  677                         }
  678                         break;
  679 
  680                 default:
  681                         printf("Unknown opcode %d\n", data->nd_opcode);
  682                         res = INSQTI(data, &fqb->nf_mforw);
  683                         if (res == Q_EMPTY) {
  684                                 WAITREG(NI_PCR, PCR_OWN);
  685                                 NI_WREG(NI_PCR, PCR_FREEQNE|PCR_MFREEQ|PCR_OWN);
  686                         }
  687                 }
  688         }
  689 
  690         /* Try to kick on the start routine again */
  691         nistart(ifp);
  692 
  693         NI_WREG(NI_PSR, NI_RREG(NI_PSR) & ~(PSR_OWN|PSR_RSQ));
  694         KERNEL_UNLOCK();
  695 }
  696 
  697 /*
  698  * Process an ioctl request.
  699  */
  700 int
  701 niioctl(ifp, cmd, data)
  702         register struct ifnet *ifp;
  703         u_long cmd;
  704         caddr_t data;
  705 {
  706         struct ni_softc *sc = ifp->if_softc;
  707         struct ifreq *ifr = (struct ifreq *)data;
  708         struct ifaddr *ifa = (struct ifaddr *)data;
  709         int s = splnet(), error = 0;
  710 
  711         switch (cmd) {
  712 
  713         case SIOCSIFADDR:
  714                 ifp->if_flags |= IFF_UP;
  715                 switch(ifa->ifa_addr->sa_family) {
  716 #ifdef INET
  717                 case AF_INET:
  718                         niinit(sc);
  719                         arp_ifinit(ifp, ifa);
  720                         break;
  721 #endif
  722                 }
  723                 break;
  724 
  725         case SIOCSIFFLAGS:
  726                 if ((ifp->if_flags & IFF_UP) == 0 &&
  727                     (ifp->if_flags & IFF_RUNNING) != 0) {
  728                         /*
  729                          * If interface is marked down and it is running,
  730                          * stop it.
  731                          */
  732                         ifp->if_flags &= ~IFF_RUNNING;
  733                         ni_setup(sc);
  734                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  735                            (ifp->if_flags & IFF_RUNNING) == 0) {
  736                         /*
  737                          * If interface it marked up and it is stopped, then
  738                          * start it.
  739                          */
  740                         niinit(sc);
  741                 } else if ((ifp->if_flags & IFF_UP) != 0) {
  742                         /*
  743                          * Send a new setup packet to match any new changes.
  744                          * (Like IFF_PROMISC etc)
  745                          */
  746                         ni_setup(sc);
  747                 }
  748                 break;
  749 
  750         case SIOCADDMULTI:
  751         case SIOCDELMULTI:
  752                 /*
  753                  * Update our multicast list.
  754                  */
  755                 error = (cmd == SIOCADDMULTI) ?
  756                         ether_addmulti(ifr, &sc->sc_ec):
  757                         ether_delmulti(ifr, &sc->sc_ec);
  758 
  759                 if (error == ENETRESET) {
  760                         /*
  761                          * Multicast list has changed; set the hardware filter
  762                          * accordingly.
  763                          */
  764                         ni_setup(sc);
  765                         error = 0;
  766                 }
  767                 break;
  768 
  769         default:
  770                 error = EINVAL;
  771 
  772         }
  773         splx(s);
  774         return (error);
  775 }
  776 
  777 /*
  778  * Add a receive buffer to the indicated descriptor.
  779  */
  780 int
  781 ni_add_rxbuf(struct ni_softc *sc, struct ni_dg *data, int idx) 
  782 {
  783         struct ni_bbd *bd = &bbd[idx];
  784         struct mbuf *m;
  785 
  786         MGETHDR(m, M_DONTWAIT, MT_DATA);
  787         if (m == NULL)
  788                 return (ENOBUFS);
  789 
  790         MCLGET(m, M_DONTWAIT);
  791         if ((m->m_flags & M_EXT) == 0) {
  792                 m_freem(m);
  793                 return (ENOBUFS);
  794         }
  795 
  796         m->m_data += 2;
  797         bd->nb_len = (m->m_ext.ext_size - 2);
  798         bd->nb_pte = (long)kvtopte(m->m_ext.ext_buf);
  799         bd->nb_status = 2 | NIBD_VALID;
  800         bd->nb_key = 1;
  801 
  802         data->bufs[0]._offset = 0;
  803         data->bufs[0]._len = bd->nb_len;
  804         data->bufs[0]._index = idx;
  805         data->nd_cmdref = (long)m;
  806 
  807         return (0);
  808 }
  809 
  810 /*
  811  * Create setup packet and put in queue for sending.
  812  */
  813 void
  814 ni_setup(struct ni_softc *sc)
  815 {
  816         struct ifnet *ifp = &sc->sc_if;
  817         struct ni_msg *msg;
  818         struct ni_ptdb *ptdb;
  819         struct ether_multi *enm;
  820         struct ether_multistep step;
  821         int i, res;
  822 
  823         msg = REMQHI(&fqb->nf_mforw);
  824         if ((int)msg == Q_EMPTY)
  825                 return; /* What to do? */
  826 
  827         ptdb = (struct ni_ptdb *)&msg->nm_text[0];
  828         memset(ptdb, 0, sizeof(struct ni_ptdb));
  829 
  830         msg->nm_opcode = BVP_MSG;
  831         msg->nm_len = 18;
  832         ptdb->np_index = 2; /* definition type index */
  833         ptdb->np_fque = 2; /* Free queue */
  834         if (ifp->if_flags & IFF_RUNNING) {
  835                 msg->nm_opcode2 = NI_STPTDB;
  836                 ptdb->np_type = ETHERTYPE_IP;
  837                 ptdb->np_flags = PTDB_UNKN|PTDB_BDC;
  838                 if (ifp->if_flags & IFF_PROMISC)
  839                         ptdb->np_flags |= PTDB_PROMISC;
  840                 memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN); /* Broadcast */
  841                 ptdb->np_adrlen = 1;
  842                 msg->nm_len += 8;
  843                 ifp->if_flags &= ~IFF_ALLMULTI;
  844                 if ((ifp->if_flags & IFF_PROMISC) == 0) {
  845                         ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
  846                         i = 1;
  847                         while (enm != NULL) {
  848                                 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) {
  849                                         ifp->if_flags |= IFF_ALLMULTI;
  850                                         ptdb->np_flags |= PTDB_AMC;
  851                                         break;
  852                                 }
  853                                 msg->nm_len += 8;
  854                                 ptdb->np_adrlen++;
  855                                 memcpy(ptdb->np_mcast[i++], enm->enm_addrlo,
  856                                     ETHER_ADDR_LEN);
  857                                 ETHER_NEXT_MULTI(step, enm);
  858                         }
  859                 }
  860         } else
  861                 msg->nm_opcode2 = NI_CLPTDB;
  862 
  863         res = INSQTI(msg, &gvp->nc_forw0);
  864         if (res == Q_EMPTY) {
  865                 WAITREG(NI_PCR, PCR_OWN);
  866                 NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
  867         }
  868 }
  869 
  870 /*
  871  * Check for dead transmit logic. Not uncommon.
  872  */
  873 void
  874 nitimeout(ifp)
  875         struct ifnet *ifp;
  876 {
  877 #if 0
  878         struct ni_softc *sc = ifp->if_softc;
  879 
  880         if (sc->sc_inq == 0)
  881                 return;
  882 
  883         printf("%s: xmit logic died, resetting...\n", sc->sc_dev.dv_xname);
  884         /*
  885          * Do a reset of interface, to get it going again.
  886          * Will it work by just restart the transmit logic?
  887          */
  888         niinit(sc);
  889 #endif
  890 }
  891 
  892 /*
  893  * Shutdown hook.  Make sure the interface is stopped at reboot.
  894  */
  895 void
  896 ni_shutdown(arg)
  897         void *arg;
  898 {
  899         struct ni_softc *sc = arg;
  900 
  901         WAITREG(NI_PCR, PCR_OWN);
  902         NI_WREG(NI_PCR, PCR_OWN|PCR_SHUTDOWN);
  903         WAITREG(NI_PCR, PCR_OWN);
  904         WAITREG(NI_PSR, PSR_OWN);
  905 
  906 }
  907 

Cache object: 37edb84cd71de37c5ff222bca201099f


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