iPXE
w89c840.c
Go to the documentation of this file.
00001 /*
00002  * Etherboot -  BOOTP/TFTP Bootstrap Program
00003  *
00004  * w89c840.c -- This file implements the winbond-840 driver for etherboot.
00005  *
00006  */
00007 
00008 /*
00009  * Adapted by Igor V. Kovalenko
00010  *  -- <garrison@mail.ru>
00011  *   OR
00012  *  -- <iko@crec.mipt.ru>
00013  * Initial adaptaion stage, including testing, completed 23 August 2000.
00014  */
00015 
00016 /*
00017  * This program is free software; you can redistribute it and/or
00018  * modify it under the terms of the GNU General Public License as
00019  * published by the Free Software Foundation; either version 2, or (at
00020  * your option) any later version.
00021  *
00022  * This program is distributed in the hope that it will be useful, but
00023  * WITHOUT ANY WARRANTY; without even the implied warranty of
00024  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025  * General Public License for more details.
00026  *
00027  * You should have received a copy of the GNU General Public License
00028  * along with this program; if not, write to the Free Software
00029  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00030  * 02110-1301, USA.
00031  */
00032 
00033 FILE_LICENCE ( GPL2_OR_LATER );
00034 
00035 /*
00036  *              date       version  by   what
00037  *  Written:    Aug 20 2000  V0.10  iko  Initial revision.
00038  * changes:     Aug 22 2000  V0.90  iko  Works!
00039  *              Aug 23 2000  V0.91  iko  Cleanup, posted to etherboot
00040  *                                       maintainer.
00041  *              Aug 26 2000  V0.92  iko  Fixed Rx ring handling.
00042  *                                       First Linux Kernel (TM)
00043  *                                       successfully loaded using
00044  *                                       this driver.
00045  *              Jan 07 2001  V0.93  iko  Transmitter timeouts are handled
00046  *                                       using timer2 routines. Proposed
00047  *                                       by Ken Yap to eliminate CPU speed
00048  *                                       dependency.
00049  *             Dec 12 2003  V0.94   timlegge    Fixed issues in 5.2, removed 
00050  *                                              interrupt usage, enabled
00051  *                                              multicast support
00052  *
00053  * This is the etherboot driver for cards based on Winbond W89c840F chip.
00054  *
00055  * It was written from skeleton source, with Donald Becker's winbond-840.c
00056  * kernel driver as a guideline. Mostly the w89c840 related definitions
00057  * and the lower level routines have been cut-and-pasted into this source.
00058  *
00059  * Frankly speaking, about 90% of the code was obtained using cut'n'paste
00060  * sequence :) while the remainder appeared while brainstorming
00061  * Linux Kernel 2.4.0-testX source code. Thanks, Donald and Linus!
00062  *
00063  * There was a demand for using this card in a rather large
00064  * remote boot environment at MSKP OVTI Lab of
00065  * Moscow Institute for Physics and Technology (MIPT) -- http://www.mipt.ru/
00066  * so you may count that for motivation.
00067  *
00068  */
00069 
00070 /*
00071  * If you want to see debugging output then define W89C840_DEBUG
00072  */
00073 
00074 /*
00075 #define W89C840_DEBUG
00076 */
00077 
00078 /*
00079  * Keep using IO_OPS for Etherboot driver!
00080  */
00081 #define USE_IO_OPS
00082 
00083 #include "etherboot.h"
00084 #include "nic.h"
00085 #include <ipxe/pci.h>
00086 #include <ipxe/ethernet.h>
00087 
00088 static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
00089 
00090 /* Linux support functions */
00091 #define virt_to_le32desc(addr)  virt_to_bus(addr)
00092 #define le32desc_to_virt(addr)  bus_to_virt(addr)
00093 
00094 /*
00095 #define cpu_to_le32(val) (val)
00096 #define le32_to_cpu(val) (val)
00097 */
00098 
00099 /* Operational parameters that are set at compile time. */
00100 
00101 /* Keep the ring sizes a power of two for compile efficiency.
00102    The compiler will convert <unsigned>'%'<2^N> into a bit mask.
00103    Making the Tx ring too large decreases the effectiveness of channel
00104    bonding and packet priority.
00105    There are no ill effects from too-large receive rings. */
00106 #define TX_RING_SIZE    2
00107 #define RX_RING_SIZE    2
00108 
00109 /* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
00110    To avoid overflowing we don't queue again until we have room for a
00111    full-size packet.
00112  */
00113 #define TX_FIFO_SIZE (2048)
00114 #define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
00115 
00116 /* Operational parameters that usually are not changed. */
00117 /* Time in jiffies before concluding the transmitter is hung. */
00118 #define TX_TIMEOUT  (10*1000)
00119 
00120 #define PKT_BUF_SZ  1536  /* Size of each temporary Rx buffer.*/
00121 
00122 /*
00123  * Used to be this much CPU loops on Celeron@400 (?),
00124  * now using real timer and TX_TIMEOUT!
00125  * #define TX_LOOP_COUNT 10000000
00126  */
00127 
00128 #if !defined(__OPTIMIZE__)
00129 #warning  You must compile this file with the correct options!
00130 #warning  See the last lines of the source file.
00131 #error You must compile this driver with "-O".
00132 #endif
00133 
00134 enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2};
00135 
00136 #ifdef USE_IO_OPS
00137 #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
00138 #else
00139 #define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
00140 #endif
00141 
00142 static u32 driver_flags = CanHaveMII | HasBrokenTx;
00143 
00144 /* This driver was written to use PCI memory space, however some x86 systems
00145    work only with I/O space accesses.  Pass -DUSE_IO_OPS to use PCI I/O space
00146    accesses instead of memory space. */
00147 
00148 #ifdef USE_IO_OPS
00149 #undef readb
00150 #undef readw
00151 #undef readl
00152 #undef writeb
00153 #undef writew
00154 #undef writel
00155 #define readb inb
00156 #define readw inw
00157 #define readl inl
00158 #define writeb outb
00159 #define writew outw
00160 #define writel outl
00161 #endif
00162 
00163 /* Offsets to the Command and Status Registers, "CSRs".
00164    While similar to the Tulip, these registers are longword aligned.
00165    Note: It's not useful to define symbolic names for every register bit in
00166    the device.  The name can only partially document the semantics and make
00167    the driver longer and more difficult to read.
00168 */
00169 enum w840_offsets {
00170     PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
00171     RxRingPtr=0x0C, TxRingPtr=0x10,
00172     IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
00173     RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
00174     CurRxDescAddr=0x30, CurRxBufAddr=0x34,            /* Debug use */
00175     MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
00176     CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
00177 };
00178 
00179 /* Bits in the interrupt status/enable registers. */
00180 /* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
00181 enum intr_status_bits {
00182     NormalIntr=0x10000, AbnormalIntr=0x8000,
00183     IntrPCIErr=0x2000, TimerInt=0x800,
00184     IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
00185     TxFIFOUnderflow=0x20, RxErrIntr=0x10,
00186     TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
00187 };
00188 
00189 /* Bits in the NetworkConfig register. */
00190 enum rx_mode_bits {
00191     AcceptErr=0x80, AcceptRunt=0x40,
00192     AcceptBroadcast=0x20, AcceptMulticast=0x10,
00193     AcceptAllPhys=0x08, AcceptMyPhys=0x02,
00194 };
00195 
00196 enum mii_reg_bits {
00197     MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
00198     MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
00199 };
00200 
00201 /* The Tulip Rx and Tx buffer descriptors. */
00202 struct w840_rx_desc {
00203     s32 status;
00204     s32 length;
00205     u32 buffer1;
00206     u32 next_desc;
00207 };
00208 
00209 struct w840_tx_desc {
00210     s32 status;
00211     s32 length;
00212     u32 buffer1, buffer2;                /* We use only buffer 1.  */
00213 };
00214 
00215 /* Bits in network_desc.status */
00216 enum desc_status_bits {
00217     DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
00218     DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
00219     DescIntr=0x80000000,
00220 };
00221 #define PRIV_ALIGN    15     /* Required alignment mask */
00222 #define PRIV_ALIGN_BYTES 32
00223 
00224 static struct winbond_private
00225 {
00226     /* Descriptor rings first for alignment. */
00227     struct w840_rx_desc rx_ring[RX_RING_SIZE];
00228     struct w840_tx_desc tx_ring[TX_RING_SIZE];
00229     struct net_device *next_module;        /* Link for devices of this type. */
00230     void *priv_addr;                    /* Unaligned address for kfree */
00231     const char *product_name;
00232     /* Frequently used values: keep some adjacent for cache effect. */
00233     int chip_id, drv_flags;
00234     struct pci_dev *pci_dev;
00235     int csr6;
00236     struct w840_rx_desc *rx_head_desc;
00237     unsigned int cur_rx, dirty_rx;        /* Producer/consumer ring indices */
00238     unsigned int rx_buf_sz;                /* Based on MTU+slack. */
00239     unsigned int cur_tx, dirty_tx;
00240     int tx_q_bytes;
00241     unsigned int tx_full:1;                /* The Tx queue is full. */
00242     /* These values are keep track of the transceiver/media in use. */
00243     unsigned int full_duplex:1;            /* Full-duplex operation requested. */
00244     unsigned int duplex_lock:1;
00245     unsigned int medialock:1;            /* Do not sense media. */
00246     unsigned int default_port:4;        /* Last dev->if_port value. */
00247     /* MII transceiver section. */
00248     int mii_cnt;                        /* MII device addresses. */
00249     u16 advertising;                    /* NWay media advertisement */
00250     unsigned char phys[4];                /* MII device addresses. */
00251 } w840private __attribute__ ((aligned (PRIV_ALIGN_BYTES)));
00252 
00253 /* NIC specific static variables go here */
00254 
00255 static int ioaddr;
00256 static unsigned short eeprom [0x40];
00257 struct {
00258         char        rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
00259         char        tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
00260 } w89c840_buf __shared;
00261 
00262 static int  eeprom_read(long ioaddr, int location);
00263 static int  mdio_read(int base_address, int phy_id, int location);
00264 #if 0
00265 static void mdio_write(int base_address, int phy_id, int location, int value);
00266 #endif
00267 
00268 static void check_duplex(void);
00269 static void set_rx_mode(void);
00270 static void init_ring(void);
00271 
00272 #if defined(W89C840_DEBUG)
00273 static void decode_interrupt(u32 intr_status)
00274 {
00275     printf("Interrupt status: ");
00276 
00277 #define TRACE_INTR(_intr_) \
00278     if (intr_status & (_intr_)) { printf (" " #_intr_); }
00279 
00280     TRACE_INTR(NormalIntr);
00281     TRACE_INTR(AbnormalIntr);
00282     TRACE_INTR(IntrPCIErr);
00283     TRACE_INTR(TimerInt);
00284     TRACE_INTR(IntrRxDied);
00285     TRACE_INTR(RxNoBuf);
00286     TRACE_INTR(IntrRxDone);
00287     TRACE_INTR(TxFIFOUnderflow);
00288     TRACE_INTR(RxErrIntr);
00289     TRACE_INTR(TxIdle);
00290     TRACE_INTR(IntrTxStopped);
00291     TRACE_INTR(IntrTxDone);
00292 
00293     printf("\n");
00294     /*sleep(1);*/
00295 }
00296 #endif
00297 
00298 /**************************************************************************
00299 w89c840_reset - Reset adapter
00300 ***************************************************************************/
00301 static void w89c840_reset(struct nic *nic)
00302 {
00303     int i;
00304 
00305     /* Reset the chip to erase previous misconfiguration.
00306        No hold time required! */
00307     writel(0x00000001, ioaddr + PCIBusCfg);
00308 
00309     init_ring();
00310 
00311     writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
00312     writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);
00313 
00314     for (i = 0; i < ETH_ALEN; i++)
00315         writeb(nic->node_addr[i], ioaddr + StationAddr + i);
00316 
00317     /* Initialize other registers. */
00318     /* Configure the PCI bus bursts and FIFO thresholds.
00319        486: Set 8 longword cache alignment, 8 longword burst.
00320        586: Set 16 longword cache alignment, no burst limit.
00321        Cache alignment bits 15:14         Burst length 13:8
00322         0000    <not allowed>         0000 align to cache    0800 8 longwords
00323         4000    8  longwords        0100 1 longword        1000 16 longwords
00324         8000    16 longwords        0200 2 longwords    2000 32 longwords
00325         C000    32  longwords        0400 4 longwords
00326        Wait the specified 50 PCI cycles after a reset by initializing
00327        Tx and Rx queues and the address filter list. */
00328 
00329     writel(0xE010, ioaddr + PCIBusCfg);
00330 
00331     writel(0, ioaddr + RxStartDemand);
00332     w840private.csr6 = 0x20022002;
00333     check_duplex();
00334     set_rx_mode();
00335 
00336     /* Do not enable the interrupts Etherboot doesn't need them */
00337 /*
00338     writel(0x1A0F5, ioaddr + IntrStatus);
00339     writel(0x1A0F5, ioaddr + IntrEnable);
00340 */
00341 #if defined(W89C840_DEBUG)
00342     printf("winbond-840 : Done reset.\n");
00343 #endif
00344 }
00345 
00346 #if 0
00347 static void handle_intr(u32 intr_stat)
00348 {
00349     if ((intr_stat & (NormalIntr|AbnormalIntr)) == 0) {
00350         /* we are polling, do not return now */
00351         /*return 0;*/
00352     } else {
00353         /* Acknowledge all of the current interrupt sources ASAP. */
00354         writel(intr_stat & 0x001ffff, ioaddr + IntrStatus);
00355     }
00356 
00357     if (intr_stat & AbnormalIntr) {
00358         /* There was an abnormal interrupt */
00359         printf("\n-=- Abnormal interrupt.\n");
00360 
00361 #if defined(W89C840_DEBUG)
00362         decode_interrupt(intr_stat);
00363 #endif
00364 
00365         if (intr_stat & RxNoBuf) {
00366             /* There was an interrupt */
00367             printf("-=- <=> No receive buffers available.\n");
00368             writel(0, ioaddr + RxStartDemand);
00369         }
00370     }
00371 }
00372 #endif
00373 
00374 /**************************************************************************
00375 w89c840_poll - Wait for a frame
00376 ***************************************************************************/
00377 static int w89c840_poll(struct nic *nic, int retrieve)
00378 {
00379     /* return true if there's an ethernet packet ready to read */
00380     /* nic->packet should contain data on return */
00381     /* nic->packetlen should contain length of data */
00382     int packet_received = 0;
00383 
00384 #if defined(W89C840_DEBUG)
00385     u32 intr_status = readl(ioaddr + IntrStatus);
00386 #endif
00387 
00388     do {
00389         /* Code from netdev_rx(dev) */
00390 
00391         int entry = w840private.cur_rx % RX_RING_SIZE;
00392 
00393         struct w840_rx_desc *desc = w840private.rx_head_desc;
00394         s32 status = desc->status;
00395 
00396         if (status & DescOwn) {
00397             /* DescOwn bit is still set, we should wait for RX to complete */
00398             packet_received = 0;
00399             break;
00400         }
00401 
00402         if ( !retrieve ) {
00403             packet_received = 1;
00404             break;
00405         }
00406 
00407         if ((status & 0x38008300) != 0x0300) {
00408             if ((status & 0x38000300) != 0x0300) {
00409                 /* Ingore earlier buffers. */
00410                 if ((status & 0xffff) != 0x7fff) {
00411                     printf("winbond-840 : Oversized Ethernet frame spanned "
00412                            "multiple buffers, entry %d status %X !\n",
00413                            w840private.cur_rx, (unsigned int) status);
00414                 }
00415             } else if (status & 0x8000) {
00416                 /* There was a fatal error. */
00417 #if defined(W89C840_DEBUG)
00418                 printf("winbond-840 : Receive error, Rx status %X :", status);
00419                 if (status & 0x0890) {
00420                     printf(" RXLEN_ERROR");
00421                 }
00422                 if (status & 0x004C) {
00423                     printf(", FRAME_ERROR");
00424                 }
00425                 if (status & 0x0002) {
00426                     printf(", CRC_ERROR");
00427                 }
00428                 printf("\n");
00429 #endif
00430 
00431                 /* Simpy do a reset now... */
00432                 w89c840_reset(nic);
00433 
00434                 packet_received = 0;
00435                 break;
00436             }
00437         } else {
00438             /* Omit the four octet CRC from the length. */
00439             int pkt_len = ((status >> 16) & 0x7ff) - 4;
00440 
00441 #if defined(W89C840_DEBUG)
00442             printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
00443 #endif
00444 
00445             nic->packetlen = pkt_len;
00446 
00447             /* Check if the packet is long enough to accept without copying
00448                to a minimally-sized skbuff. */
00449 
00450             memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
00451             packet_received = 1;
00452 
00453             /* Release buffer to NIC */
00454             w840private.rx_ring[entry].status = DescOwn;
00455 
00456 #if defined(W89C840_DEBUG)
00457             /* You will want this info for the initial debug. */
00458             printf("  Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
00459                    "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
00460                    "%hhX.%hhX.%hhX.%hhX.\n",
00461                    nic->packet[0],  nic->packet[1],  nic->packet[2], nic->packet[3],
00462                    nic->packet[4],  nic->packet[5],  nic->packet[6], nic->packet[7],
00463                    nic->packet[8],  nic->packet[9],  nic->packet[10],
00464                    nic->packet[11], nic->packet[12], nic->packet[13],
00465                    nic->packet[14], nic->packet[15], nic->packet[16],
00466                    nic->packet[17]);
00467 #endif
00468 
00469         }
00470 
00471         entry = (++w840private.cur_rx) % RX_RING_SIZE;
00472         w840private.rx_head_desc = &w840private.rx_ring[entry];
00473     } while (0);
00474     
00475     return packet_received;
00476 }
00477 
00478 /**************************************************************************
00479 w89c840_transmit - Transmit a frame
00480 ***************************************************************************/
00481 
00482 static void w89c840_transmit(
00483     struct nic *nic,
00484     const char *d,            /* Destination */
00485     unsigned int t,            /* Type */
00486     unsigned int s,            /* size */
00487     const char *p)            /* Packet */
00488 {
00489     /* send the packet to destination */
00490     unsigned entry;
00491     int transmit_status;
00492     unsigned long ct;
00493 
00494     /* Caution: the write order is important here, set the field
00495        with the "ownership" bits last. */
00496 
00497     /* Fill in our transmit buffer */
00498     entry = w840private.cur_tx % TX_RING_SIZE;
00499 
00500     memcpy (w89c840_buf.tx_packet, d, ETH_ALEN);    /* dst */
00501     memcpy (w89c840_buf.tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/*src*/
00502 
00503     *((char *) w89c840_buf.tx_packet + 12) = t >> 8;    /* type */
00504     *((char *) w89c840_buf.tx_packet + 13) = t;
00505 
00506     memcpy (w89c840_buf.tx_packet + ETH_HLEN, p, s);
00507     s += ETH_HLEN;
00508 
00509     while (s < ETH_ZLEN)
00510     *((char *) w89c840_buf.tx_packet + ETH_HLEN + (s++)) = 0;
00511 
00512     w840private.tx_ring[entry].buffer1
00513             = virt_to_le32desc(w89c840_buf.tx_packet);
00514 
00515     w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
00516     if (entry >= TX_RING_SIZE-1)         /* Wrap ring */
00517         w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
00518     w840private.tx_ring[entry].status = (DescOwn);
00519     w840private.cur_tx++;
00520 
00521     w840private.tx_q_bytes = (u16) s;
00522     writel(0, ioaddr + TxStartDemand);
00523 
00524     /* Work around horrible bug in the chip by marking the queue as full
00525        when we do not have FIFO room for a maximum sized packet. */
00526 
00527     if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
00528         /* Actually this is left to help finding error tails later in debugging...
00529          * See Linux kernel driver in winbond-840.c for details.
00530          */
00531         w840private.tx_full = 1;
00532     }
00533 
00534 #if defined(W89C840_DEBUG)
00535     printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
00536 #endif
00537 
00538     /* Now wait for TX to complete. */
00539     transmit_status = w840private.tx_ring[entry].status;
00540 
00541     ct = currticks();
00542     {
00543 #if defined W89C840_DEBUG
00544         u32 intr_stat = 0;
00545 #endif
00546         while (1) {
00547 
00548 #if defined(W89C840_DEBUG)
00549               decode_interrupt(intr_stat);
00550 #endif
00551 
00552                 while ( (transmit_status & DescOwn) && ct + TX_TIMEOUT < currticks()) {
00553 
00554                     transmit_status = w840private.tx_ring[entry].status;
00555                 }
00556 
00557                 break;
00558         }
00559     }
00560 
00561     if ((transmit_status & DescOwn) == 0) {
00562 
00563 #if defined(W89C840_DEBUG)
00564         printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
00565                 w840private.tx_ring[entry].status);
00566 #endif
00567 
00568         return;
00569     }
00570 
00571     /* Transmit timed out... */
00572 
00573     printf("winbond-840 : transmission TIMEOUT : status %X\n", 
00574            (unsigned int) w840private.tx_ring[entry].status);
00575 
00576     return;
00577 }
00578 
00579 /**************************************************************************
00580 w89c840_disable - Turn off ethernet interface
00581 ***************************************************************************/
00582 static void w89c840_disable ( struct nic *nic ) {
00583 
00584     w89c840_reset(nic);
00585 
00586     /* Don't know what to do to disable the board. Is this needed at all? */
00587     /* Yes, a live NIC can corrupt the loaded memory later [Ken] */
00588     /* Stop the chip's Tx and Rx processes. */
00589     writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
00590 }
00591 
00592 /**************************************************************************
00593 w89c840_irq - Enable, Disable, or Force interrupts
00594 ***************************************************************************/
00595 static void w89c840_irq(struct nic *nic __unused, irq_action_t action __unused)
00596 {
00597   switch ( action ) {
00598   case DISABLE :
00599     break;
00600   case ENABLE :
00601     break;
00602   case FORCE :
00603     break;
00604   }
00605 }
00606 
00607 static struct nic_operations w89c840_operations = {
00608         .connect        = dummy_connect,
00609         .poll           = w89c840_poll,
00610         .transmit       = w89c840_transmit,
00611         .irq            = w89c840_irq,
00612 
00613 };
00614 
00615 static struct pci_device_id w89c840_nics[] = {
00616 PCI_ROM(0x1050, 0x0840, "winbond840",     "Winbond W89C840F", 0),
00617 PCI_ROM(0x11f6, 0x2011, "compexrl100atx", "Compex RL100ATX", 0),
00618 };
00619 
00620 PCI_DRIVER ( w89c840_driver, w89c840_nics, PCI_NO_CLASS );
00621 
00622 /**************************************************************************
00623 w89c840_probe - Look for an adapter, this routine's visible to the outside
00624 ***************************************************************************/
00625 static int w89c840_probe ( struct nic *nic, struct pci_device *p ) {
00626 
00627 
00628     u16 sum = 0;
00629     int i;
00630     unsigned short value;
00631 
00632     if (p->ioaddr == 0)
00633         return 0;
00634 
00635     nic->ioaddr = p->ioaddr;
00636     nic->irqno  = 0;
00637 
00638 #if defined(W89C840_DEBUG)
00639     printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
00640 #endif
00641 
00642     ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
00643 
00644 #define PCI_VENDOR_ID_WINBOND2          0x1050
00645 #define PCI_DEVICE_ID_WINBOND2_89C840   0x0840
00646 #define PCI_VENDOR_ID_COMPEX            0x11f6
00647 #define PCI_DEVICE_ID_COMPEX_RL100ATX   0x2011
00648 
00649     /* From Matt Hortman <mbhortman@acpthinclient.com> */
00650     if (p->vendor == PCI_VENDOR_ID_WINBOND2
00651         && p->device == PCI_DEVICE_ID_WINBOND2_89C840) {
00652 
00653         /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */
00654 
00655     } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
00656                 && p->device == PCI_DEVICE_ID_COMPEX_RL100ATX) {
00657 
00658         /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */
00659 
00660     } else {
00661         /* Gee, guess what? They missed again. */
00662         printf("device ID : %X - is not a Compex RL100ATX NIC.\n",
00663                p->device);
00664         return 0;
00665     }
00666 
00667     printf(" %s\n", w89c840_version);
00668 
00669     adjust_pci_device(p);
00670 
00671     /* Ok. Got one. Read the eeprom. */
00672     for (i = 0; i < 0x40; i++) {
00673         value = eeprom_read(ioaddr, i);
00674         eeprom[i] = value;
00675         sum += value;
00676     }
00677 
00678     for (i=0;i<ETH_ALEN;i++) {
00679         nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;
00680     }
00681 
00682     DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
00683 
00684 #if defined(W89C840_DEBUG)
00685     printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
00686 #endif
00687 
00688     /* Reset the chip to erase previous misconfiguration.
00689        No hold time required! */
00690     writel(0x00000001, ioaddr + PCIBusCfg);
00691 
00692     if (driver_flags & CanHaveMII) {
00693         int phy, phy_idx = 0;
00694         for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
00695             int mii_status = mdio_read(ioaddr, phy, 1);
00696             if (mii_status != 0xffff  &&  mii_status != 0x0000) {
00697                 w840private.phys[phy_idx++] = phy;
00698                 w840private.advertising = mdio_read(ioaddr, phy, 4);
00699 
00700 #if defined(W89C840_DEBUG)
00701                 printf("winbond-840 : MII PHY found at address %d, status "
00702                        "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
00703 #endif
00704 
00705             }
00706         }
00707 
00708         w840private.mii_cnt = phy_idx;
00709 
00710         if (phy_idx == 0) {
00711                 printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
00712         }
00713     }
00714 
00715     /* point to NIC specific routines */
00716     nic->nic_op = &w89c840_operations;
00717 
00718     w89c840_reset(nic);
00719 
00720     return 1;
00721 }
00722 
00723 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are
00724    often serial bit streams generated by the host processor.
00725    The example below is for the common 93c46 EEPROM, 64 16 bit words. */
00726 
00727 /* Delay between EEPROM clock transitions.
00728    No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
00729    a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
00730    made udelay() unreliable.
00731    The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
00732    depricated.
00733 */
00734 #define eeprom_delay(ee_addr)    readl(ee_addr)
00735 
00736 enum EEPROM_Ctrl_Bits {
00737     EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
00738     EE_ChipSelect=0x801, EE_DataIn=0x08,
00739 };
00740 
00741 /* The EEPROM commands include the alway-set leading bit. */
00742 enum EEPROM_Cmds {
00743     EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
00744 };
00745 
00746 static int eeprom_read(long addr, int location)
00747 {
00748     int i;
00749     int retval = 0;
00750     int ee_addr = addr + EECtrl;
00751     int read_cmd = location | EE_ReadCmd;
00752     writel(EE_ChipSelect, ee_addr);
00753 
00754     /* Shift the read command bits out. */
00755     for (i = 10; i >= 0; i--) {
00756         short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
00757         writel(dataval, ee_addr);
00758         eeprom_delay(ee_addr);
00759         writel(dataval | EE_ShiftClk, ee_addr);
00760         eeprom_delay(ee_addr);
00761     }
00762     writel(EE_ChipSelect, ee_addr);
00763 
00764     for (i = 16; i > 0; i--) {
00765         writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
00766         eeprom_delay(ee_addr);
00767         retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
00768         writel(EE_ChipSelect, ee_addr);
00769         eeprom_delay(ee_addr);
00770     }
00771 
00772     /* Terminate the EEPROM access. */
00773     writel(0, ee_addr);
00774     return retval;
00775 }
00776 
00777 /*  MII transceiver control section.
00778     Read and write the MII registers using software-generated serial
00779     MDIO protocol.  See the MII specifications or DP83840A data sheet
00780     for details.
00781 
00782     The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
00783     met by back-to-back 33Mhz PCI cycles. */
00784 #define mdio_delay(mdio_addr) readl(mdio_addr)
00785 
00786 /* Set iff a MII transceiver on any interface requires mdio preamble.
00787    This only set with older tranceivers, so the extra
00788    code size of a per-interface flag is not worthwhile. */
00789 static char mii_preamble_required = 1;
00790 
00791 #define MDIO_WRITE0 (MDIO_EnbOutput)
00792 #define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
00793 
00794 /* Generate the preamble required for initial synchronization and
00795    a few older transceivers. */
00796 static void mdio_sync(long mdio_addr)
00797 {
00798     int bits = 32;
00799 
00800     /* Establish sync by sending at least 32 logic ones. */
00801     while (--bits >= 0) {
00802         writel(MDIO_WRITE1, mdio_addr);
00803         mdio_delay(mdio_addr);
00804         writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
00805         mdio_delay(mdio_addr);
00806     }
00807 }
00808 
00809 static int mdio_read(int base_address, int phy_id, int location)
00810 {
00811     long mdio_addr = base_address + MIICtrl;
00812     int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
00813     int i, retval = 0;
00814 
00815     if (mii_preamble_required)
00816         mdio_sync(mdio_addr);
00817 
00818     /* Shift the read command bits out. */
00819     for (i = 15; i >= 0; i--) {
00820         int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00821 
00822         writel(dataval, mdio_addr);
00823         mdio_delay(mdio_addr);
00824         writel(dataval | MDIO_ShiftClk, mdio_addr);
00825         mdio_delay(mdio_addr);
00826     }
00827     /* Read the two transition, 16 data, and wire-idle bits. */
00828     for (i = 20; i > 0; i--) {
00829         writel(MDIO_EnbIn, mdio_addr);
00830         mdio_delay(mdio_addr);
00831         retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
00832         writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00833         mdio_delay(mdio_addr);
00834     }
00835     return (retval>>1) & 0xffff;
00836 }
00837 
00838 #if 0
00839 static void mdio_write(int base_address, int phy_id, int location, int value)
00840 {
00841     long mdio_addr = base_address + MIICtrl;
00842     int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
00843     int i;
00844 
00845     if (location == 4  &&  phy_id == w840private.phys[0])
00846         w840private.advertising = value;
00847 
00848     if (mii_preamble_required)
00849         mdio_sync(mdio_addr);
00850 
00851     /* Shift the command bits out. */
00852     for (i = 31; i >= 0; i--) {
00853         int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
00854 
00855         writel(dataval, mdio_addr);
00856         mdio_delay(mdio_addr);
00857         writel(dataval | MDIO_ShiftClk, mdio_addr);
00858         mdio_delay(mdio_addr);
00859     }
00860     /* Clear out extra bits. */
00861     for (i = 2; i > 0; i--) {
00862         writel(MDIO_EnbIn, mdio_addr);
00863         mdio_delay(mdio_addr);
00864         writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
00865         mdio_delay(mdio_addr);
00866     }
00867     return;
00868 }
00869 #endif
00870 
00871 static void check_duplex(void)
00872 {
00873     int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
00874     int negotiated =  mii_reg5 & w840private.advertising;
00875     int duplex;
00876 
00877     if (w840private.duplex_lock  ||  mii_reg5 == 0xffff)
00878         return;
00879 
00880     duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
00881     if (w840private.full_duplex != duplex) {
00882         w840private.full_duplex = duplex;       
00883 
00884 #if defined(W89C840_DEBUG)
00885         printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
00886                duplex ? "full" : "half", w840private.phys[0], negotiated);
00887 #endif
00888 
00889         w840private.csr6 &= ~0x200;
00890         w840private.csr6 |= duplex ? 0x200 : 0;
00891     }
00892 }
00893 
00894 static void set_rx_mode(void)
00895 {
00896     u32 mc_filter[2];            /* Multicast hash filter */
00897     u32 rx_mode;
00898 
00899     /* Accept all multicasts from now on. */
00900     memset(mc_filter, 0xff, sizeof(mc_filter));
00901 
00902 /*
00903  * works OK with multicast enabled. 
00904  */
00905 
00906     rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
00907 
00908     writel(mc_filter[0], ioaddr + MulticastFilter0);
00909     writel(mc_filter[1], ioaddr + MulticastFilter1);
00910     w840private.csr6 &= ~0x00F8;
00911     w840private.csr6 |= rx_mode;
00912     writel(w840private.csr6, ioaddr + NetworkConfig);
00913 
00914 #if defined(W89C840_DEBUG)
00915     printf("winbond-840 : Done setting RX mode.\n");
00916 #endif
00917 }
00918 
00919 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
00920 static void init_ring(void)
00921 {
00922     int i;
00923     char * p;
00924 
00925     w840private.tx_full = 0;
00926     w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
00927     w840private.dirty_rx = w840private.dirty_tx = 0;
00928 
00929     w840private.rx_buf_sz = PKT_BUF_SZ;
00930     w840private.rx_head_desc = &w840private.rx_ring[0];
00931 
00932     /* Initial all Rx descriptors. Fill in the Rx buffers. */
00933 
00934     p = &w89c840_buf.rx_packet[0];
00935 
00936     for (i = 0; i < RX_RING_SIZE; i++) {
00937         w840private.rx_ring[i].length = w840private.rx_buf_sz;
00938         w840private.rx_ring[i].status = 0;
00939         w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);
00940 
00941         w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
00942         w840private.rx_ring[i].status = DescOwn | DescIntr;
00943     }
00944 
00945     /* Mark the last entry as wrapping the ring. */
00946     w840private.rx_ring[i-1].length |= DescEndRing;
00947     w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);
00948 
00949     w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);
00950 
00951     for (i = 0; i < TX_RING_SIZE; i++) {
00952         w840private.tx_ring[i].status = 0;
00953     }
00954     return;
00955 }
00956 
00957 
00958 DRIVER ( "W89C840F", nic_driver, pci_driver, w89c840_driver,
00959          w89c840_probe, w89c840_disable );
00960 
00961 /*
00962  * Local variables:
00963  *  c-basic-offset: 8
00964  *  c-indent-level: 8
00965  *  tab-width: 8
00966  * End:
00967  */