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/i386/isa/if_ex.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 /*
    2  * Copyright (c) 1996, Javier Martín Rueda (jmrueda@diatel.upm.es)
    3  * 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 unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * Intel EtherExpress Pro/10 Ethernet driver
   30  *
   31  * Revision history:
   32  *
   33  * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast.
   34  */
   35 
   36 #include "ex.h"
   37 #if NEX > 0
   38 #include "bpfilter.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/conf.h>
   44 #include <sys/errno.h>
   45 #include <sys/ioctl.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/socket.h>
   48 #include <sys/syslog.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_dl.h>
   52 #include <net/if_types.h>
   53 
   54 #ifdef INET
   55 #include <netinet/in.h>
   56 #include <netinet/in_systm.h>
   57 #include <netinet/in_var.h>
   58 #include <netinet/ip.h>
   59 #include <netinet/if_ether.h>
   60 #endif
   61 
   62 #ifdef IPX
   63 #include <netipx/ipx.h>
   64 #include <netipx/ipx_if.h>
   65 #endif
   66 
   67 #ifdef NS
   68 #include <netns/ns.h>
   69 #include <netns/ns_if.h>
   70 #endif
   71 
   72 #if NBPFILTER > 0
   73 #include <net/bpf.h>
   74 #include <net/bpfdesc.h>
   75 #endif
   76 
   77 #include <machine/clock.h>
   78 
   79 #include <i386/isa/isa_device.h>
   80 #include <i386/isa/if_exreg.h>
   81 
   82 #ifdef EXDEBUG
   83 #define Start_End 1
   84 #define Rcvd_Pkts 2
   85 #define Sent_Pkts 4
   86 #define Status    8
   87 static int debug_mask = 0;
   88 static int exintr_count = 0;
   89 #define DODEBUG(level, action) if (level & debug_mask) action
   90 #else
   91 #define DODEBUG(level, action)
   92 #endif
   93 
   94 #define Conn_BNC 1
   95 #define Conn_TPE 2
   96 #define Conn_AUI 3
   97 
   98 struct ex_softc {
   99         struct arpcom arpcom;   /* Ethernet common data */
  100         u_int iobase;   /* I/O base address. */
  101         u_short connector;      /* Connector type. */
  102         u_short irq_no; /* IRQ number. */
  103         char *irq2ee; /* irq <-> internal representation conversion */
  104         u_char *ee2irq;
  105         u_int mem_size; /* Total memory size, in bytes. */
  106         u_int rx_mem_size;      /* Rx memory size (by default, first 3/4 of total memory). */
  107   u_int rx_lower_limit, rx_upper_limit; /* Lower and upper limits of receive buffer. */
  108   u_int rx_head; /* Head of receive ring buffer. */
  109         u_int tx_mem_size;      /* Tx memory size (by default, last quarter of total memory). */
  110   u_int tx_lower_limit, tx_upper_limit; /* Lower and upper limits of transmit buffer. */
  111   u_int tx_head, tx_tail; /* Head and tail of transmit ring buffer. */
  112   u_int tx_last; /* Pointer to beginning of last frame in the chain. */
  113 };
  114 
  115 static struct ex_softc ex_sc[NEX]; /* XXX would it be better to malloc(3) the memory? */
  116 
  117 static char irq2eemap[] = { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 };
  118 static u_char ee2irqmap[] = { 9, 3, 5, 10, 11, 0, 0, 0 };
  119 static char plus_irq2eemap[] = { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 };
  120 static u_char plus_ee2irqmap[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
  121 
  122 static int ex_probe __P((struct isa_device *));
  123 static int ex_attach __P((struct isa_device *));
  124 static void ex_init __P((void *));
  125 static void ex_start __P((struct ifnet *));
  126 static void ex_stop __P((int));
  127 static int ex_ioctl __P((struct ifnet *, int, caddr_t));
  128 static void ex_reset __P((int));
  129 static void ex_watchdog __P((struct ifnet *));
  130 
  131 static u_short eeprom_read __P((int, int));
  132 static int look_for_card __P((u_int));
  133 static void ex_tx_intr __P((int));
  134 static void ex_rx_intr __P((int));
  135 
  136 struct isa_driver exdriver = {
  137         ex_probe,
  138         ex_attach,
  139         "ex",
  140         0
  141 };
  142 
  143 static int look_for_card(u_int iobase)
  144 {
  145         int count1, count2;
  146 
  147         /*
  148          * Check for the i82595 signature, and check that the round robin
  149          * counter actually advances.
  150          */
  151         if (((count1 = inb(iobase + ID_REG)) & Id_Mask) != Id_Sig)
  152                 return(0);
  153         count2 = inb(iobase + ID_REG);
  154         count2 = inb(iobase + ID_REG);
  155         count2 = inb(iobase + ID_REG);
  156         return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits));
  157 }
  158 
  159 
  160 int ex_probe(struct isa_device *dev)
  161 {
  162         int unit = dev->id_unit;
  163         struct ex_softc *sc = &ex_sc[unit];
  164         u_int iobase;
  165         u_short eaddr_tmp;
  166         int tmp;
  167 
  168         DODEBUG(Start_End, printf("ex_probe%d: start\n", unit););
  169 
  170         /*
  171          * If an I/O address was supplied in the configuration file, probe only
  172          * that. Otherwise, cycle through the predefined set of possible addresses.
  173          */
  174         if (dev->id_iobase != -1) {
  175                 if (! look_for_card(iobase = dev->id_iobase))
  176                         return(0);
  177         }
  178         else {
  179                 for (iobase = 0x200; iobase < 0x3a0; iobase += 0x10)
  180                         if (look_for_card(iobase))
  181                                 break;
  182                 if (iobase >= 0x3a0)
  183                         return(0);
  184                 else
  185                         dev->id_iobase = iobase;
  186         }
  187 
  188         /*
  189          * Reset the card.
  190          */
  191         outb(iobase + CMD_REG, Reset_CMD);
  192         DELAY(400);
  193 
  194         /*
  195          * Fill in several fields of the softc structure:
  196          *      - I/O base address.
  197          *      - Hardware Ethernet address.
  198          *      - IRQ number (if not supplied in config file, read it from EEPROM).
  199          *      - Connector type.
  200          */
  201         sc->iobase = iobase;
  202         eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo);
  203         sc->arpcom.ac_enaddr[5] = eaddr_tmp & 0xff;
  204         sc->arpcom.ac_enaddr[4] = eaddr_tmp >> 8;
  205         eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid);
  206         sc->arpcom.ac_enaddr[3] = eaddr_tmp & 0xff;
  207         sc->arpcom.ac_enaddr[2] = eaddr_tmp >> 8;
  208         eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi);
  209         sc->arpcom.ac_enaddr[1] = eaddr_tmp & 0xff;
  210         sc->arpcom.ac_enaddr[0] = eaddr_tmp >> 8;
  211         tmp = eeprom_read(iobase, EE_IRQ_No) & IRQ_No_Mask;
  212 
  213         /* work out which set of irq <-> internal tables to use */
  214         if (sc->arpcom.ac_enaddr[0] == 0x00 &&
  215             sc->arpcom.ac_enaddr[1] == 0xA0 &&
  216             sc->arpcom.ac_enaddr[2] == 0xC9) {    /* it's a 10+ */
  217                 sc->irq2ee = plus_irq2eemap;
  218                 sc->ee2irq = plus_ee2irqmap;
  219         } else {                                  /* it's an ordinary 10 */
  220                 sc->irq2ee = irq2eemap;
  221                 sc->ee2irq = ee2irqmap;
  222         }
  223 
  224         if (dev->id_irq > 0) {
  225                 if (sc->ee2irq[tmp] != ffs(dev->id_irq) - 1)
  226                         printf("ex%d: WARNING: board's EEPROM is configured for IRQ %d, using %d\n", unit, sc->ee2irq[tmp], ffs(dev->id_irq) - 1);
  227                 sc->irq_no = ffs(dev->id_irq) - 1;
  228         }
  229         else {
  230                 sc->irq_no = sc->ee2irq[tmp];
  231                 dev->id_irq = 1 << sc->irq_no;
  232         }
  233         if (sc->irq_no == 0) {
  234                 printf("ex%d: invalid IRQ.\n", unit);
  235                 return(0);
  236         }
  237         outb(iobase + CMD_REG, Bank2_Sel);
  238         tmp = inb(iobase + REG3);
  239         if (tmp & TPE_bit)
  240                 sc->connector = Conn_TPE;
  241         else if (tmp & BNC_bit)
  242                 sc->connector = Conn_BNC;
  243         else
  244                 sc->connector = Conn_AUI;
  245         sc->mem_size = CARD_RAM_SIZE;   /* XXX This should be read from the card itself. */
  246 
  247         outb(iobase + CMD_REG, Bank0_Sel);
  248 
  249         DODEBUG(Start_End, printf("ex_probe%d: finish\n", unit););
  250         return(EX_IOSIZE);
  251 }
  252 
  253 
  254 int ex_attach(struct isa_device *dev)
  255 {
  256         int unit = dev->id_unit;
  257         struct ex_softc *sc = &ex_sc[unit];
  258         struct ifnet *ifp = &sc->arpcom.ac_if;
  259         struct ifaddr *ifa;
  260         struct sockaddr_dl *sdl;
  261 
  262         DODEBUG(Start_End, printf("ex_attach%d: start\n", unit););
  263 
  264         /*
  265          * Initialize the ifnet structure.
  266          */
  267         ifp->if_softc = sc;
  268         ifp->if_unit = unit;
  269         ifp->if_name = "ex";
  270         ifp->if_init = ex_init;
  271         ifp->if_output = ether_output;
  272         ifp->if_start = ex_start;
  273         ifp->if_ioctl = ex_ioctl;
  274         ifp->if_watchdog = ex_watchdog;
  275         ifp->if_mtu = ETHERMTU;
  276         ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST /* XXX not done yet. | IFF_MULTICAST */;
  277 
  278         /*
  279          * Attach the interface.
  280          */
  281         if_attach(ifp);
  282         ether_ifattach(ifp);
  283 
  284         if (sc->arpcom.ac_enaddr[0] == 0x00 &&
  285             sc->arpcom.ac_enaddr[1] == 0xA0 &&
  286             sc->arpcom.ac_enaddr[2] == 0xC9) {
  287                 printf("ex%d: Intel EtherExpress Pro/10+, address %6D, connector ", dev->id_unit, sc->arpcom.ac_enaddr, ":");
  288         } else {
  289                 printf("ex%d: Intel EtherExpress Pro/10, address %6D, connector ", dev->id_unit, sc->arpcom.ac_enaddr, ":");
  290         }
  291         switch(sc->connector) {
  292                 case Conn_TPE: printf("TPE\n"); break;
  293                 case Conn_BNC: printf("BNC\n"); break;
  294                 case Conn_AUI: printf("AUI\n"); break;
  295                 default: printf("???\n");
  296         }
  297 
  298         /*
  299          * If BPF is in the kernel, call the attach for it
  300          */
  301 #if NBPFILTER > 0
  302         bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
  303 #endif
  304         DODEBUG(Start_End, printf("ex_attach%d: finish\n", unit););
  305         return(1);
  306 }
  307 
  308 
  309 void ex_init(void *xsc)
  310 {
  311         register struct ex_softc *sc = (struct ex_softc *) xsc;
  312         struct ifnet *ifp = &sc->arpcom.ac_if;
  313         int s, i;
  314         register int iobase = sc->iobase;
  315         unsigned short temp_reg;
  316 
  317         DODEBUG(Start_End, printf("ex_init%d: start\n", ifp->if_unit););
  318 
  319         if (ifp->if_addrlist == (struct ifaddr *) 0)
  320           return;
  321         s = splimp();
  322         sc->arpcom.ac_if.if_timer = 0;
  323 
  324         /*
  325          * Load the ethernet address into the card.
  326          */
  327         outb(iobase + CMD_REG, Bank2_Sel);
  328         temp_reg = inb(iobase + EEPROM_REG);
  329         if (temp_reg & Trnoff_Enable)
  330           outb(iobase + EEPROM_REG, temp_reg & ~Trnoff_Enable);
  331         for (i = 0; i < ETHER_ADDR_LEN; i++)
  332           outb(iobase + I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]);
  333         /*
  334          * - Setup transmit chaining and discard bad received frames.
  335          * - Match broadcast.
  336          * - Clear test mode.
  337          * - Set receiving mode.
  338          * - Set IRQ number.
  339          */
  340         outb(iobase + REG1, inb(iobase + REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr);
  341         outb(iobase + REG2, inb(iobase + REG2) | No_SA_Ins | RX_CRC_InMem);
  342         outb(iobase + REG3, inb(iobase + REG3) & 0x3f /* XXX constants. */ );
  343         outb(iobase + CMD_REG, Bank1_Sel);
  344         outb(iobase + INT_NO_REG, (inb(iobase + INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]);
  345 
  346         /*
  347          * Divide the available memory in the card into rcv and xmt buffers.
  348          * By default, I use the first 3/4 of the memory for the rcv buffer,
  349          * and the remaining 1/4 of the memory for the xmt buffer.
  350          */
  351         sc->rx_mem_size = sc->mem_size * 3 / 4;
  352         sc->tx_mem_size = sc->mem_size - sc->rx_mem_size;
  353         sc->rx_lower_limit = 0x0000;
  354         sc->rx_upper_limit = sc->rx_mem_size - 2;
  355         sc->tx_lower_limit = sc->rx_mem_size;
  356         sc->tx_upper_limit = sc->mem_size - 2;
  357         outb(iobase + RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8);
  358         outb(iobase + RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8);
  359         outb(iobase + XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8);
  360         outb(iobase + XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8);
  361         
  362         /*
  363          * Enable receive and transmit interrupts, and clear any pending int.
  364          */
  365         outb(iobase + REG1, inb(iobase + REG1) | TriST_INT);
  366         outb(iobase + CMD_REG, Bank0_Sel);
  367         outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
  368         outb(iobase + STATUS_REG, All_Int);
  369 
  370         /*
  371          * Initialize receive and transmit ring buffers.
  372          */
  373         outw(iobase + RCV_BAR, sc->rx_lower_limit);
  374         sc->rx_head = sc->rx_lower_limit;
  375         outw(iobase + RCV_STOP_REG, sc->rx_upper_limit | 0xfe);
  376         outw(iobase + XMT_BAR, sc->tx_lower_limit);
  377         sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
  378 
  379         ifp->if_flags |= IFF_RUNNING;
  380         ifp->if_flags &= ~IFF_OACTIVE;
  381         DODEBUG(Status, printf("OIDLE init\n"););
  382         
  383         /*
  384          * Final reset of the board, and enable operation.
  385          */
  386         outb(iobase + CMD_REG, Sel_Reset_CMD);
  387         DELAY(2);
  388         outb(iobase + CMD_REG, Rcv_Enable_CMD);
  389 
  390         ex_start(ifp);
  391         splx(s);
  392 
  393         DODEBUG(Start_End, printf("ex_init%d: finish\n", ifp->if_unit););
  394 }
  395 
  396 
  397 void ex_start(struct ifnet *ifp)
  398 {
  399   int unit = ifp->if_unit;
  400   register struct ex_softc *sc = &ex_sc[unit];
  401   register int iobase = sc->iobase;
  402   int i, s, len, data_len, avail, dest, next;
  403   unsigned char tmp16[2], *cP;
  404   struct mbuf *opkt;
  405   register struct mbuf *m;
  406 
  407   DODEBUG(Start_End, printf("ex_start%d: start\n", unit););
  408 
  409   s = splimp();
  410 
  411   /*
  412    * Main loop: send outgoing packets to network card until there are no
  413    * more packets left, or the card cannot accept any more yet.
  414    */
  415   while (((opkt = ifp->if_snd.ifq_head) != NULL) && ! (ifp->if_flags & IFF_OACTIVE)) {
  416 
  417     /*
  418      * Ensure there is enough free transmit buffer space for this packet,
  419      * including its header. Note: the header cannot wrap around the end of
  420      * the transmit buffer and must be kept together, so we allow space for
  421      * twice the length of the header, just in case.
  422      */
  423     for (len = 0, m = opkt; m != NULL; m = m->m_next)
  424       len += m->m_len;
  425     data_len = len;
  426     DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len););
  427     if (len & 1)
  428       len += XMT_HEADER_LEN + 1;
  429     else
  430       len += XMT_HEADER_LEN;
  431     if ((i = sc->tx_tail - sc->tx_head) >= 0)
  432       avail = sc->tx_mem_size - i;
  433     else
  434       avail = -i;
  435         DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail););
  436     if (avail >= len + XMT_HEADER_LEN) {
  437       IF_DEQUEUE(&ifp->if_snd, opkt);
  438 
  439 #ifdef EX_PSA_INTR      
  440       /*
  441        * Disable rx and tx interrupts, to avoid corruption of the host
  442        * address register by interrupt service routines. XXX Is this necessary with splimp() enabled?
  443        */
  444       outb(iobase + MASK_REG, All_Int);
  445 #endif
  446 
  447       /*
  448        * Compute the start and end addresses of this frame in the tx buffer.
  449        */
  450       dest = sc->tx_tail;
  451       next = dest + len;
  452       if (next > sc->tx_upper_limit) {
  453         if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= XMT_HEADER_LEN) {
  454           dest = sc->tx_lower_limit;
  455           next = dest + len;
  456         }
  457         else
  458           next = sc->tx_lower_limit + next - sc->tx_upper_limit - 2;
  459       }
  460 
  461       /*
  462        * Build the packet frame in the card's ring buffer.
  463        */
  464       DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next););
  465       outw(iobase + HOST_ADDR_REG, dest);
  466       outw(iobase + IO_PORT_REG, Transmit_CMD);
  467       outw(iobase + IO_PORT_REG, 0);
  468       outw(iobase + IO_PORT_REG, next);
  469       outw(iobase + IO_PORT_REG, data_len);
  470 
  471         /*
  472          * Output the packet data to the card. Ensure all transfers are
  473          * 16-bit wide, even if individual mbufs have odd length.
  474          */
  475 
  476      for (m = opkt, i = 0; m != NULL; m = m->m_next) {
  477                 DODEBUG(Sent_Pkts, printf("[%d]", m->m_len););
  478                 if (i) {
  479                         tmp16[1] = *(mtod(m, caddr_t));
  480                         outsw(iobase + IO_PORT_REG, tmp16, 1);
  481                 }
  482                 outsw(iobase + IO_PORT_REG, mtod(m, caddr_t) + i, (m->m_len - i) / 2);
  483                 if (i = (m->m_len - i) & 1)
  484                         tmp16[0] = *(mtod(m, caddr_t) + m->m_len - 1);
  485         }
  486         if (i)
  487                 outsw(iobase + IO_PORT_REG, tmp16, 1);
  488 
  489       /*
  490        * If there were other frames chained, update the chain in the last one.
  491        */
  492       if (sc->tx_head != sc->tx_tail) {
  493         if (sc->tx_tail != dest) {
  494           outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_Chain_Point);
  495           outw(iobase + IO_PORT_REG, dest);
  496         }
  497         outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_Byte_Count);
  498         i = inw(iobase + IO_PORT_REG);
  499         outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_Byte_Count);
  500         outw(iobase + IO_PORT_REG, i | Ch_bit);
  501       }
  502 
  503       /*
  504        * Resume normal operation of the card:
  505        * - Make a dummy read to flush the DRAM write pipeline.
  506        * - Enable receive and transmit interrupts.
  507        * - Send Transmit or Resume_XMT command, as appropriate.
  508        */
  509       inw(iobase + IO_PORT_REG);
  510 #ifdef EX_PSA_INTR
  511       outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int));
  512 #endif
  513       if (sc->tx_head == sc->tx_tail) {
  514         outw(iobase + XMT_BAR, dest);
  515         outb(iobase + CMD_REG, Transmit_CMD);
  516         sc->tx_head = dest;
  517         DODEBUG(Sent_Pkts, printf("Transmit\n"););
  518       }
  519       else {
  520         outb(iobase + CMD_REG, Resume_XMT_List_CMD);
  521         DODEBUG(Sent_Pkts, printf("Resume\n"););
  522         }
  523       sc->tx_last = dest;
  524       sc->tx_tail = next;
  525       
  526 #if NBPFILTER > 0
  527       if (ifp->if_bpf != NULL)
  528         bpf_mtap(ifp, opkt);
  529 #endif
  530       ifp->if_timer = 2;
  531       ifp->if_opackets++;
  532       m_freem(opkt);
  533     }
  534     else {
  535       ifp->if_flags |= IFF_OACTIVE;
  536           DODEBUG(Status, printf("OACTIVE start\n"););
  537         }
  538   }
  539 
  540   splx(s);
  541 
  542   DODEBUG(Start_End, printf("ex_start%d: finish\n", unit););
  543 }
  544 
  545 
  546 void ex_stop(int unit)
  547 {
  548   struct ex_softc *sc = &ex_sc[unit];
  549   int iobase = sc->iobase;
  550 
  551   DODEBUG(Start_End, printf("ex_stop%d: start\n", unit););
  552 
  553   /*
  554    * Disable card operation:
  555    * - Disable the interrupt line.
  556    * - Flush transmission and disable reception.
  557    * - Mask and clear all interrupts.
  558    * - Reset the 82595.
  559    */
  560   outb(iobase + CMD_REG, Bank1_Sel);
  561   outb(iobase + REG1, inb(iobase + REG1) & ~TriST_INT);
  562   outb(iobase + CMD_REG, Bank0_Sel);
  563   outb(iobase + CMD_REG, Rcv_Stop);
  564   sc->tx_head = sc->tx_tail = sc->tx_lower_limit;
  565   sc->tx_last = 0; /* XXX I think these two lines are not necessary, because ex_init will always be called again to reinit the interface. */
  566   outb(iobase + MASK_REG, All_Int);
  567   outb(iobase + STATUS_REG, All_Int);
  568   outb(iobase + CMD_REG, Reset_CMD);
  569   DELAY(200);
  570 
  571   DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit););
  572 }
  573 
  574 
  575 void exintr(int unit)
  576 {
  577   struct ex_softc *sc = &ex_sc[unit];
  578   struct ifnet *ifp = &sc->arpcom.ac_if;
  579   int iobase = sc->iobase;
  580   int s, int_status, send_pkts;
  581 
  582   DODEBUG(Start_End, printf("exintr%d: start\n", unit););
  583 
  584 #ifdef EXDEBUG
  585         if (++exintr_count != 1)
  586                 printf("WARNING: nested interrupt (%d). Mail the author.\n", exintr_count);
  587 #endif
  588 
  589   send_pkts = 0;
  590   while ((int_status = inb(iobase + STATUS_REG)) & (Tx_Int | Rx_Int)) {
  591     if (int_status & Rx_Int) {
  592       outb(iobase + STATUS_REG, Rx_Int);
  593       ex_rx_intr(unit);
  594     }
  595         else if (int_status & Tx_Int) {
  596       outb(iobase + STATUS_REG, Tx_Int);
  597       ex_tx_intr(unit);
  598       send_pkts = 1;
  599     }
  600   }
  601 
  602   /*
  603    * If any packet has been transmitted, and there are queued packets to
  604    * be sent, attempt to send more packets to the network card.
  605    */
  606 
  607   if (send_pkts && (ifp->if_snd.ifq_head != NULL))
  608     ex_start(ifp);
  609 
  610 #ifdef EXDEBUG
  611         exintr_count--;
  612 #endif
  613 
  614   DODEBUG(Start_End, printf("exintr%d: finish\n", unit););
  615 }
  616 
  617 
  618 void ex_tx_intr(int unit)
  619 {
  620   register struct ex_softc *sc = &ex_sc[unit];
  621   register struct ifnet *ifp = &sc->arpcom.ac_if;
  622   register int iobase = sc->iobase;
  623   int tx_status;
  624 
  625   DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit););
  626 
  627   /*
  628    * - Cancel the watchdog.
  629    * For all packets transmitted since last transmit interrupt:
  630    * - Advance chain pointer to next queued packet.
  631    * - Update statistics.
  632    */
  633 
  634   ifp->if_timer = 0;
  635   while (sc->tx_head != sc->tx_tail) {
  636     outw(iobase + HOST_ADDR_REG, sc->tx_head);
  637     if (! inw(iobase + IO_PORT_REG) & Done_bit)
  638       break;
  639     tx_status = inw(iobase + IO_PORT_REG);
  640     sc->tx_head = inw(iobase + IO_PORT_REG);
  641     if (tx_status & TX_OK_bit)
  642       ifp->if_opackets++;
  643     else
  644       ifp->if_oerrors++;
  645     ifp->if_collisions += tx_status & No_Collisions_bits;
  646   }
  647 
  648   /*
  649    * The card should be ready to accept more packets now.
  650    */
  651 
  652   ifp->if_flags &= ~IFF_OACTIVE;
  653   DODEBUG(Status, printf("OIDLE tx_intr\n"););
  654 
  655   DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit););
  656 }
  657 
  658 
  659 void ex_rx_intr(int unit)
  660 {
  661   register struct ex_softc *sc = &ex_sc[unit];
  662   register struct ifnet *ifp = &sc->arpcom.ac_if;
  663   register int iobase = sc->iobase;
  664   int rx_status, pkt_len, QQQ;
  665   register struct mbuf *m, *ipkt;
  666   struct ether_header *eh;
  667 
  668   DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit););
  669 
  670   /*
  671    * For all packets received since last receive interrupt:
  672    * - If packet ok, read it into a new mbuf and queue it to interface,
  673    *   updating statistics.
  674    * - If packet bad, just discard it, and update statistics.
  675    * Finally, advance receive stop limit in card's memory to new location.
  676    */
  677 
  678   outw(iobase + HOST_ADDR_REG, sc->rx_head);
  679   while (inw(iobase + IO_PORT_REG) == RCV_Done) {
  680     rx_status = inw(iobase + IO_PORT_REG);
  681     sc->rx_head = inw(iobase + IO_PORT_REG);
  682     QQQ = pkt_len = inw(iobase + IO_PORT_REG);
  683     if (rx_status & RCV_OK_bit) {
  684       MGETHDR(m, M_DONTWAIT, MT_DATA);
  685       ipkt = m;
  686       if (ipkt == NULL)
  687         ifp->if_iqdrops++;
  688       else {
  689         ipkt->m_pkthdr.rcvif = ifp;
  690         ipkt->m_pkthdr.len = pkt_len;
  691         ipkt->m_len = MHLEN;
  692         while (pkt_len > 0) {
  693           if (pkt_len > MINCLSIZE) {
  694             MCLGET(m, M_DONTWAIT);
  695             if (m->m_flags & M_EXT)
  696               m->m_len = MCLBYTES;
  697             else {
  698               m_freem(ipkt);
  699               ifp->if_iqdrops++;
  700               goto rx_another;
  701             }
  702           }
  703           m->m_len = min(m->m_len, pkt_len);
  704 
  705           /*
  706            * NOTE: I'm assuming that all mbufs allocated are of even length,
  707            * except for the last one in an odd-length packet.
  708            */
  709           insw(iobase + IO_PORT_REG, mtod(m, caddr_t), m->m_len / 2);
  710           if (m->m_len & 1)
  711                 *(mtod(m, caddr_t) + m->m_len - 1) = inb(iobase + IO_PORT_REG);
  712           pkt_len -= m->m_len;
  713           if (pkt_len > 0) {
  714             MGET(m->m_next, M_DONTWAIT, MT_DATA);
  715             if (m->m_next == NULL) {
  716               m_freem(ipkt);
  717               ifp->if_iqdrops++;
  718               goto rx_another;
  719             }
  720             m = m->m_next;
  721             m->m_len = MLEN;
  722           }
  723         }
  724         eh = mtod(ipkt, struct ether_header *);
  725 #ifdef EXDEBUG
  726           if (debug_mask & Rcvd_Pkts) {
  727           if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) {
  728             printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":");
  729             printf("%6D\n", eh->ether_dhost, ":");
  730           } /* QQQ */
  731           }
  732 #endif
  733 #if NBPFILTER > 0
  734         if (ifp->if_bpf != NULL) {
  735                 bpf_mtap(ifp, ipkt);
  736 
  737                 /*
  738                  * Note that the interface cannot be in promiscuous mode if there are
  739                  * no BPF listeners. And if we are in promiscuous mode, we have to
  740                  * check if this packet is really ours.
  741                  */
  742                 if ((ifp->if_flags & IFF_PROMISC) &&
  743                     (eh->ether_dhost[0] & 1) == 0 &&
  744                     bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0 &&
  745                     bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)) != 0) {
  746                         m_freem(ipkt);
  747                         goto rx_another;
  748                 }
  749         }
  750 #endif
  751         m_adj(ipkt, sizeof(struct ether_header));
  752         ether_input(ifp, eh, ipkt);
  753         ifp->if_ipackets++;
  754       }
  755     }
  756     else
  757       ifp->if_ierrors++;
  758     outw(iobase + HOST_ADDR_REG, sc->rx_head);
  759   rx_another:
  760   }
  761   if (sc->rx_head < sc->rx_lower_limit + 2)
  762     outw(iobase + RCV_STOP_REG, sc->rx_upper_limit);
  763   else
  764     outw(iobase + RCV_STOP_REG, sc->rx_head - 2);
  765 
  766   DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit););
  767 }
  768 
  769 
  770 int ex_ioctl(register struct ifnet *ifp, int cmd, caddr_t data)
  771 {
  772   register struct ifaddr *ifa = (struct ifaddr *) data;
  773   struct ex_softc *sc = &ex_sc[ifp->if_unit];
  774   struct ifreq *ifr = (struct ifreq *) data;
  775   int s, error = 0;
  776 
  777   DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit););
  778 
  779   s = splimp();
  780 
  781   switch(cmd) {
  782   case SIOCSIFADDR:
  783     DODEBUG(Start_End, printf("SIOCSIFADDR"););
  784     ifp->if_flags |= IFF_UP;
  785     
  786     switch(ifa->ifa_addr->sa_family) {
  787 #ifdef INET
  788     case AF_INET:
  789       ex_init(sc);
  790       arp_ifinit((struct arpcom *) ifp, ifa);
  791       break;
  792 #endif
  793 #ifdef IPX_NOTYET
  794     case AF_IPX:
  795       {
  796         register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
  797 
  798         if (ipx_nullhost(*ina))
  799           ina->x_host = *(union ipx_host *) (sc->arpcom.ac_enaddr);
  800         else {
  801           ifp->if_flags &= ~IFF_RUNNING;
  802           bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr));
  803         }
  804         ex_init(sc);
  805         break;
  806       }
  807 #endif
  808 #ifdef NS
  809     case AF_NS:
  810       {
  811         register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
  812 
  813         if (ns_nullhost(*ina))
  814           ina->x_host = *(union ns_host *) (sc->arpcom.ac_enaddr);
  815         else {
  816           ifp->if_flags &= ~IFF_RUNNING;
  817           bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr));
  818         }
  819         ex_init(sc);
  820         break;
  821       }
  822 #endif
  823     default:
  824       ex_init(sc);
  825       break;
  826     }
  827     break;
  828   case SIOCGIFADDR:
  829     {
  830       struct sockaddr *sa;
  831 
  832       DODEBUG(Start_End, printf("SIOCGIFADDR"););
  833       sa = (struct sockaddr *) &ifr->ifr_data;
  834       bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
  835     }
  836   break;
  837   case SIOCSIFFLAGS:
  838     DODEBUG(Start_End, printf("SIOCSIFFLAGS"););
  839     if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
  840       ifp->if_flags &= ~IFF_RUNNING;
  841       ex_stop(ifp->if_unit);
  842     }
  843     else
  844       ex_init(sc);
  845     break;
  846 #ifdef NODEF
  847   case SIOCGHWADDR:
  848     DODEBUG(Start_End, printf("SIOCGHWADDR"););
  849     bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr));
  850     break;
  851 #endif
  852   case SIOCSIFMTU:
  853     DODEBUG(Start_End, printf("SIOCSIFMTU"););
  854     if (ifr->ifr_mtu > ETHERMTU)
  855       error = EINVAL;
  856     else
  857       ifp->if_mtu = ifr->ifr_mtu;
  858     break;
  859   case SIOCADDMULTI:
  860     DODEBUG(Start_End, printf("SIOCADDMULTI"););
  861   case SIOCDELMULTI:
  862     DODEBUG(Start_End, printf("SIOCDELMULTI"););
  863     /* XXX Support not done yet. */
  864     error = EINVAL;
  865     break;
  866   default:
  867     DODEBUG(Start_End, printf("unknown"););
  868     error = EINVAL;
  869   }
  870 
  871   splx(s);
  872 
  873   DODEBUG(Start_End, printf("\nex_ioctl%d: finish\n", ifp->if_unit););
  874   return(error);
  875 }
  876 
  877 
  878 void ex_reset(int unit)
  879 {
  880   struct ex_softc *sc = &ex_sc[unit];
  881   struct ifnet *ifp = &sc->arpcom.ac_if;
  882   int s;
  883 
  884   DODEBUG(Start_End, printf("ex_reset%d: start\n", unit););
  885   
  886   s = splimp();
  887 
  888   ex_stop(unit);
  889   ex_init(sc);
  890 
  891   splx(s);
  892 
  893   DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit););
  894 }
  895 
  896 
  897 void ex_watchdog(struct ifnet *ifp)
  898 {
  899   struct ex_softc *sc = &ex_sc[ifp->if_unit];
  900 
  901   DODEBUG(Start_End, printf("ex_watchdog%d: start\n", ifp->if_unit););
  902 
  903   ifp->if_flags &= ~IFF_OACTIVE;
  904   DODEBUG(Status, printf("OIDLE watchdog\n"););
  905   ifp->if_oerrors++;
  906   ex_reset(ifp->if_unit);
  907   ex_start(ifp);
  908 
  909   DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit););
  910 }
  911 
  912 
  913 static u_short eeprom_read(int iobase, int location)
  914 {
  915         int i;
  916         u_short data = 0;
  917         int ee_addr;
  918         int read_cmd = location | EE_READ_CMD;
  919         short ctrl_val = EECS;
  920 
  921         ee_addr = iobase + EEPROM_REG;
  922         outb(iobase + CMD_REG, Bank2_Sel);
  923         outb(ee_addr, EECS);
  924         for (i = 8; i >= 0; i--) {
  925                 short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val;
  926                 outb(ee_addr, outval);
  927                 outb(ee_addr, outval | EESK);
  928                 DELAY(3);
  929                 outb(ee_addr, outval);
  930                 DELAY(2);
  931         }
  932         outb(ee_addr, ctrl_val);
  933 
  934         for (i = 16; i > 0; i--) {
  935                 outb(ee_addr, ctrl_val | EESK);
  936                 DELAY(3);
  937                 data = (data << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0);
  938                 outb(ee_addr, ctrl_val);
  939                 DELAY(2);
  940         }
  941 
  942         ctrl_val &= ~EECS;
  943         outb(ee_addr, ctrl_val | EESK);
  944         DELAY(3);
  945         outb(ee_addr, ctrl_val);
  946         DELAY(2);
  947         outb(iobase + CMD_REG, Bank0_Sel);
  948         return(data);
  949 }
  950 
  951 #endif /* NEX > 0 */

Cache object: e081f77aaa79850c3823d34a61dfc523


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