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

Cache object: 7d820831d54ebf0286d8ff0f80d54c66


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