17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Etherboot - BOOTP/TFTP Bootstrap Program
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * w89c840.c -- This file implements the winbond-840 driver for etherboot.
57c478bd9Sstevel@tonic-gate *
67c478bd9Sstevel@tonic-gate */
77c478bd9Sstevel@tonic-gate
87c478bd9Sstevel@tonic-gate /*
97c478bd9Sstevel@tonic-gate * Adapted by Igor V. Kovalenko
107c478bd9Sstevel@tonic-gate * -- <garrison@mail.ru>
117c478bd9Sstevel@tonic-gate * OR
127c478bd9Sstevel@tonic-gate * -- <iko@crec.mipt.ru>
137c478bd9Sstevel@tonic-gate * Initial adaptaion stage, including testing, completed 23 August 2000.
147c478bd9Sstevel@tonic-gate */
157c478bd9Sstevel@tonic-gate
167c478bd9Sstevel@tonic-gate /*
177c478bd9Sstevel@tonic-gate * This program is free software; you can redistribute it and/or
187c478bd9Sstevel@tonic-gate * modify it under the terms of the GNU General Public License as
197c478bd9Sstevel@tonic-gate * published by the Free Software Foundation; either version 2, or (at
207c478bd9Sstevel@tonic-gate * your option) any later version.
217c478bd9Sstevel@tonic-gate *
227c478bd9Sstevel@tonic-gate * This program is distributed in the hope that it will be useful, but
237c478bd9Sstevel@tonic-gate * WITHOUT ANY WARRANTY; without even the implied warranty of
247c478bd9Sstevel@tonic-gate * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
257c478bd9Sstevel@tonic-gate * General Public License for more details.
267c478bd9Sstevel@tonic-gate *
277c478bd9Sstevel@tonic-gate * You should have received a copy of the GNU General Public License
287c478bd9Sstevel@tonic-gate * along with this program; if not, write to the Free Software
297c478bd9Sstevel@tonic-gate * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate * date version by what
347c478bd9Sstevel@tonic-gate * Written: Aug 20 2000 V0.10 iko Initial revision.
357c478bd9Sstevel@tonic-gate * changes: Aug 22 2000 V0.90 iko Works!
367c478bd9Sstevel@tonic-gate * Aug 23 2000 V0.91 iko Cleanup, posted to etherboot
377c478bd9Sstevel@tonic-gate * maintainer.
387c478bd9Sstevel@tonic-gate * Aug 26 2000 V0.92 iko Fixed Rx ring handling.
397c478bd9Sstevel@tonic-gate * First Linux Kernel (TM)
407c478bd9Sstevel@tonic-gate * successfully loaded using
417c478bd9Sstevel@tonic-gate * this driver.
427c478bd9Sstevel@tonic-gate * Jan 07 2001 V0.93 iko Transmitter timeouts are handled
437c478bd9Sstevel@tonic-gate * using timer2 routines. Proposed
447c478bd9Sstevel@tonic-gate * by Ken Yap to eliminate CPU speed
457c478bd9Sstevel@tonic-gate * dependency.
467c478bd9Sstevel@tonic-gate * Dec 12 2003 V0.94 timlegge Fixed issues in 5.2, removed
477c478bd9Sstevel@tonic-gate * interrupt usage, enabled
487c478bd9Sstevel@tonic-gate * multicast support
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * This is the etherboot driver for cards based on Winbond W89c840F chip.
517c478bd9Sstevel@tonic-gate *
527c478bd9Sstevel@tonic-gate * It was written from skeleton source, with Donald Becker's winbond-840.c
537c478bd9Sstevel@tonic-gate * kernel driver as a guideline. Mostly the w89c840 related definitions
547c478bd9Sstevel@tonic-gate * and the lower level routines have been cut-and-pasted into this source.
557c478bd9Sstevel@tonic-gate *
567c478bd9Sstevel@tonic-gate * Frankly speaking, about 90% of the code was obtained using cut'n'paste
577c478bd9Sstevel@tonic-gate * sequence :) while the remainder appeared while brainstorming
587c478bd9Sstevel@tonic-gate * Linux Kernel 2.4.0-testX source code. Thanks, Donald and Linus!
597c478bd9Sstevel@tonic-gate *
607c478bd9Sstevel@tonic-gate * There was a demand for using this card in a rather large
617c478bd9Sstevel@tonic-gate * remote boot environment at MSKP OVTI Lab of
627c478bd9Sstevel@tonic-gate * Moscow Institute for Physics and Technology (MIPT) -- http://www.mipt.ru/
637c478bd9Sstevel@tonic-gate * so you may count that for motivation.
647c478bd9Sstevel@tonic-gate *
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate * If you want to see debugging output then define W89C840_DEBUG
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate #define W89C840_DEBUG
737c478bd9Sstevel@tonic-gate */
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * Keep using IO_OPS for Etherboot driver!
777c478bd9Sstevel@tonic-gate */
787c478bd9Sstevel@tonic-gate #define USE_IO_OPS
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #include "etherboot.h"
817c478bd9Sstevel@tonic-gate #include "nic.h"
827c478bd9Sstevel@tonic-gate #include "pci.h"
837c478bd9Sstevel@tonic-gate #include "timer.h"
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate typedef unsigned char u8;
887c478bd9Sstevel@tonic-gate typedef signed char s8;
897c478bd9Sstevel@tonic-gate typedef unsigned short u16;
907c478bd9Sstevel@tonic-gate typedef signed short s16;
917c478bd9Sstevel@tonic-gate typedef unsigned int u32;
927c478bd9Sstevel@tonic-gate typedef signed int s32;
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /* Linux support functions */
957c478bd9Sstevel@tonic-gate #define virt_to_le32desc(addr) virt_to_bus(addr)
967c478bd9Sstevel@tonic-gate #define le32desc_to_virt(addr) bus_to_virt(addr)
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate #define cpu_to_le32(val) (val)
1007c478bd9Sstevel@tonic-gate #define le32_to_cpu(val) (val)
1017c478bd9Sstevel@tonic-gate */
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate /* Operational parameters that are set at compile time. */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate /* Keep the ring sizes a power of two for compile efficiency.
1067c478bd9Sstevel@tonic-gate The compiler will convert <unsigned>'%'<2^N> into a bit mask.
1077c478bd9Sstevel@tonic-gate Making the Tx ring too large decreases the effectiveness of channel
1087c478bd9Sstevel@tonic-gate bonding and packet priority.
1097c478bd9Sstevel@tonic-gate There are no ill effects from too-large receive rings. */
1107c478bd9Sstevel@tonic-gate #define TX_RING_SIZE 2
1117c478bd9Sstevel@tonic-gate #define RX_RING_SIZE 2
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
1147c478bd9Sstevel@tonic-gate To avoid overflowing we don't queue again until we have room for a
1157c478bd9Sstevel@tonic-gate full-size packet.
1167c478bd9Sstevel@tonic-gate */
1177c478bd9Sstevel@tonic-gate #define TX_FIFO_SIZE (2048)
1187c478bd9Sstevel@tonic-gate #define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /* Operational parameters that usually are not changed. */
1217c478bd9Sstevel@tonic-gate /* Time in jiffies before concluding the transmitter is hung. */
1227c478bd9Sstevel@tonic-gate #define TX_TIMEOUT (10*TICKS_PER_MS)
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate * Used to be this much CPU loops on Celeron@400 (?),
1287c478bd9Sstevel@tonic-gate * now using real timer and TX_TIMEOUT!
1297c478bd9Sstevel@tonic-gate * #define TX_LOOP_COUNT 10000000
1307c478bd9Sstevel@tonic-gate */
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate #if !defined(__OPTIMIZE__)
1337c478bd9Sstevel@tonic-gate #warning You must compile this file with the correct options!
1347c478bd9Sstevel@tonic-gate #warning See the last lines of the source file.
1357c478bd9Sstevel@tonic-gate #error You must compile this driver with "-O".
1367c478bd9Sstevel@tonic-gate #endif
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2};
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate #ifdef USE_IO_OPS
1417c478bd9Sstevel@tonic-gate #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
1427c478bd9Sstevel@tonic-gate #else
1437c478bd9Sstevel@tonic-gate #define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
1447c478bd9Sstevel@tonic-gate #endif
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate static u32 driver_flags = CanHaveMII | HasBrokenTx;
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /* This driver was written to use PCI memory space, however some x86 systems
1497c478bd9Sstevel@tonic-gate work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space
1507c478bd9Sstevel@tonic-gate accesses instead of memory space. */
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate #ifdef USE_IO_OPS
1537c478bd9Sstevel@tonic-gate #undef readb
1547c478bd9Sstevel@tonic-gate #undef readw
1557c478bd9Sstevel@tonic-gate #undef readl
1567c478bd9Sstevel@tonic-gate #undef writeb
1577c478bd9Sstevel@tonic-gate #undef writew
1587c478bd9Sstevel@tonic-gate #undef writel
1597c478bd9Sstevel@tonic-gate #define readb inb
1607c478bd9Sstevel@tonic-gate #define readw inw
1617c478bd9Sstevel@tonic-gate #define readl inl
1627c478bd9Sstevel@tonic-gate #define writeb outb
1637c478bd9Sstevel@tonic-gate #define writew outw
1647c478bd9Sstevel@tonic-gate #define writel outl
1657c478bd9Sstevel@tonic-gate #endif
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate /* Offsets to the Command and Status Registers, "CSRs".
1687c478bd9Sstevel@tonic-gate While similar to the Tulip, these registers are longword aligned.
1697c478bd9Sstevel@tonic-gate Note: It's not useful to define symbolic names for every register bit in
1707c478bd9Sstevel@tonic-gate the device. The name can only partially document the semantics and make
1717c478bd9Sstevel@tonic-gate the driver longer and more difficult to read.
1727c478bd9Sstevel@tonic-gate */
1737c478bd9Sstevel@tonic-gate enum w840_offsets {
1747c478bd9Sstevel@tonic-gate PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
1757c478bd9Sstevel@tonic-gate RxRingPtr=0x0C, TxRingPtr=0x10,
1767c478bd9Sstevel@tonic-gate IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
1777c478bd9Sstevel@tonic-gate RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
1787c478bd9Sstevel@tonic-gate CurRxDescAddr=0x30, CurRxBufAddr=0x34, /* Debug use */
1797c478bd9Sstevel@tonic-gate MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
1807c478bd9Sstevel@tonic-gate CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
1817c478bd9Sstevel@tonic-gate };
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /* Bits in the interrupt status/enable registers. */
1847c478bd9Sstevel@tonic-gate /* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
1857c478bd9Sstevel@tonic-gate enum intr_status_bits {
1867c478bd9Sstevel@tonic-gate NormalIntr=0x10000, AbnormalIntr=0x8000,
1877c478bd9Sstevel@tonic-gate IntrPCIErr=0x2000, TimerInt=0x800,
1887c478bd9Sstevel@tonic-gate IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
1897c478bd9Sstevel@tonic-gate TxFIFOUnderflow=0x20, RxErrIntr=0x10,
1907c478bd9Sstevel@tonic-gate TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
1917c478bd9Sstevel@tonic-gate };
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /* Bits in the NetworkConfig register. */
1947c478bd9Sstevel@tonic-gate enum rx_mode_bits {
1957c478bd9Sstevel@tonic-gate AcceptErr=0x80, AcceptRunt=0x40,
1967c478bd9Sstevel@tonic-gate AcceptBroadcast=0x20, AcceptMulticast=0x10,
1977c478bd9Sstevel@tonic-gate AcceptAllPhys=0x08, AcceptMyPhys=0x02,
1987c478bd9Sstevel@tonic-gate };
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate enum mii_reg_bits {
2017c478bd9Sstevel@tonic-gate MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
2027c478bd9Sstevel@tonic-gate MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
2037c478bd9Sstevel@tonic-gate };
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /* The Tulip Rx and Tx buffer descriptors. */
2067c478bd9Sstevel@tonic-gate struct w840_rx_desc {
2077c478bd9Sstevel@tonic-gate s32 status;
2087c478bd9Sstevel@tonic-gate s32 length;
2097c478bd9Sstevel@tonic-gate u32 buffer1;
2107c478bd9Sstevel@tonic-gate u32 next_desc;
2117c478bd9Sstevel@tonic-gate };
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate struct w840_tx_desc {
2147c478bd9Sstevel@tonic-gate s32 status;
2157c478bd9Sstevel@tonic-gate s32 length;
2167c478bd9Sstevel@tonic-gate u32 buffer1, buffer2; /* We use only buffer 1. */
2177c478bd9Sstevel@tonic-gate };
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate /* Bits in network_desc.status */
2207c478bd9Sstevel@tonic-gate enum desc_status_bits {
2217c478bd9Sstevel@tonic-gate DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
2227c478bd9Sstevel@tonic-gate DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
2237c478bd9Sstevel@tonic-gate DescIntr=0x80000000,
2247c478bd9Sstevel@tonic-gate };
2257c478bd9Sstevel@tonic-gate #define PRIV_ALIGN 15 /* Required alignment mask */
2267c478bd9Sstevel@tonic-gate #define PRIV_ALIGN_BYTES 32
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate static struct winbond_private
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate /* Descriptor rings first for alignment. */
2317c478bd9Sstevel@tonic-gate struct w840_rx_desc rx_ring[RX_RING_SIZE];
2327c478bd9Sstevel@tonic-gate struct w840_tx_desc tx_ring[TX_RING_SIZE];
2337c478bd9Sstevel@tonic-gate struct net_device *next_module; /* Link for devices of this type. */
2347c478bd9Sstevel@tonic-gate void *priv_addr; /* Unaligned address for kfree */
2357c478bd9Sstevel@tonic-gate const char *product_name;
2367c478bd9Sstevel@tonic-gate /* Frequently used values: keep some adjacent for cache effect. */
2377c478bd9Sstevel@tonic-gate int chip_id, drv_flags;
2387c478bd9Sstevel@tonic-gate struct pci_dev *pci_dev;
2397c478bd9Sstevel@tonic-gate int csr6;
2407c478bd9Sstevel@tonic-gate struct w840_rx_desc *rx_head_desc;
2417c478bd9Sstevel@tonic-gate unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
2427c478bd9Sstevel@tonic-gate unsigned int rx_buf_sz; /* Based on MTU+slack. */
2437c478bd9Sstevel@tonic-gate unsigned int cur_tx, dirty_tx;
2447c478bd9Sstevel@tonic-gate int tx_q_bytes;
2457c478bd9Sstevel@tonic-gate unsigned int tx_full:1; /* The Tx queue is full. */
2467c478bd9Sstevel@tonic-gate /* These values are keep track of the transceiver/media in use. */
2477c478bd9Sstevel@tonic-gate unsigned int full_duplex:1; /* Full-duplex operation requested. */
2487c478bd9Sstevel@tonic-gate unsigned int duplex_lock:1;
2497c478bd9Sstevel@tonic-gate unsigned int medialock:1; /* Do not sense media. */
2507c478bd9Sstevel@tonic-gate unsigned int default_port:4; /* Last dev->if_port value. */
2517c478bd9Sstevel@tonic-gate /* MII transceiver section. */
2527c478bd9Sstevel@tonic-gate int mii_cnt; /* MII device addresses. */
2537c478bd9Sstevel@tonic-gate u16 advertising; /* NWay media advertisement */
2547c478bd9Sstevel@tonic-gate unsigned char phys[2]; /* MII device addresses. */
2557c478bd9Sstevel@tonic-gate } w840private __attribute__ ((aligned (PRIV_ALIGN_BYTES)));
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate /* NIC specific static variables go here */
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate static int ioaddr;
2607c478bd9Sstevel@tonic-gate static unsigned short eeprom [0x40];
2617c478bd9Sstevel@tonic-gate static char rx_packet[PKT_BUF_SZ * RX_RING_SIZE];
2627c478bd9Sstevel@tonic-gate static char tx_packet[PKT_BUF_SZ * TX_RING_SIZE];
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate static int eeprom_read(long ioaddr, int location);
2657c478bd9Sstevel@tonic-gate static int mdio_read(int base_address, int phy_id, int location);
2667c478bd9Sstevel@tonic-gate #if 0
2677c478bd9Sstevel@tonic-gate static void mdio_write(int base_address, int phy_id, int location, int value);
2687c478bd9Sstevel@tonic-gate #endif
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate static void check_duplex(void);
2717c478bd9Sstevel@tonic-gate static void set_rx_mode(void);
2727c478bd9Sstevel@tonic-gate static void init_ring(void);
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
decode_interrupt(u32 intr_status)2757c478bd9Sstevel@tonic-gate static void decode_interrupt(u32 intr_status)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate printf("Interrupt status: ");
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate #define TRACE_INTR(_intr_) \
2807c478bd9Sstevel@tonic-gate if (intr_status & (_intr_)) { printf (" " #_intr_); }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate TRACE_INTR(NormalIntr);
2837c478bd9Sstevel@tonic-gate TRACE_INTR(AbnormalIntr);
2847c478bd9Sstevel@tonic-gate TRACE_INTR(IntrPCIErr);
2857c478bd9Sstevel@tonic-gate TRACE_INTR(TimerInt);
2867c478bd9Sstevel@tonic-gate TRACE_INTR(IntrRxDied);
2877c478bd9Sstevel@tonic-gate TRACE_INTR(RxNoBuf);
2887c478bd9Sstevel@tonic-gate TRACE_INTR(IntrRxDone);
2897c478bd9Sstevel@tonic-gate TRACE_INTR(TxFIFOUnderflow);
2907c478bd9Sstevel@tonic-gate TRACE_INTR(RxErrIntr);
2917c478bd9Sstevel@tonic-gate TRACE_INTR(TxIdle);
2927c478bd9Sstevel@tonic-gate TRACE_INTR(IntrTxStopped);
2937c478bd9Sstevel@tonic-gate TRACE_INTR(IntrTxDone);
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate printf("\n");
2967c478bd9Sstevel@tonic-gate /*sleep(1);*/
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate #endif
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /**************************************************************************
3017c478bd9Sstevel@tonic-gate w89c840_reset - Reset adapter
3027c478bd9Sstevel@tonic-gate ***************************************************************************/
w89c840_reset(struct nic * nic)3037c478bd9Sstevel@tonic-gate static void w89c840_reset(struct nic *nic)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate int i;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate /* Reset the chip to erase previous misconfiguration.
3087c478bd9Sstevel@tonic-gate No hold time required! */
3097c478bd9Sstevel@tonic-gate writel(0x00000001, ioaddr + PCIBusCfg);
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate init_ring();
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
3147c478bd9Sstevel@tonic-gate writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate for (i = 0; i < ETH_ALEN; i++)
3177c478bd9Sstevel@tonic-gate writeb(nic->node_addr[i], ioaddr + StationAddr + i);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate /* Initialize other registers. */
3207c478bd9Sstevel@tonic-gate /* Configure the PCI bus bursts and FIFO thresholds.
3217c478bd9Sstevel@tonic-gate 486: Set 8 longword cache alignment, 8 longword burst.
3227c478bd9Sstevel@tonic-gate 586: Set 16 longword cache alignment, no burst limit.
3237c478bd9Sstevel@tonic-gate Cache alignment bits 15:14 Burst length 13:8
3247c478bd9Sstevel@tonic-gate 0000 <not allowed> 0000 align to cache 0800 8 longwords
3257c478bd9Sstevel@tonic-gate 4000 8 longwords 0100 1 longword 1000 16 longwords
3267c478bd9Sstevel@tonic-gate 8000 16 longwords 0200 2 longwords 2000 32 longwords
3277c478bd9Sstevel@tonic-gate C000 32 longwords 0400 4 longwords
3287c478bd9Sstevel@tonic-gate Wait the specified 50 PCI cycles after a reset by initializing
3297c478bd9Sstevel@tonic-gate Tx and Rx queues and the address filter list. */
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate writel(0xE010, ioaddr + PCIBusCfg);
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate writel(0, ioaddr + RxStartDemand);
3347c478bd9Sstevel@tonic-gate w840private.csr6 = 0x20022002;
3357c478bd9Sstevel@tonic-gate check_duplex();
3367c478bd9Sstevel@tonic-gate set_rx_mode();
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate /* Do not enable the interrupts Etherboot doesn't need them */
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate writel(0x1A0F5, ioaddr + IntrStatus);
3417c478bd9Sstevel@tonic-gate writel(0x1A0F5, ioaddr + IntrEnable);
3427c478bd9Sstevel@tonic-gate */
3437c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
3447c478bd9Sstevel@tonic-gate printf("winbond-840 : Done reset.\n");
3457c478bd9Sstevel@tonic-gate #endif
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate #if 0
3497c478bd9Sstevel@tonic-gate static void handle_intr(u32 intr_stat)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate if ((intr_stat & (NormalIntr|AbnormalIntr)) == 0) {
3527c478bd9Sstevel@tonic-gate /* we are polling, do not return now */
3537c478bd9Sstevel@tonic-gate /*return 0;*/
3547c478bd9Sstevel@tonic-gate } else {
3557c478bd9Sstevel@tonic-gate /* Acknowledge all of the current interrupt sources ASAP. */
3567c478bd9Sstevel@tonic-gate writel(intr_stat & 0x001ffff, ioaddr + IntrStatus);
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate if (intr_stat & AbnormalIntr) {
3607c478bd9Sstevel@tonic-gate /* There was an abnormal interrupt */
3617c478bd9Sstevel@tonic-gate printf("\n-=- Abnormal interrupt.\n");
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
3647c478bd9Sstevel@tonic-gate decode_interrupt(intr_stat);
3657c478bd9Sstevel@tonic-gate #endif
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate if (intr_stat & RxNoBuf) {
3687c478bd9Sstevel@tonic-gate /* There was an interrupt */
3697c478bd9Sstevel@tonic-gate printf("-=- <=> No receive buffers available.\n");
3707c478bd9Sstevel@tonic-gate writel(0, ioaddr + RxStartDemand);
3717c478bd9Sstevel@tonic-gate }
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate #endif
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate /**************************************************************************
3777c478bd9Sstevel@tonic-gate w89c840_poll - Wait for a frame
3787c478bd9Sstevel@tonic-gate ***************************************************************************/
w89c840_poll(struct nic * nic,int retrieve)3797c478bd9Sstevel@tonic-gate static int w89c840_poll(struct nic *nic, int retrieve)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate /* return true if there's an ethernet packet ready to read */
3827c478bd9Sstevel@tonic-gate /* nic->packet should contain data on return */
3837c478bd9Sstevel@tonic-gate /* nic->packetlen should contain length of data */
3847c478bd9Sstevel@tonic-gate int packet_received = 0;
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
3877c478bd9Sstevel@tonic-gate u32 intr_status = readl(ioaddr + IntrStatus);
3887c478bd9Sstevel@tonic-gate #endif
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate do {
3917c478bd9Sstevel@tonic-gate /* Code from netdev_rx(dev) */
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate int entry = w840private.cur_rx % RX_RING_SIZE;
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate struct w840_rx_desc *desc = w840private.rx_head_desc;
3967c478bd9Sstevel@tonic-gate s32 status = desc->status;
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate if (status & DescOwn) {
3997c478bd9Sstevel@tonic-gate /* DescOwn bit is still set, we should wait for RX to complete */
4007c478bd9Sstevel@tonic-gate packet_received = 0;
4017c478bd9Sstevel@tonic-gate break;
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate if ( !retrieve ) {
4057c478bd9Sstevel@tonic-gate packet_received = 1;
4067c478bd9Sstevel@tonic-gate break;
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate if ((status & 0x38008300) != 0x0300) {
4107c478bd9Sstevel@tonic-gate if ((status & 0x38000300) != 0x0300) {
4117c478bd9Sstevel@tonic-gate /* Ingore earlier buffers. */
4127c478bd9Sstevel@tonic-gate if ((status & 0xffff) != 0x7fff) {
4137c478bd9Sstevel@tonic-gate printf("winbond-840 : Oversized Ethernet frame spanned "
4147c478bd9Sstevel@tonic-gate "multiple buffers, entry %d status %X !\n",
4157c478bd9Sstevel@tonic-gate w840private.cur_rx, status);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate } else if (status & 0x8000) {
4187c478bd9Sstevel@tonic-gate /* There was a fatal error. */
4197c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
4207c478bd9Sstevel@tonic-gate printf("winbond-840 : Receive error, Rx status %X :", status);
4217c478bd9Sstevel@tonic-gate if (status & 0x0890) {
4227c478bd9Sstevel@tonic-gate printf(" RXLEN_ERROR");
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate if (status & 0x004C) {
4257c478bd9Sstevel@tonic-gate printf(", FRAME_ERROR");
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate if (status & 0x0002) {
4287c478bd9Sstevel@tonic-gate printf(", CRC_ERROR");
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate printf("\n");
4317c478bd9Sstevel@tonic-gate #endif
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate /* Simpy do a reset now... */
4347c478bd9Sstevel@tonic-gate w89c840_reset(nic);
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate packet_received = 0;
4377c478bd9Sstevel@tonic-gate break;
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate } else {
4407c478bd9Sstevel@tonic-gate /* Omit the four octet CRC from the length. */
4417c478bd9Sstevel@tonic-gate int pkt_len = ((status >> 16) & 0x7ff) - 4;
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
4447c478bd9Sstevel@tonic-gate printf(" netdev_rx() normal Rx pkt ring %d length %d status %X\n", entry, pkt_len, status);
4457c478bd9Sstevel@tonic-gate #endif
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate nic->packetlen = pkt_len;
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate /* Check if the packet is long enough to accept without copying
4507c478bd9Sstevel@tonic-gate to a minimally-sized skbuff. */
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate memcpy(nic->packet, le32desc_to_virt(w840private.rx_ring[entry].buffer1), pkt_len);
4537c478bd9Sstevel@tonic-gate packet_received = 1;
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate /* Release buffer to NIC */
4567c478bd9Sstevel@tonic-gate w840private.rx_ring[entry].status = DescOwn;
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
4597c478bd9Sstevel@tonic-gate /* You will want this info for the initial debug. */
4607c478bd9Sstevel@tonic-gate printf(" Rx data %hhX:%hhX:%hhX:%hhX:%hhX:"
4617c478bd9Sstevel@tonic-gate "%hhX %hhX:%hhX:%hhX:%hhX:%hhX:%hhX %hhX%hhX "
4627c478bd9Sstevel@tonic-gate "%hhX.%hhX.%hhX.%hhX.\n",
4637c478bd9Sstevel@tonic-gate nic->packet[0], nic->packet[1], nic->packet[2], nic->packet[3],
4647c478bd9Sstevel@tonic-gate nic->packet[4], nic->packet[5], nic->packet[6], nic->packet[7],
4657c478bd9Sstevel@tonic-gate nic->packet[8], nic->packet[9], nic->packet[10],
4667c478bd9Sstevel@tonic-gate nic->packet[11], nic->packet[12], nic->packet[13],
4677c478bd9Sstevel@tonic-gate nic->packet[14], nic->packet[15], nic->packet[16],
4687c478bd9Sstevel@tonic-gate nic->packet[17]);
4697c478bd9Sstevel@tonic-gate #endif
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate entry = (++w840private.cur_rx) % RX_RING_SIZE;
4747c478bd9Sstevel@tonic-gate w840private.rx_head_desc = &w840private.rx_ring[entry];
4757c478bd9Sstevel@tonic-gate } while (0);
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate return packet_received;
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate /**************************************************************************
4817c478bd9Sstevel@tonic-gate w89c840_transmit - Transmit a frame
4827c478bd9Sstevel@tonic-gate ***************************************************************************/
4837c478bd9Sstevel@tonic-gate
w89c840_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)4847c478bd9Sstevel@tonic-gate static void w89c840_transmit(
4857c478bd9Sstevel@tonic-gate struct nic *nic,
4867c478bd9Sstevel@tonic-gate const char *d, /* Destination */
4877c478bd9Sstevel@tonic-gate unsigned int t, /* Type */
4887c478bd9Sstevel@tonic-gate unsigned int s, /* size */
4897c478bd9Sstevel@tonic-gate const char *p) /* Packet */
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate /* send the packet to destination */
4927c478bd9Sstevel@tonic-gate unsigned entry;
4937c478bd9Sstevel@tonic-gate int transmit_status;
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate /* Caution: the write order is important here, set the field
4967c478bd9Sstevel@tonic-gate with the "ownership" bits last. */
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate /* Fill in our transmit buffer */
4997c478bd9Sstevel@tonic-gate entry = w840private.cur_tx % TX_RING_SIZE;
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate memcpy (tx_packet, d, ETH_ALEN); /* dst */
5027c478bd9Sstevel@tonic-gate memcpy (tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/* src */
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate *((char *) tx_packet + 12) = t >> 8; /* type */
5057c478bd9Sstevel@tonic-gate *((char *) tx_packet + 13) = t;
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate memcpy (tx_packet + ETH_HLEN, p, s);
5087c478bd9Sstevel@tonic-gate s += ETH_HLEN;
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate while (s < ETH_ZLEN)
5117c478bd9Sstevel@tonic-gate *((char *) tx_packet + ETH_HLEN + (s++)) = 0;
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate w840private.tx_ring[entry].buffer1 = virt_to_le32desc(tx_packet);
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate w840private.tx_ring[entry].length = (DescWholePkt | (u32) s);
5167c478bd9Sstevel@tonic-gate if (entry >= TX_RING_SIZE-1) /* Wrap ring */
5177c478bd9Sstevel@tonic-gate w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);
5187c478bd9Sstevel@tonic-gate w840private.tx_ring[entry].status = (DescOwn);
5197c478bd9Sstevel@tonic-gate w840private.cur_tx++;
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate w840private.tx_q_bytes = (u16) s;
5227c478bd9Sstevel@tonic-gate writel(0, ioaddr + TxStartDemand);
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate /* Work around horrible bug in the chip by marking the queue as full
5257c478bd9Sstevel@tonic-gate when we do not have FIFO room for a maximum sized packet. */
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {
5287c478bd9Sstevel@tonic-gate /* Actually this is left to help finding error tails later in debugging...
5297c478bd9Sstevel@tonic-gate * See Linux kernel driver in winbond-840.c for details.
5307c478bd9Sstevel@tonic-gate */
5317c478bd9Sstevel@tonic-gate w840private.tx_full = 1;
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
5357c478bd9Sstevel@tonic-gate printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);
5367c478bd9Sstevel@tonic-gate #endif
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate /* Now wait for TX to complete. */
5397c478bd9Sstevel@tonic-gate transmit_status = w840private.tx_ring[entry].status;
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate load_timer2(TX_TIMEOUT);
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate #if defined W89C840_DEBUG
5457c478bd9Sstevel@tonic-gate u32 intr_stat = 0;
5467c478bd9Sstevel@tonic-gate #endif
5477c478bd9Sstevel@tonic-gate while (1) {
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
5507c478bd9Sstevel@tonic-gate decode_interrupt(intr_stat);
5517c478bd9Sstevel@tonic-gate #endif
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate while ( (transmit_status & DescOwn) && timer2_running()) {
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate transmit_status = w840private.tx_ring[entry].status;
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate break;
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate if ((transmit_status & DescOwn) == 0) {
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
5657c478bd9Sstevel@tonic-gate printf("winbond-840 : transmission complete after wait loop iterations, status %X\n",
5667c478bd9Sstevel@tonic-gate w840private.tx_ring[entry].status);
5677c478bd9Sstevel@tonic-gate #endif
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate return;
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate /* Transmit timed out... */
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate printf("winbond-840 : transmission TIMEOUT : status %X\n", w840private.tx_ring[entry].status);
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate return;
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate /**************************************************************************
5807c478bd9Sstevel@tonic-gate w89c840_disable - Turn off ethernet interface
5817c478bd9Sstevel@tonic-gate ***************************************************************************/
w89c840_disable(struct dev * dev)5827c478bd9Sstevel@tonic-gate static void w89c840_disable(struct dev *dev)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate struct nic *nic = (struct nic *)dev;
5857c478bd9Sstevel@tonic-gate /* merge reset and disable */
5867c478bd9Sstevel@tonic-gate w89c840_reset(nic);
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate /* Don't know what to do to disable the board. Is this needed at all? */
5897c478bd9Sstevel@tonic-gate /* Yes, a live NIC can corrupt the loaded memory later [Ken] */
5907c478bd9Sstevel@tonic-gate /* Stop the chip's Tx and Rx processes. */
5917c478bd9Sstevel@tonic-gate writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate /**************************************************************************
5957c478bd9Sstevel@tonic-gate w89c840_irq - Enable, Disable, or Force interrupts
5967c478bd9Sstevel@tonic-gate ***************************************************************************/
w89c840_irq(struct nic * nic __unused,irq_action_t action __unused)5977c478bd9Sstevel@tonic-gate static void w89c840_irq(struct nic *nic __unused, irq_action_t action __unused)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate switch ( action ) {
6007c478bd9Sstevel@tonic-gate case DISABLE :
6017c478bd9Sstevel@tonic-gate break;
6027c478bd9Sstevel@tonic-gate case ENABLE :
6037c478bd9Sstevel@tonic-gate break;
6047c478bd9Sstevel@tonic-gate case FORCE :
6057c478bd9Sstevel@tonic-gate break;
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate /**************************************************************************
6107c478bd9Sstevel@tonic-gate w89c840_probe - Look for an adapter, this routine's visible to the outside
6117c478bd9Sstevel@tonic-gate ***************************************************************************/
w89c840_probe(struct dev * dev,struct pci_device * p)6127c478bd9Sstevel@tonic-gate static int w89c840_probe(struct dev *dev, struct pci_device *p)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate struct nic *nic = (struct nic *)dev;
6157c478bd9Sstevel@tonic-gate u16 sum = 0;
6167c478bd9Sstevel@tonic-gate int i, j;
6177c478bd9Sstevel@tonic-gate unsigned short value;
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate if (p->ioaddr == 0)
6207c478bd9Sstevel@tonic-gate return 0;
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate ioaddr = p->ioaddr;
6237c478bd9Sstevel@tonic-gate nic->ioaddr = p->ioaddr & ~3;
6247c478bd9Sstevel@tonic-gate nic->irqno = 0;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
6287c478bd9Sstevel@tonic-gate printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);
6297c478bd9Sstevel@tonic-gate #endif
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate /* From Matt Hortman <mbhortman@acpthinclient.com> */
6347c478bd9Sstevel@tonic-gate if (p->vendor == PCI_VENDOR_ID_WINBOND2
6357c478bd9Sstevel@tonic-gate && p->dev_id == PCI_DEVICE_ID_WINBOND2_89C840) {
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */
6387c478bd9Sstevel@tonic-gate
6397c478bd9Sstevel@tonic-gate } else if ( p->vendor == PCI_VENDOR_ID_COMPEX
6407c478bd9Sstevel@tonic-gate && p->dev_id == PCI_DEVICE_ID_COMPEX_RL100ATX) {
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate } else {
6457c478bd9Sstevel@tonic-gate /* Gee, guess what? They missed again. */
6467c478bd9Sstevel@tonic-gate printf("device ID : %X - is not a Compex RL100ATX NIC.\n", p->dev_id);
6477c478bd9Sstevel@tonic-gate return 0;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate printf(" %s\n", w89c840_version);
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate adjust_pci_device(p);
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate /* Ok. Got one. Read the eeprom. */
6557c478bd9Sstevel@tonic-gate for (j = 0, i = 0; i < 0x40; i++) {
6567c478bd9Sstevel@tonic-gate value = eeprom_read(ioaddr, i);
6577c478bd9Sstevel@tonic-gate eeprom[i] = value;
6587c478bd9Sstevel@tonic-gate sum += value;
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate for (i=0;i<ETH_ALEN;i++) {
6627c478bd9Sstevel@tonic-gate nic->node_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff;
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate printf ("Ethernet addr: %!\n", nic->node_addr);
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
6677c478bd9Sstevel@tonic-gate printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);
6687c478bd9Sstevel@tonic-gate #endif
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate /* Reset the chip to erase previous misconfiguration.
6717c478bd9Sstevel@tonic-gate No hold time required! */
6727c478bd9Sstevel@tonic-gate writel(0x00000001, ioaddr + PCIBusCfg);
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate if (driver_flags & CanHaveMII) {
6757c478bd9Sstevel@tonic-gate int phy, phy_idx = 0;
6767c478bd9Sstevel@tonic-gate for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
6777c478bd9Sstevel@tonic-gate int mii_status = mdio_read(ioaddr, phy, 1);
6787c478bd9Sstevel@tonic-gate if (mii_status != 0xffff && mii_status != 0x0000) {
6797c478bd9Sstevel@tonic-gate w840private.phys[phy_idx++] = phy;
6807c478bd9Sstevel@tonic-gate w840private.advertising = mdio_read(ioaddr, phy, 4);
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
6837c478bd9Sstevel@tonic-gate printf("winbond-840 : MII PHY found at address %d, status "
6847c478bd9Sstevel@tonic-gate "%X advertising %hX.\n", phy, mii_status, w840private.advertising);
6857c478bd9Sstevel@tonic-gate #endif
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate w840private.mii_cnt = phy_idx;
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate if (phy_idx == 0) {
6937c478bd9Sstevel@tonic-gate printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate /* point to NIC specific routines */
6987c478bd9Sstevel@tonic-gate dev->disable = w89c840_disable;
6997c478bd9Sstevel@tonic-gate nic->poll = w89c840_poll;
7007c478bd9Sstevel@tonic-gate nic->transmit = w89c840_transmit;
7017c478bd9Sstevel@tonic-gate nic->irq = w89c840_irq;
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate w89c840_reset(nic);
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate return 1;
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are
7097c478bd9Sstevel@tonic-gate often serial bit streams generated by the host processor.
7107c478bd9Sstevel@tonic-gate The example below is for the common 93c46 EEPROM, 64 16 bit words. */
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate /* Delay between EEPROM clock transitions.
7137c478bd9Sstevel@tonic-gate No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
7147c478bd9Sstevel@tonic-gate a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that
7157c478bd9Sstevel@tonic-gate made udelay() unreliable.
7167c478bd9Sstevel@tonic-gate The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
7177c478bd9Sstevel@tonic-gate depricated.
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate #define eeprom_delay(ee_addr) readl(ee_addr)
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate enum EEPROM_Ctrl_Bits {
7227c478bd9Sstevel@tonic-gate EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
7237c478bd9Sstevel@tonic-gate EE_ChipSelect=0x801, EE_DataIn=0x08,
7247c478bd9Sstevel@tonic-gate };
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate /* The EEPROM commands include the alway-set leading bit. */
7277c478bd9Sstevel@tonic-gate enum EEPROM_Cmds {
7287c478bd9Sstevel@tonic-gate EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
7297c478bd9Sstevel@tonic-gate };
7307c478bd9Sstevel@tonic-gate
eeprom_read(long addr,int location)7317c478bd9Sstevel@tonic-gate static int eeprom_read(long addr, int location)
7327c478bd9Sstevel@tonic-gate {
7337c478bd9Sstevel@tonic-gate int i;
7347c478bd9Sstevel@tonic-gate int retval = 0;
7357c478bd9Sstevel@tonic-gate int ee_addr = addr + EECtrl;
7367c478bd9Sstevel@tonic-gate int read_cmd = location | EE_ReadCmd;
7377c478bd9Sstevel@tonic-gate writel(EE_ChipSelect, ee_addr);
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate /* Shift the read command bits out. */
7407c478bd9Sstevel@tonic-gate for (i = 10; i >= 0; i--) {
7417c478bd9Sstevel@tonic-gate short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
7427c478bd9Sstevel@tonic-gate writel(dataval, ee_addr);
7437c478bd9Sstevel@tonic-gate eeprom_delay(ee_addr);
7447c478bd9Sstevel@tonic-gate writel(dataval | EE_ShiftClk, ee_addr);
7457c478bd9Sstevel@tonic-gate eeprom_delay(ee_addr);
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate writel(EE_ChipSelect, ee_addr);
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate for (i = 16; i > 0; i--) {
7507c478bd9Sstevel@tonic-gate writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
7517c478bd9Sstevel@tonic-gate eeprom_delay(ee_addr);
7527c478bd9Sstevel@tonic-gate retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
7537c478bd9Sstevel@tonic-gate writel(EE_ChipSelect, ee_addr);
7547c478bd9Sstevel@tonic-gate eeprom_delay(ee_addr);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /* Terminate the EEPROM access. */
7587c478bd9Sstevel@tonic-gate writel(0, ee_addr);
7597c478bd9Sstevel@tonic-gate return retval;
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate /* MII transceiver control section.
7637c478bd9Sstevel@tonic-gate Read and write the MII registers using software-generated serial
7647c478bd9Sstevel@tonic-gate MDIO protocol. See the MII specifications or DP83840A data sheet
7657c478bd9Sstevel@tonic-gate for details.
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
7687c478bd9Sstevel@tonic-gate met by back-to-back 33Mhz PCI cycles. */
7697c478bd9Sstevel@tonic-gate #define mdio_delay(mdio_addr) readl(mdio_addr)
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate /* Set iff a MII transceiver on any interface requires mdio preamble.
7727c478bd9Sstevel@tonic-gate This only set with older tranceivers, so the extra
7737c478bd9Sstevel@tonic-gate code size of a per-interface flag is not worthwhile. */
7747c478bd9Sstevel@tonic-gate static char mii_preamble_required = 1;
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate #define MDIO_WRITE0 (MDIO_EnbOutput)
7777c478bd9Sstevel@tonic-gate #define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate /* Generate the preamble required for initial synchronization and
7807c478bd9Sstevel@tonic-gate a few older transceivers. */
mdio_sync(long mdio_addr)7817c478bd9Sstevel@tonic-gate static void mdio_sync(long mdio_addr)
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate int bits = 32;
7847c478bd9Sstevel@tonic-gate
7857c478bd9Sstevel@tonic-gate /* Establish sync by sending at least 32 logic ones. */
7867c478bd9Sstevel@tonic-gate while (--bits >= 0) {
7877c478bd9Sstevel@tonic-gate writel(MDIO_WRITE1, mdio_addr);
7887c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
7897c478bd9Sstevel@tonic-gate writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
7907c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate
mdio_read(int base_address,int phy_id,int location)7947c478bd9Sstevel@tonic-gate static int mdio_read(int base_address, int phy_id, int location)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate long mdio_addr = base_address + MIICtrl;
7977c478bd9Sstevel@tonic-gate int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
7987c478bd9Sstevel@tonic-gate int i, retval = 0;
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate if (mii_preamble_required)
8017c478bd9Sstevel@tonic-gate mdio_sync(mdio_addr);
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate /* Shift the read command bits out. */
8047c478bd9Sstevel@tonic-gate for (i = 15; i >= 0; i--) {
8057c478bd9Sstevel@tonic-gate int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate writel(dataval, mdio_addr);
8087c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8097c478bd9Sstevel@tonic-gate writel(dataval | MDIO_ShiftClk, mdio_addr);
8107c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate /* Read the two transition, 16 data, and wire-idle bits. */
8137c478bd9Sstevel@tonic-gate for (i = 20; i > 0; i--) {
8147c478bd9Sstevel@tonic-gate writel(MDIO_EnbIn, mdio_addr);
8157c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8167c478bd9Sstevel@tonic-gate retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
8177c478bd9Sstevel@tonic-gate writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
8187c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate return (retval>>1) & 0xffff;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate #if 0
8247c478bd9Sstevel@tonic-gate static void mdio_write(int base_address, int phy_id, int location, int value)
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate long mdio_addr = base_address + MIICtrl;
8277c478bd9Sstevel@tonic-gate int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
8287c478bd9Sstevel@tonic-gate int i;
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate if (location == 4 && phy_id == w840private.phys[0])
8317c478bd9Sstevel@tonic-gate w840private.advertising = value;
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate if (mii_preamble_required)
8347c478bd9Sstevel@tonic-gate mdio_sync(mdio_addr);
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate /* Shift the command bits out. */
8377c478bd9Sstevel@tonic-gate for (i = 31; i >= 0; i--) {
8387c478bd9Sstevel@tonic-gate int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate writel(dataval, mdio_addr);
8417c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8427c478bd9Sstevel@tonic-gate writel(dataval | MDIO_ShiftClk, mdio_addr);
8437c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate /* Clear out extra bits. */
8467c478bd9Sstevel@tonic-gate for (i = 2; i > 0; i--) {
8477c478bd9Sstevel@tonic-gate writel(MDIO_EnbIn, mdio_addr);
8487c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8497c478bd9Sstevel@tonic-gate writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
8507c478bd9Sstevel@tonic-gate mdio_delay(mdio_addr);
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate return;
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate #endif
8557c478bd9Sstevel@tonic-gate
check_duplex(void)8567c478bd9Sstevel@tonic-gate static void check_duplex(void)
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);
8597c478bd9Sstevel@tonic-gate int negotiated = mii_reg5 & w840private.advertising;
8607c478bd9Sstevel@tonic-gate int duplex;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate if (w840private.duplex_lock || mii_reg5 == 0xffff)
8637c478bd9Sstevel@tonic-gate return;
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
8667c478bd9Sstevel@tonic-gate if (w840private.full_duplex != duplex) {
8677c478bd9Sstevel@tonic-gate w840private.full_duplex = duplex;
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
8707c478bd9Sstevel@tonic-gate printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",
8717c478bd9Sstevel@tonic-gate duplex ? "full" : "half", w840private.phys[0], negotiated);
8727c478bd9Sstevel@tonic-gate #endif
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate w840private.csr6 &= ~0x200;
8757c478bd9Sstevel@tonic-gate w840private.csr6 |= duplex ? 0x200 : 0;
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate
set_rx_mode(void)8797c478bd9Sstevel@tonic-gate static void set_rx_mode(void)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate u32 mc_filter[2]; /* Multicast hash filter */
8827c478bd9Sstevel@tonic-gate u32 rx_mode;
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /* Accept all multicasts from now on. */
8857c478bd9Sstevel@tonic-gate memset(mc_filter, 0xff, sizeof(mc_filter));
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate /*
8887c478bd9Sstevel@tonic-gate * works OK with multicast enabled.
8897c478bd9Sstevel@tonic-gate */
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate writel(mc_filter[0], ioaddr + MulticastFilter0);
8947c478bd9Sstevel@tonic-gate writel(mc_filter[1], ioaddr + MulticastFilter1);
8957c478bd9Sstevel@tonic-gate w840private.csr6 &= ~0x00F8;
8967c478bd9Sstevel@tonic-gate w840private.csr6 |= rx_mode;
8977c478bd9Sstevel@tonic-gate writel(w840private.csr6, ioaddr + NetworkConfig);
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate #if defined(W89C840_DEBUG)
9007c478bd9Sstevel@tonic-gate printf("winbond-840 : Done setting RX mode.\n");
9017c478bd9Sstevel@tonic-gate #endif
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
init_ring(void)9057c478bd9Sstevel@tonic-gate static void init_ring(void)
9067c478bd9Sstevel@tonic-gate {
9077c478bd9Sstevel@tonic-gate int i;
9087c478bd9Sstevel@tonic-gate char * p;
9097c478bd9Sstevel@tonic-gate
9107c478bd9Sstevel@tonic-gate w840private.tx_full = 0;
9117c478bd9Sstevel@tonic-gate w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;
9127c478bd9Sstevel@tonic-gate w840private.dirty_rx = w840private.dirty_tx = 0;
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate w840private.rx_buf_sz = PKT_BUF_SZ;
9157c478bd9Sstevel@tonic-gate w840private.rx_head_desc = &w840private.rx_ring[0];
9167c478bd9Sstevel@tonic-gate
9177c478bd9Sstevel@tonic-gate /* Initial all Rx descriptors. Fill in the Rx buffers. */
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate p = &rx_packet[0];
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate for (i = 0; i < RX_RING_SIZE; i++) {
9227c478bd9Sstevel@tonic-gate w840private.rx_ring[i].length = w840private.rx_buf_sz;
9237c478bd9Sstevel@tonic-gate w840private.rx_ring[i].status = 0;
9247c478bd9Sstevel@tonic-gate w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));
9277c478bd9Sstevel@tonic-gate w840private.rx_ring[i].status = DescOwn | DescIntr;
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate /* Mark the last entry as wrapping the ring. */
9317c478bd9Sstevel@tonic-gate w840private.rx_ring[i-1].length |= DescEndRing;
9327c478bd9Sstevel@tonic-gate w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate for (i = 0; i < TX_RING_SIZE; i++) {
9377c478bd9Sstevel@tonic-gate w840private.tx_ring[i].status = 0;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate return;
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate static struct pci_id w89c840_nics[] = {
9447c478bd9Sstevel@tonic-gate PCI_ROM(0x1050, 0x0840, "winbond840", "Winbond W89C840F"),
9457c478bd9Sstevel@tonic-gate PCI_ROM(0x11f6, 0x2011, "compexrl100atx", "Compex RL100ATX"),
9467c478bd9Sstevel@tonic-gate };
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate struct pci_driver w89c840_driver = {
9497c478bd9Sstevel@tonic-gate .type = NIC_DRIVER,
9507c478bd9Sstevel@tonic-gate .name = "W89C840F",
9517c478bd9Sstevel@tonic-gate .probe = w89c840_probe,
9527c478bd9Sstevel@tonic-gate .ids = w89c840_nics,
9537c478bd9Sstevel@tonic-gate .id_count = sizeof(w89c840_nics)/sizeof(w89c840_nics[0]),
9547c478bd9Sstevel@tonic-gate .class = 0,
9557c478bd9Sstevel@tonic-gate };
956