Annotation of qemu/roms/ipxe/src/drivers/net/w89c840.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Etherboot -  BOOTP/TFTP Bootstrap Program
                      3:  *
                      4:  * w89c840.c -- This file implements the winbond-840 driver for etherboot.
                      5:  *
                      6:  */
                      7: 
                      8: /*
                      9:  * Adapted by Igor V. Kovalenko
                     10:  *  -- <[email protected]>
                     11:  *   OR
                     12:  *  -- <[email protected]>
                     13:  * Initial adaptaion stage, including testing, completed 23 August 2000.
                     14:  */
                     15: 
                     16: /*
                     17:  * This program is free software; you can redistribute it and/or
                     18:  * modify it under the terms of the GNU General Public License as
                     19:  * published by the Free Software Foundation; either version 2, or (at
                     20:  * your option) any later version.
                     21:  *
                     22:  * This program is distributed in the hope that it will be useful, but
                     23:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     24:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     25:  * General Public License for more details.
                     26:  *
                     27:  * You should have received a copy of the GNU General Public License
                     28:  * along with this program; if not, write to the Free Software
                     29:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     30:  */
                     31: 
                     32: FILE_LICENCE ( GPL2_OR_LATER );
                     33: 
                     34: /*
                     35:  *              date       version  by   what
                     36:  *  Written:    Aug 20 2000  V0.10  iko  Initial revision.
                     37:  * changes:     Aug 22 2000  V0.90  iko  Works!
                     38:  *              Aug 23 2000  V0.91  iko  Cleanup, posted to etherboot
                     39:  *                                       maintainer.
                     40:  *              Aug 26 2000  V0.92  iko  Fixed Rx ring handling.
                     41:  *                                       First Linux Kernel (TM)
                     42:  *                                       successfully loaded using
                     43:  *                                       this driver.
                     44:  *              Jan 07 2001  V0.93  iko  Transmitter timeouts are handled
                     45:  *                                       using timer2 routines. Proposed
                     46:  *                                       by Ken Yap to eliminate CPU speed
                     47:  *                                       dependency.
                     48:  *             Dec 12 2003  V0.94   timlegge   Fixed issues in 5.2, removed 
                     49:  *                                                     interrupt usage, enabled
                     50:  *                                                     multicast support
                     51:  *
                     52:  * This is the etherboot driver for cards based on Winbond W89c840F chip.
                     53:  *
                     54:  * It was written from skeleton source, with Donald Becker's winbond-840.c
                     55:  * kernel driver as a guideline. Mostly the w89c840 related definitions
                     56:  * and the lower level routines have been cut-and-pasted into this source.
                     57:  *
                     58:  * Frankly speaking, about 90% of the code was obtained using cut'n'paste
                     59:  * sequence :) while the remainder appeared while brainstorming
                     60:  * Linux Kernel 2.4.0-testX source code. Thanks, Donald and Linus!
                     61:  *
                     62:  * There was a demand for using this card in a rather large
                     63:  * remote boot environment at MSKP OVTI Lab of
                     64:  * Moscow Institute for Physics and Technology (MIPT) -- http://www.mipt.ru/
                     65:  * so you may count that for motivation.
                     66:  *
                     67:  */
                     68: 
                     69: /*
                     70:  * If you want to see debugging output then define W89C840_DEBUG
                     71:  */
                     72: 
                     73: /*
                     74: #define W89C840_DEBUG
                     75: */
                     76: 
                     77: /*
                     78:  * Keep using IO_OPS for Etherboot driver!
                     79:  */
                     80: #define USE_IO_OPS
                     81: 
                     82: #include "etherboot.h"
                     83: #include "nic.h"
                     84: #include <ipxe/pci.h>
                     85: #include <ipxe/ethernet.h>
                     86: 
                     87: static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
                     88: 
                     89: /* Linux support functions */
                     90: #define virt_to_le32desc(addr)  virt_to_bus(addr)
                     91: #define le32desc_to_virt(addr)  bus_to_virt(addr)
                     92: 
                     93: /*
                     94: #define cpu_to_le32(val) (val)
                     95: #define le32_to_cpu(val) (val)
                     96: */
                     97: 
                     98: /* Operational parameters that are set at compile time. */
                     99: 
                    100: /* Keep the ring sizes a power of two for compile efficiency.
                    101:    The compiler will convert <unsigned>'%'<2^N> into a bit mask.
                    102:    Making the Tx ring too large decreases the effectiveness of channel
                    103:    bonding and packet priority.
                    104:    There are no ill effects from too-large receive rings. */
                    105: #define TX_RING_SIZE    2
                    106: #define RX_RING_SIZE    2
                    107: 
                    108: /* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
                    109:    To avoid overflowing we don't queue again until we have room for a
                    110:    full-size packet.
                    111:  */
                    112: #define TX_FIFO_SIZE (2048)
                    113: #define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
                    114: 
                    115: /* Operational parameters that usually are not changed. */
                    116: /* Time in jiffies before concluding the transmitter is hung. */
                    117: #define TX_TIMEOUT  (10*1000)
                    118: 
                    119: #define PKT_BUF_SZ  1536  /* Size of each temporary Rx buffer.*/
                    120: 
                    121: /*
                    122:  * Used to be this much CPU loops on Celeron@400 (?),
                    123:  * now using real timer and TX_TIMEOUT!
                    124:  * #define TX_LOOP_COUNT 10000000
                    125:  */
                    126: 
                    127: #if !defined(__OPTIMIZE__)
                    128: #warning  You must compile this file with the correct options!
                    129: #warning  See the last lines of the source file.
                    130: #error You must compile this driver with "-O".
                    131: #endif
                    132: 
                    133: enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2};
                    134: 
                    135: #ifdef USE_IO_OPS
                    136: #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
                    137: #else
                    138: #define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
                    139: #endif
                    140: 
                    141: static u32 driver_flags = CanHaveMII | HasBrokenTx;
                    142: 
                    143: /* This driver was written to use PCI memory space, however some x86 systems
                    144:    work only with I/O space accesses.  Pass -DUSE_IO_OPS to use PCI I/O space
                    145:    accesses instead of memory space. */
                    146: 
                    147: #ifdef USE_IO_OPS
                    148: #undef readb
                    149: #undef readw
                    150: #undef readl
                    151: #undef writeb
                    152: #undef writew
                    153: #undef writel
                    154: #define readb inb
                    155: #define readw inw
                    156: #define readl inl
                    157: #define writeb outb
                    158: #define writew outw
                    159: #define writel outl
                    160: #endif
                    161: 
                    162: /* Offsets to the Command and Status Registers, "CSRs".
                    163:    While similar to the Tulip, these registers are longword aligned.
                    164:    Note: It's not useful to define symbolic names for every register bit in
                    165:    the device.  The name can only partially document the semantics and make
                    166:    the driver longer and more difficult to read.
                    167: */
                    168: enum w840_offsets {
                    169:     PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
                    170:     RxRingPtr=0x0C, TxRingPtr=0x10,
                    171:     IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
                    172:     RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
                    173:     CurRxDescAddr=0x30, CurRxBufAddr=0x34,            /* Debug use */
                    174:     MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
                    175:     CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
                    176: };
                    177: 
                    178: /* Bits in the interrupt status/enable registers. */
                    179: /* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
                    180: enum intr_status_bits {
                    181:     NormalIntr=0x10000, AbnormalIntr=0x8000,
                    182:     IntrPCIErr=0x2000, TimerInt=0x800,
                    183:     IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
                    184:     TxFIFOUnderflow=0x20, RxErrIntr=0x10,
                    185:     TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
                    186: };
                    187: 
                    188: /* Bits in the NetworkConfig register. */
                    189: enum rx_mode_bits {
                    190:     AcceptErr=0x80, AcceptRunt=0x40,
                    191:     AcceptBroadcast=0x20, AcceptMulticast=0x10,
                    192:     AcceptAllPhys=0x08, AcceptMyPhys=0x02,
                    193: };
                    194: 
                    195: enum mii_reg_bits {
                    196:     MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
                    197:     MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
                    198: };
                    199: 
                    200: /* The Tulip Rx and Tx buffer descriptors. */
                    201: struct w840_rx_desc {
                    202:     s32 status;
                    203:     s32 length;
                    204:     u32 buffer1;
                    205:     u32 next_desc;
                    206: };
                    207: 
                    208: struct w840_tx_desc {
                    209:     s32 status;
                    210:     s32 length;
                    211:     u32 buffer1, buffer2;                /* We use only buffer 1.  */
                    212: };
                    213: 
                    214: /* Bits in network_desc.status */
                    215: enum desc_status_bits {
                    216:     DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
                    217:     DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
                    218:     DescIntr=0x80000000,
                    219: };
                    220: #define PRIV_ALIGN    15     /* Required alignment mask */
                    221: #define PRIV_ALIGN_BYTES 32
                    222: 
                    223: static struct winbond_private
                    224: {
                    225:     /* Descriptor rings first for alignment. */
                    226:     struct w840_rx_desc rx_ring[RX_RING_SIZE];
                    227:     struct w840_tx_desc tx_ring[TX_RING_SIZE];
                    228:     struct net_device *next_module;        /* Link for devices of this type. */
                    229:     void *priv_addr;                    /* Unaligned address for kfree */
                    230:     const char *product_name;
                    231:     /* Frequently used values: keep some adjacent for cache effect. */
                    232:     int chip_id, drv_flags;
                    233:     struct pci_dev *pci_dev;
                    234:     int csr6;
                    235:     struct w840_rx_desc *rx_head_desc;
                    236:     unsigned int cur_rx, dirty_rx;        /* Producer/consumer ring indices */
                    237:     unsigned int rx_buf_sz;                /* Based on MTU+slack. */
                    238:     unsigned int cur_tx, dirty_tx;
                    239:     int tx_q_bytes;
                    240:     unsigned int tx_full:1;                /* The Tx queue is full. */
                    241:     /* These values are keep track of the transceiver/media in use. */
                    242:     unsigned int full_duplex:1;            /* Full-duplex operation requested. */
                    243:     unsigned int duplex_lock:1;
                    244:     unsigned int medialock:1;            /* Do not sense media. */
                    245:     unsigned int default_port:4;        /* Last dev->if_port value. */
                    246:     /* MII transceiver section. */
                    247:     int mii_cnt;                        /* MII device addresses. */
                    248:     u16 advertising;                    /* NWay media advertisement */
                    249:     unsigned char phys[2];                /* MII device addresses. */
                    250: } w840private __attribute__ ((aligned (PRIV_ALIGN_BYTES)));
                    251: 
                    252: /* NIC specific static variables go here */
                    253: 
                    254: static int ioaddr;
                    255: static unsigned short eeprom [0x40];
                    256: struct {
                    257:        char        rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
                    258:        char        tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
                    259: } w89c840_buf __shared;
                    260: 
                    261: static int  eeprom_read(long ioaddr, int location);
                    262: static int  mdio_read(int base_address, int phy_id, int location);
                    263: #if 0
                    264: static void mdio_write(int base_address, int phy_id, int location, int value);
                    265: #endif
                    266: 
                    267: static void check_duplex(void);
                    268: static void set_rx_mode(void);
                    269: static void init_ring(void);
                    270: 
                    271: #if defined(W89C840_DEBUG)
                    272: static void decode_interrupt(u32 intr_status)
                    273: {
                    274:     printf("Interrupt status: ");
                    275: 
                    276: #define TRACE_INTR(_intr_) \
                    277:     if (intr_status & (_intr_)) { printf (" " #_intr_); }
                    278: 
                    279:     TRACE_INTR(NormalIntr);
                    280:     TRACE_INTR(AbnormalIntr);
                    281:     TRACE_INTR(IntrPCIErr);
                    282:     TRACE_INTR(TimerInt);
                    283:     TRACE_INTR(IntrRxDied);
                    284:     TRACE_INTR(RxNoBuf);
                    285:     TRACE_INTR(IntrRxDone);
                    286:     TRACE_INTR(TxFIFOUnderflow);
                    287:     TRACE_INTR(RxErrIntr);
                    288:     TRACE_INTR(TxIdle);
                    289:     TRACE_INTR(IntrTxStopped);
                    290:     TRACE_INTR(IntrTxDone);
                    291: 
                    292:     printf("\n");
                    293:     /*sleep(1);*/
                    294: }
                    295: #endif
                    296: 
                    297: /**************************************************************************
                    298: w89c840_reset - Reset adapter
                    299: ***************************************************************************/
                    300: static void w89c840_reset(struct nic *nic)
                    301: {
                    302:     int i;
                    303: 
                    304:     /* Reset the chip to erase previous misconfiguration.
                    305:        No hold time required! */
                    306:     writel(0x00000001, ioaddr + PCIBusCfg);
                    307: 
                    308:     init_ring();
                    309: 
                    310:     writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
                    311:     writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);
                    312: 
                    313:     for (i = 0; i < ETH_ALEN; i++)
                    314:         writeb(nic->node_addr[i], ioaddr + StationAddr + i);
                    315: 
                    316:     /* Initialize other registers. */
                    317:     /* Configure the PCI bus bursts and FIFO thresholds.
                    318:        486: Set 8 longword cache alignment, 8 longword burst.
                    319:        586: Set 16 longword cache alignment, no burst limit.
                    320:        Cache alignment bits 15:14         Burst length 13:8
                    321:         0000    <not allowed>         0000 align to cache    0800 8 longwords
                    322:         4000    8  longwords        0100 1 longword        1000 16 longwords
                    323:         8000    16 longwords        0200 2 longwords    2000 32 longwords
                    324:         C000    32  longwords        0400 4 longwords
                    325:        Wait the specified 50 PCI cycles after a reset by initializing
                    326:        Tx and Rx queues and the address filter list. */
                    327: 
                    328:     writel(0xE010, ioaddr + PCIBusCfg);
                    329: 
                    330:     writel(0, ioaddr + RxStartDemand);
                    331:     w840private.csr6 = 0x20022002;
                    332:     check_duplex();
                    333:     set_rx_mode();
                    334: 
                    335:     /* Do not enable the interrupts Etherboot doesn't need them */
                    336: /*
                    337:     writel(0x1A0F5, ioaddr + IntrStatus);
                    338:     writel(0x1A0F5, ioaddr + IntrEnable);
                    339: */
                    340: #if defined(W89C840_DEBUG)
                    341:     printf("winbond-840 : Done reset.\n");
                    342: #endif
                    343: }
                    344: 
                    345: #if 0
                    346: static void handle_intr(u32 intr_stat)
                    347: {
                    348:     if ((intr_stat & (NormalIntr|AbnormalIntr)) == 0) {
                    349:         /* we are polling, do not return now */
                    350:         /*return 0;*/
                    351:     } else {
                    352:         /* Acknowledge all of the current interrupt sources ASAP. */
                    353:         writel(intr_stat & 0x001ffff, ioaddr + IntrStatus);
                    354:     }
                    355: 
                    356:     if (intr_stat & AbnormalIntr) {
                    357:         /* There was an abnormal interrupt */
                    358:         printf("\n-=- Abnormal interrupt.\n");
                    359: 
                    360: #if defined(W89C840_DEBUG)
                    361:         decode_interrupt(intr_stat);
                    362: #endif
                    363: 
                    364:         if (intr_stat & RxNoBuf) {
                    365:             /* There was an interrupt */
                    366:             printf("-=- <=> No receive buffers available.\n");
                    367:             writel(0, ioaddr + RxStartDemand);
                    368:         }
                    369:     }
                    370: }
                    371: #endif
                    372: 
                    373: /**************************************************************************
                    374: w89c840_poll - Wait for a frame
                    375: ***************************************************************************/
                    376: static int w89c840_poll(struct nic *nic, int retrieve)
                    377: {
                    378:     /* return true if there's an ethernet packet ready to read */
                    379:     /* nic->packet should contain data on return */
                    380:     /* nic->packetlen should contain length of data */
                    381:     int packet_received = 0;
                    382: 
                    383: #if defined(W89C840_DEBUG)
                    384:     u32 intr_status = readl(ioaddr + IntrStatus);
                    385: #endif
                    386: 
                    387:     do {
                    388:         /* Code from netdev_rx(dev) */
                    389: 
                    390:         int entry = w840private.cur_rx % RX_RING_SIZE;
                    391: 
                    392:         struct w840_rx_desc *desc = w840private.rx_head_desc;
                    393:         s32 status = desc->status;
                    394: 
                    395:         if (status & DescOwn) {
                    396:             /* DescOwn bit is still set, we should wait for RX to complete */
                    397:             packet_received = 0;
                    398:             break;
                    399:         }
                    400: 
                    401:         if ( !retrieve ) {
                    402:             packet_received = 1;
                    403:             break;
                    404:         }
                    405: 
                    406:         if ((status & 0x38008300) != 0x0300) {
                    407:             if ((status & 0x38000300) != 0x0300) {
                    408:                 /* Ingore earlier buffers. */
                    409:                 if ((status & 0xffff) != 0x7fff) {
                    410:                     printf("winbond-840 : Oversized Ethernet frame spanned "
                    411:                            "multiple buffers, entry %d status %X !\n",
                    412:                            w840private.cur_rx, (unsigned int) status);
                    413:                 }
                    414:             } else if (status & 0x8000) {
                    415:                 /* There was a fatal error. */
                    416: #if defined(W89C840_DEBUG)
                    417:                 printf("winbond-840 : Receive error, Rx status %X :", status);
                    418:                 if (status & 0x0890) {
                    419:                     printf(" RXLEN_ERROR");
                    420:                 }
                    421:                 if (status & 0x004C) {
                    422:                     printf(", FRAME_ERROR");
                    423:                 }
                    424:                 if (status & 0x0002) {
                    425:                     printf(", CRC_ERROR");
                    426:                 }
                    427:                 printf("\n");
                    428: #endif
                    429: 
                    430:                 /* Simpy do a reset now... */
                    431:                 w89c840_reset(nic);
                    432: 
                    433:                 packet_received = 0;
                    434:                 break;
                    435:             }
                    436:         } else {
                    437:             /* Omit the four octet CRC from the length. */
                    438:             int pkt_len = ((status >> 16) & 0x7ff) - 4;
                    439: 
                    440: #if defined(W89C840_DEBUG)
                    441:             printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
                    442: #endif
                    443: 
                    444:             nic->packetlen = pkt_len;
                    445: 
                    446:             /* Check if the packet is long enough to accept without copying
                    447:                to a minimally-sized skbuff. */
                    448: 
                    449:             memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
                    450:             packet_received = 1;
                    451: 
                    452:             /* Release buffer to NIC */
                    453:             w840private.rx_ring[entry].status = DescOwn;
                    454: 
                    455: #if defined(W89C840_DEBUG)
                    456:             /* You will want this info for the initial debug. */
                    457:             printf("  Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
                    458:                    "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
                    459:                    "%hhX.%hhX.%hhX.%hhX.\n",
                    460:                    nic->packet[0],  nic->packet[1],  nic->packet[2], nic->packet[3],
                    461:                    nic->packet[4],  nic->packet[5],  nic->packet[6], nic->packet[7],
                    462:                    nic->packet[8],  nic->packet[9],  nic->packet[10],
                    463:                    nic->packet[11], nic->packet[12], nic->packet[13],
                    464:                    nic->packet[14], nic->packet[15], nic->packet[16],
                    465:                    nic->packet[17]);
                    466: #endif
                    467: 
                    468:         }
                    469: 
                    470:         entry = (++w840private.cur_rx) % RX_RING_SIZE;
                    471:         w840private.rx_head_desc = &w840private.rx_ring[entry];
                    472:     } while (0);
                    473:     
                    474:     return packet_received;
                    475: }
                    476: 
                    477: /**************************************************************************
                    478: w89c840_transmit - Transmit a frame
                    479: ***************************************************************************/
                    480: 
                    481: static void w89c840_transmit(
                    482:     struct nic *nic,
                    483:     const char *d,            /* Destination */
                    484:     unsigned int t,            /* Type */
                    485:     unsigned int s,            /* size */
                    486:     const char *p)            /* Packet */
                    487: {
                    488:     /* send the packet to destination */
                    489:     unsigned entry;
                    490:     int transmit_status;
                    491:     unsigned long ct;
                    492: 
                    493:     /* Caution: the write order is important here, set the field
                    494:        with the "ownership" bits last. */
                    495: 
                    496:     /* Fill in our transmit buffer */
                    497:     entry = w840private.cur_tx % TX_RING_SIZE;
                    498: 
                    499:     memcpy (w89c840_buf.tx_packet, d, ETH_ALEN);    /* dst */
                    500:     memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/*src*/
                    501: 
                    502:     *((char *) w89c840_buf.tx_packet + 12) = t >> 8;    /* type */
                    503:     *((char *) w89c840_buf.tx_packet + 13) = t;
                    504: 
                    505:     memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s);
                    506:     s += ETH_HLEN;
                    507: 
                    508:     while (s < ETH_ZLEN)
                    509:     *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0;
                    510: 
                    511:     w840private.tx_ring[entry].buffer1
                    512:            = virt_to_le32desc(w89c840_buf.tx_packet);
                    513: 
                    514:     w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
                    515:     if (entry >= TX_RING_SIZE-1)         /* Wrap ring */
                    516:         w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
                    517:     w840private.tx_ring[entry].status = (DescOwn);
                    518:     w840private.cur_tx++;
                    519: 
                    520:     w840private.tx_q_bytes = (u16) s;
                    521:     writel(0, ioaddr + TxStartDemand);
                    522: 
                    523:     /* Work around horrible bug in the chip by marking the queue as full
                    524:        when we do not have FIFO room for a maximum sized packet. */
                    525: 
                    526:     if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
                    527:         /* Actually this is left to help finding error tails later in debugging...
                    528:          * See Linux kernel driver in winbond-840.c for details.
                    529:          */
                    530:         w840private.tx_full = 1;
                    531:     }
                    532: 
                    533: #if defined(W89C840_DEBUG)
                    534:     printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
                    535: #endif
                    536: 
                    537:     /* Now wait for TX to complete. */
                    538:     transmit_status = w840private.tx_ring[entry].status;
                    539: 
                    540:     ct = currticks();
                    541:     {
                    542: #if defined W89C840_DEBUG
                    543:         u32 intr_stat = 0;
                    544: #endif
                    545:         while (1) {
                    546: 
                    547: #if defined(W89C840_DEBUG)
                    548:              decode_interrupt(intr_stat);
                    549: #endif
                    550: 
                    551:                 while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) {
                    552: 
                    553:                     transmit_status = w840private.tx_ring[entry].status;
                    554:                 }
                    555: 
                    556:                 break;
                    557:         }
                    558:     }
                    559: 
                    560:     if ((transmit_status & DescOwn) == 0) {
                    561: 
                    562: #if defined(W89C840_DEBUG)
                    563:         printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
                    564:                 w840private.tx_ring[entry].status);
                    565: #endif
                    566: 
                    567:         return;
                    568:     }
                    569: 
                    570:     /* Transmit timed out... */
                    571: 
                    572:     printf("winbond-840 : transmission TIMEOUT : status %X\n", 
                    573:           (unsigned int) w840private.tx_ring[entry].status);
                    574: 
                    575:     return;
                    576: }
                    577: 
                    578: /**************************************************************************
                    579: w89c840_disable - Turn off ethernet interface
                    580: ***************************************************************************/
                    581: static void w89c840_disable ( struct nic *nic ) {
                    582: 
                    583:     w89c840_reset(nic);
                    584: 
                    585:     /* Don't know what to do to disable the board. Is this needed at all? */
                    586:     /* Yes, a live NIC can corrupt the loaded memory later [Ken] */
                    587:     /* Stop the chip's Tx and Rx processes. */
                    588:     writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
                    589: }
                    590: 
                    591: /**************************************************************************
                    592: w89c840_irq - Enable, Disable, or Force interrupts
                    593: ***************************************************************************/
                    594: static void w89c840_irq(struct nic *nic __unused, irq_action_t action __unused)
                    595: {
                    596:   switch ( action ) {
                    597:   case DISABLE :
                    598:     break;
                    599:   case ENABLE :
                    600:     break;
                    601:   case FORCE :
                    602:     break;
                    603:   }
                    604: }
                    605: 
                    606: static struct nic_operations w89c840_operations = {
                    607:        .connect        = dummy_connect,
                    608:        .poll           = w89c840_poll,
                    609:        .transmit       = w89c840_transmit,
                    610:        .irq            = w89c840_irq,
                    611: 
                    612: };
                    613: 
                    614: static struct pci_device_id w89c840_nics[] = {
                    615: PCI_ROM(0x1050, 0x0840, "winbond840",     "Winbond W89C840F", 0),
                    616: PCI_ROM(0x11f6, 0x2011, "compexrl100atx", "Compex RL100ATX", 0),
                    617: };
                    618: 
                    619: PCI_DRIVER ( w89c840_driver, w89c840_nics, PCI_NO_CLASS );
                    620: 
                    621: /**************************************************************************
                    622: w89c840_probe - Look for an adapter, this routine's visible to the outside
                    623: ***************************************************************************/
                    624: static int w89c840_probe ( struct nic *nic, struct pci_device *p ) {
                    625: 
                    626: 
                    627:     u16 sum = 0;
                    628:     int i;
                    629:     unsigned short value;
                    630: 
                    631:     if (p->ioaddr == 0)
                    632:         return 0;
                    633: 
                    634:     nic->ioaddr = p->ioaddr;
                    635:     nic->irqno  = 0;
                    636: 
                    637: #if defined(W89C840_DEBUG)
                    638:     printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
                    639: #endif
                    640: 
                    641:     ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
                    642: 
                    643: #define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
                    644: #define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011
                    645: 
                    646:     /* From Matt Hortman <[email protected]> */
                    647:     if (p->vendor == PCI_VENDOR_ID_WINBOND2
                    648:         && p->device == PCI_DEVICE_ID_WINBOND2_89C840) {
                    649: 
                    650:         /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */
                    651: 
                    652:     } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
                    653:                 && p->device == PCI_DEVICE_ID_COMPEX_RL100ATX) {
                    654: 
                    655:         /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */
                    656: 
                    657:     } else {
                    658:         /* Gee, guess what? They missed again. */
                    659:         printf("device ID : %X - is not a Compex RL100ATX NIC.\n",
                    660:               p->device);
                    661:         return 0;
                    662:     }
                    663: 
                    664:     printf(" %s\n", w89c840_version);
                    665: 
                    666:     adjust_pci_device(p);
                    667: 
                    668:     /* Ok. Got one. Read the eeprom. */
                    669:     for (i = 0; i < 0x40; i++) {
                    670:         value = eeprom_read(ioaddr, i);
                    671:         eeprom[i] = value;
                    672:         sum += value;
                    673:     }
                    674: 
                    675:     for (i=0;i<ETH_ALEN;i++) {
                    676:         nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;
                    677:     }
                    678: 
                    679:     DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
                    680: 
                    681: #if defined(W89C840_DEBUG)
                    682:     printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
                    683: #endif
                    684: 
                    685:     /* Reset the chip to erase previous misconfiguration.
                    686:        No hold time required! */
                    687:     writel(0x00000001, ioaddr + PCIBusCfg);
                    688: 
                    689:     if (driver_flags & CanHaveMII) {
                    690:         int phy, phy_idx = 0;
                    691:         for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
                    692:             int mii_status = mdio_read(ioaddr, phy, 1);
                    693:             if (mii_status != 0xffff  &&  mii_status != 0x0000) {
                    694:                 w840private.phys[phy_idx++] = phy;
                    695:                 w840private.advertising = mdio_read(ioaddr, phy, 4);
                    696: 
                    697: #if defined(W89C840_DEBUG)
                    698:                 printf("winbond-840 : MII PHY found at address %d, status "
                    699:                        "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
                    700: #endif
                    701: 
                    702:             }
                    703:         }
                    704: 
                    705:         w840private.mii_cnt = phy_idx;
                    706: 
                    707:         if (phy_idx == 0) {
                    708:                 printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
                    709:         }
                    710:     }
                    711: 
                    712:     /* point to NIC specific routines */
                    713:     nic->nic_op        = &w89c840_operations;
                    714: 
                    715:     w89c840_reset(nic);
                    716: 
                    717:     return 1;
                    718: }
                    719: 
                    720: /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are
                    721:    often serial bit streams generated by the host processor.
                    722:    The example below is for the common 93c46 EEPROM, 64 16 bit words. */
                    723: 
                    724: /* Delay between EEPROM clock transitions.
                    725:    No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
                    726:    a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
                    727:    made udelay() unreliable.
                    728:    The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
                    729:    depricated.
                    730: */
                    731: #define eeprom_delay(ee_addr)    readl(ee_addr)
                    732: 
                    733: enum EEPROM_Ctrl_Bits {
                    734:     EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
                    735:     EE_ChipSelect=0x801, EE_DataIn=0x08,
                    736: };
                    737: 
                    738: /* The EEPROM commands include the alway-set leading bit. */
                    739: enum EEPROM_Cmds {
                    740:     EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
                    741: };
                    742: 
                    743: static int eeprom_read(long addr, int location)
                    744: {
                    745:     int i;
                    746:     int retval = 0;
                    747:     int ee_addr = addr + EECtrl;
                    748:     int read_cmd = location | EE_ReadCmd;
                    749:     writel(EE_ChipSelect, ee_addr);
                    750: 
                    751:     /* Shift the read command bits out. */
                    752:     for (i = 10; i >= 0; i--) {
                    753:         short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
                    754:         writel(dataval, ee_addr);
                    755:         eeprom_delay(ee_addr);
                    756:         writel(dataval | EE_ShiftClk, ee_addr);
                    757:         eeprom_delay(ee_addr);
                    758:     }
                    759:     writel(EE_ChipSelect, ee_addr);
                    760: 
                    761:     for (i = 16; i > 0; i--) {
                    762:         writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
                    763:         eeprom_delay(ee_addr);
                    764:         retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
                    765:         writel(EE_ChipSelect, ee_addr);
                    766:         eeprom_delay(ee_addr);
                    767:     }
                    768: 
                    769:     /* Terminate the EEPROM access. */
                    770:     writel(0, ee_addr);
                    771:     return retval;
                    772: }
                    773: 
                    774: /*  MII transceiver control section.
                    775:     Read and write the MII registers using software-generated serial
                    776:     MDIO protocol.  See the MII specifications or DP83840A data sheet
                    777:     for details.
                    778: 
                    779:     The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
                    780:     met by back-to-back 33Mhz PCI cycles. */
                    781: #define mdio_delay(mdio_addr) readl(mdio_addr)
                    782: 
                    783: /* Set iff a MII transceiver on any interface requires mdio preamble.
                    784:    This only set with older tranceivers, so the extra
                    785:    code size of a per-interface flag is not worthwhile. */
                    786: static char mii_preamble_required = 1;
                    787: 
                    788: #define MDIO_WRITE0 (MDIO_EnbOutput)
                    789: #define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
                    790: 
                    791: /* Generate the preamble required for initial synchronization and
                    792:    a few older transceivers. */
                    793: static void mdio_sync(long mdio_addr)
                    794: {
                    795:     int bits = 32;
                    796: 
                    797:     /* Establish sync by sending at least 32 logic ones. */
                    798:     while (--bits >= 0) {
                    799:         writel(MDIO_WRITE1, mdio_addr);
                    800:         mdio_delay(mdio_addr);
                    801:         writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
                    802:         mdio_delay(mdio_addr);
                    803:     }
                    804: }
                    805: 
                    806: static int mdio_read(int base_address, int phy_id, int location)
                    807: {
                    808:     long mdio_addr = base_address + MIICtrl;
                    809:     int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
                    810:     int i, retval = 0;
                    811: 
                    812:     if (mii_preamble_required)
                    813:         mdio_sync(mdio_addr);
                    814: 
                    815:     /* Shift the read command bits out. */
                    816:     for (i = 15; i >= 0; i--) {
                    817:         int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
                    818: 
                    819:         writel(dataval, mdio_addr);
                    820:         mdio_delay(mdio_addr);
                    821:         writel(dataval | MDIO_ShiftClk, mdio_addr);
                    822:         mdio_delay(mdio_addr);
                    823:     }
                    824:     /* Read the two transition, 16 data, and wire-idle bits. */
                    825:     for (i = 20; i > 0; i--) {
                    826:         writel(MDIO_EnbIn, mdio_addr);
                    827:         mdio_delay(mdio_addr);
                    828:         retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
                    829:         writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
                    830:         mdio_delay(mdio_addr);
                    831:     }
                    832:     return (retval>>1) & 0xffff;
                    833: }
                    834: 
                    835: #if 0
                    836: static void mdio_write(int base_address, int phy_id, int location, int value)
                    837: {
                    838:     long mdio_addr = base_address + MIICtrl;
                    839:     int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
                    840:     int i;
                    841: 
                    842:     if (location == 4  &&  phy_id == w840private.phys[0])
                    843:         w840private.advertising = value;
                    844: 
                    845:     if (mii_preamble_required)
                    846:         mdio_sync(mdio_addr);
                    847: 
                    848:     /* Shift the command bits out. */
                    849:     for (i = 31; i >= 0; i--) {
                    850:         int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
                    851: 
                    852:         writel(dataval, mdio_addr);
                    853:         mdio_delay(mdio_addr);
                    854:         writel(dataval | MDIO_ShiftClk, mdio_addr);
                    855:         mdio_delay(mdio_addr);
                    856:     }
                    857:     /* Clear out extra bits. */
                    858:     for (i = 2; i > 0; i--) {
                    859:         writel(MDIO_EnbIn, mdio_addr);
                    860:         mdio_delay(mdio_addr);
                    861:         writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
                    862:         mdio_delay(mdio_addr);
                    863:     }
                    864:     return;
                    865: }
                    866: #endif
                    867: 
                    868: static void check_duplex(void)
                    869: {
                    870:     int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
                    871:     int negotiated =  mii_reg5 & w840private.advertising;
                    872:     int duplex;
                    873: 
                    874:     if (w840private.duplex_lock  ||  mii_reg5 == 0xffff)
                    875:         return;
                    876: 
                    877:     duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
                    878:     if (w840private.full_duplex != duplex) {
                    879:         w840private.full_duplex = duplex;       
                    880: 
                    881: #if defined(W89C840_DEBUG)
                    882:         printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
                    883:                duplex ? "full" : "half", w840private.phys[0], negotiated);
                    884: #endif
                    885: 
                    886:         w840private.csr6 &= ~0x200;
                    887:         w840private.csr6 |= duplex ? 0x200 : 0;
                    888:     }
                    889: }
                    890: 
                    891: static void set_rx_mode(void)
                    892: {
                    893:     u32 mc_filter[2];            /* Multicast hash filter */
                    894:     u32 rx_mode;
                    895: 
                    896:     /* Accept all multicasts from now on. */
                    897:     memset(mc_filter, 0xff, sizeof(mc_filter));
                    898: 
                    899: /*
                    900:  * works OK with multicast enabled. 
                    901:  */
                    902: 
                    903:     rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
                    904: 
                    905:     writel(mc_filter[0], ioaddr + MulticastFilter0);
                    906:     writel(mc_filter[1], ioaddr + MulticastFilter1);
                    907:     w840private.csr6 &= ~0x00F8;
                    908:     w840private.csr6 |= rx_mode;
                    909:     writel(w840private.csr6, ioaddr + NetworkConfig);
                    910: 
                    911: #if defined(W89C840_DEBUG)
                    912:     printf("winbond-840 : Done setting RX mode.\n");
                    913: #endif
                    914: }
                    915: 
                    916: /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
                    917: static void init_ring(void)
                    918: {
                    919:     int i;
                    920:     char * p;
                    921: 
                    922:     w840private.tx_full = 0;
                    923:     w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
                    924:     w840private.dirty_rx = w840private.dirty_tx = 0;
                    925: 
                    926:     w840private.rx_buf_sz = PKT_BUF_SZ;
                    927:     w840private.rx_head_desc = &w840private.rx_ring[0];
                    928: 
                    929:     /* Initial all Rx descriptors. Fill in the Rx buffers. */
                    930: 
                    931:     p = &w89c840_buf.rx_packet[0];
                    932: 
                    933:     for (i = 0; i < RX_RING_SIZE; i++) {
                    934:         w840private.rx_ring[i].length = w840private.rx_buf_sz;
                    935:         w840private.rx_ring[i].status = 0;
                    936:         w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);
                    937: 
                    938:         w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
                    939:         w840private.rx_ring[i].status = DescOwn | DescIntr;
                    940:     }
                    941: 
                    942:     /* Mark the last entry as wrapping the ring. */
                    943:     w840private.rx_ring[i-1].length |= DescEndRing;
                    944:     w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);
                    945: 
                    946:     w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);
                    947: 
                    948:     for (i = 0; i < TX_RING_SIZE; i++) {
                    949:         w840private.tx_ring[i].status = 0;
                    950:     }
                    951:     return;
                    952: }
                    953: 
                    954: 
                    955: DRIVER ( "W89C840F", nic_driver, pci_driver, w89c840_driver,
                    956:         w89c840_probe, w89c840_disable );
                    957: 
                    958: /*
                    959:  * Local variables:
                    960:  *  c-basic-offset: 8
                    961:  *  c-indent-level: 8
                    962:  *  tab-width: 8
                    963:  * End:
                    964:  */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.