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