11b8adde7SWilliam Kucharski /************************************************************************** 21b8adde7SWilliam Kucharski * 31b8adde7SWilliam Kucharski * pcnet32.c -- Etherboot device driver for the AMD PCnet32 41b8adde7SWilliam Kucharski * Written 2003-2003 by Timothy Legge <tlegge@rogers.com> 51b8adde7SWilliam Kucharski * 61b8adde7SWilliam Kucharski * This program is free software; you can redistribute it and/or modify 71b8adde7SWilliam Kucharski * it under the terms of the GNU General Public License as published by 81b8adde7SWilliam Kucharski * the Free Software Foundation; either version 2 of the License, or 91b8adde7SWilliam Kucharski * (at your option) any later version. 101b8adde7SWilliam Kucharski * 111b8adde7SWilliam Kucharski * This program is distributed in the hope that it will be useful, 121b8adde7SWilliam Kucharski * but WITHOUT ANY WARRANTY; without even the implied warranty of 131b8adde7SWilliam Kucharski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141b8adde7SWilliam Kucharski * GNU General Public License for more details. 151b8adde7SWilliam Kucharski * 161b8adde7SWilliam Kucharski * You should have received a copy of the GNU General Public License 171b8adde7SWilliam Kucharski * along with this program; if not, write to the Free Software 181b8adde7SWilliam Kucharski * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 191b8adde7SWilliam Kucharski * 201b8adde7SWilliam Kucharski * Portions of this code based on: 211b8adde7SWilliam Kucharski * pcnet32.c: An AMD PCnet32 ethernet driver for linux: 221b8adde7SWilliam Kucharski * 231b8adde7SWilliam Kucharski * (C) 1996-1999 Thomas Bogendoerfer 241b8adde7SWilliam Kucharski * See Linux Driver for full information 251b8adde7SWilliam Kucharski * 261b8adde7SWilliam Kucharski * The transmit and poll functions were written with reference to: 271b8adde7SWilliam Kucharski * lance.c - LANCE NIC driver for Etherboot written by Ken Yap 281b8adde7SWilliam Kucharski * 291b8adde7SWilliam Kucharski * Linux Driver Version 1.27a, 10.02.2002 301b8adde7SWilliam Kucharski * 311b8adde7SWilliam Kucharski * 321b8adde7SWilliam Kucharski * REVISION HISTORY: 331b8adde7SWilliam Kucharski * ================ 341b8adde7SWilliam Kucharski * v1.0 08-06-2003 timlegge Initial port of Linux driver 351b8adde7SWilliam Kucharski * v1.1 08-23-2003 timlegge Add multicast support 361b8adde7SWilliam Kucharski * v1.2 01-17-2004 timlegge Initial driver output cleanup 371b8adde7SWilliam Kucharski * v1.3 03-29-2004 timlegge More driver cleanup 381b8adde7SWilliam Kucharski * 391b8adde7SWilliam Kucharski * Indent Options: indent -kr -i8 401b8adde7SWilliam Kucharski ***************************************************************************/ 411b8adde7SWilliam Kucharski 421b8adde7SWilliam Kucharski /* to get some global routines like printf */ 431b8adde7SWilliam Kucharski #include "etherboot.h" 441b8adde7SWilliam Kucharski /* to get the interface to the body of the program */ 451b8adde7SWilliam Kucharski #include "nic.h" 461b8adde7SWilliam Kucharski /* to get the PCI support functions, if this is a PCI NIC */ 471b8adde7SWilliam Kucharski #include "pci.h" 481b8adde7SWilliam Kucharski /* Include the time functions */ 491b8adde7SWilliam Kucharski #include "timer.h" 501b8adde7SWilliam Kucharski #include "mii.h" 511b8adde7SWilliam Kucharski /* void hex_dump(const char *data, const unsigned int len); */ 521b8adde7SWilliam Kucharski 531b8adde7SWilliam Kucharski /* Etherboot Specific definations */ 541b8adde7SWilliam Kucharski #define drv_version "v1.3" 551b8adde7SWilliam Kucharski #define drv_date "03-29-2004" 561b8adde7SWilliam Kucharski 571b8adde7SWilliam Kucharski typedef unsigned char u8; 581b8adde7SWilliam Kucharski typedef signed char s8; 591b8adde7SWilliam Kucharski typedef unsigned short u16; 601b8adde7SWilliam Kucharski typedef signed short s16; 611b8adde7SWilliam Kucharski typedef unsigned int u32; 621b8adde7SWilliam Kucharski typedef signed int s32; 631b8adde7SWilliam Kucharski 641b8adde7SWilliam Kucharski static u32 ioaddr; /* Globally used for the card's io address */ 651b8adde7SWilliam Kucharski 661b8adde7SWilliam Kucharski #ifdef EDEBUG 671b8adde7SWilliam Kucharski #define dprintf(x) printf x 681b8adde7SWilliam Kucharski #else 691b8adde7SWilliam Kucharski #define dprintf(x) 701b8adde7SWilliam Kucharski #endif 711b8adde7SWilliam Kucharski 721b8adde7SWilliam Kucharski /* Condensed operations for readability. */ 731b8adde7SWilliam Kucharski #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) 741b8adde7SWilliam Kucharski #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) 751b8adde7SWilliam Kucharski 761b8adde7SWilliam Kucharski /* End Etherboot Specific */ 771b8adde7SWilliam Kucharski 781b8adde7SWilliam Kucharski int cards_found /* __initdata */ ; 791b8adde7SWilliam Kucharski 801b8adde7SWilliam Kucharski #ifdef REMOVE 811b8adde7SWilliam Kucharski /* FIXME: Remove these they are probably pointless */ 821b8adde7SWilliam Kucharski 831b8adde7SWilliam Kucharski /* 841b8adde7SWilliam Kucharski * VLB I/O addresses 851b8adde7SWilliam Kucharski */ 861b8adde7SWilliam Kucharski static unsigned int pcnet32_portlist[] /*__initdata */ = 871b8adde7SWilliam Kucharski { 0x300, 0x320, 0x340, 0x360, 0 }; 881b8adde7SWilliam Kucharski 891b8adde7SWilliam Kucharski static int pcnet32_debug = 1; 901b8adde7SWilliam Kucharski static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ 911b8adde7SWilliam Kucharski static int pcnet32vlb; /* check for VLB cards ? */ 921b8adde7SWilliam Kucharski 931b8adde7SWilliam Kucharski static struct net_device *pcnet32_dev; 941b8adde7SWilliam Kucharski 951b8adde7SWilliam Kucharski static int max_interrupt_work = 80; 961b8adde7SWilliam Kucharski static int rx_copybreak = 200; 971b8adde7SWilliam Kucharski #endif 981b8adde7SWilliam Kucharski #define PCNET32_PORT_AUI 0x00 991b8adde7SWilliam Kucharski #define PCNET32_PORT_10BT 0x01 1001b8adde7SWilliam Kucharski #define PCNET32_PORT_GPSI 0x02 1011b8adde7SWilliam Kucharski #define PCNET32_PORT_MII 0x03 1021b8adde7SWilliam Kucharski 1031b8adde7SWilliam Kucharski #define PCNET32_PORT_PORTSEL 0x03 1041b8adde7SWilliam Kucharski #define PCNET32_PORT_ASEL 0x04 1051b8adde7SWilliam Kucharski #define PCNET32_PORT_100 0x40 1061b8adde7SWilliam Kucharski #define PCNET32_PORT_FD 0x80 1071b8adde7SWilliam Kucharski 1081b8adde7SWilliam Kucharski #define PCNET32_DMA_MASK 0xffffffff 1091b8adde7SWilliam Kucharski 1101b8adde7SWilliam Kucharski /* 1111b8adde7SWilliam Kucharski * table to translate option values from tulip 1121b8adde7SWilliam Kucharski * to internal options 1131b8adde7SWilliam Kucharski */ 1141b8adde7SWilliam Kucharski static unsigned char options_mapping[] = { 1151b8adde7SWilliam Kucharski PCNET32_PORT_ASEL, /* 0 Auto-select */ 1161b8adde7SWilliam Kucharski PCNET32_PORT_AUI, /* 1 BNC/AUI */ 1171b8adde7SWilliam Kucharski PCNET32_PORT_AUI, /* 2 AUI/BNC */ 1181b8adde7SWilliam Kucharski PCNET32_PORT_ASEL, /* 3 not supported */ 1191b8adde7SWilliam Kucharski PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ 1201b8adde7SWilliam Kucharski PCNET32_PORT_ASEL, /* 5 not supported */ 1211b8adde7SWilliam Kucharski PCNET32_PORT_ASEL, /* 6 not supported */ 1221b8adde7SWilliam Kucharski PCNET32_PORT_ASEL, /* 7 not supported */ 1231b8adde7SWilliam Kucharski PCNET32_PORT_ASEL, /* 8 not supported */ 1241b8adde7SWilliam Kucharski PCNET32_PORT_MII, /* 9 MII 10baseT */ 1251b8adde7SWilliam Kucharski PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ 1261b8adde7SWilliam Kucharski PCNET32_PORT_MII, /* 11 MII (autosel) */ 1271b8adde7SWilliam Kucharski PCNET32_PORT_10BT, /* 12 10BaseT */ 1281b8adde7SWilliam Kucharski PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ 1291b8adde7SWilliam Kucharski PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */ 1301b8adde7SWilliam Kucharski PCNET32_PORT_ASEL /* 15 not supported */ 1311b8adde7SWilliam Kucharski }; 1321b8adde7SWilliam Kucharski 1331b8adde7SWilliam Kucharski #define MAX_UNITS 8 /* More are supported, limit only on options */ 1341b8adde7SWilliam Kucharski static int options[MAX_UNITS]; 1351b8adde7SWilliam Kucharski static int full_duplex[MAX_UNITS]; 1361b8adde7SWilliam Kucharski 1371b8adde7SWilliam Kucharski /* 1381b8adde7SWilliam Kucharski * Theory of Operation 1391b8adde7SWilliam Kucharski * 1401b8adde7SWilliam Kucharski * This driver uses the same software structure as the normal lance 1411b8adde7SWilliam Kucharski * driver. So look for a verbose description in lance.c. The differences 1421b8adde7SWilliam Kucharski * to the normal lance driver is the use of the 32bit mode of PCnet32 1431b8adde7SWilliam Kucharski * and PCnetPCI chips. Because these chips are 32bit chips, there is no 1441b8adde7SWilliam Kucharski * 16MB limitation and we don't need bounce buffers. 1451b8adde7SWilliam Kucharski */ 1461b8adde7SWilliam Kucharski 1471b8adde7SWilliam Kucharski 1481b8adde7SWilliam Kucharski 1491b8adde7SWilliam Kucharski /* 1501b8adde7SWilliam Kucharski * Set the number of Tx and Rx buffers, using Log_2(# buffers). 1511b8adde7SWilliam Kucharski * Reasonable default values are 4 Tx buffers, and 16 Rx buffers. 1521b8adde7SWilliam Kucharski * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). 1531b8adde7SWilliam Kucharski */ 1541b8adde7SWilliam Kucharski #ifndef PCNET32_LOG_TX_BUFFERS 1551b8adde7SWilliam Kucharski #define PCNET32_LOG_TX_BUFFERS 1 1561b8adde7SWilliam Kucharski #define PCNET32_LOG_RX_BUFFERS 2 1571b8adde7SWilliam Kucharski #endif 1581b8adde7SWilliam Kucharski 1591b8adde7SWilliam Kucharski #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) 1601b8adde7SWilliam Kucharski #define TX_RING_MOD_MASK (TX_RING_SIZE - 1) 1611b8adde7SWilliam Kucharski /* FIXME: Fix this to allow multiple tx_ring descriptors */ 1621b8adde7SWilliam Kucharski #define TX_RING_LEN_BITS 0x0000 /*PCNET32_LOG_TX_BUFFERS) << 12) */ 1631b8adde7SWilliam Kucharski 1641b8adde7SWilliam Kucharski #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) 1651b8adde7SWilliam Kucharski #define RX_RING_MOD_MASK (RX_RING_SIZE - 1) 1661b8adde7SWilliam Kucharski #define RX_RING_LEN_BITS ((PCNET32_LOG_RX_BUFFERS) << 4) 1671b8adde7SWilliam Kucharski 1681b8adde7SWilliam Kucharski #define PKT_BUF_SZ 1544 1691b8adde7SWilliam Kucharski 1701b8adde7SWilliam Kucharski /* Offsets from base I/O address. */ 1711b8adde7SWilliam Kucharski #define PCNET32_WIO_RDP 0x10 1721b8adde7SWilliam Kucharski #define PCNET32_WIO_RAP 0x12 1731b8adde7SWilliam Kucharski #define PCNET32_WIO_RESET 0x14 1741b8adde7SWilliam Kucharski #define PCNET32_WIO_BDP 0x16 1751b8adde7SWilliam Kucharski 1761b8adde7SWilliam Kucharski #define PCNET32_DWIO_RDP 0x10 1771b8adde7SWilliam Kucharski #define PCNET32_DWIO_RAP 0x14 1781b8adde7SWilliam Kucharski #define PCNET32_DWIO_RESET 0x18 1791b8adde7SWilliam Kucharski #define PCNET32_DWIO_BDP 0x1C 1801b8adde7SWilliam Kucharski 1811b8adde7SWilliam Kucharski #define PCNET32_TOTAL_SIZE 0x20 1821b8adde7SWilliam Kucharski 1831b8adde7SWilliam Kucharski /* Buffers for the tx and Rx */ 1841b8adde7SWilliam Kucharski 1851b8adde7SWilliam Kucharski /* Create a static buffer of size PKT_BUF_SZ for each 1861b8adde7SWilliam Kucharski TX Descriptor. All descriptors point to a 1871b8adde7SWilliam Kucharski part of this buffer */ 1881b8adde7SWilliam Kucharski static unsigned char txb[PKT_BUF_SZ * TX_RING_SIZE]; 1891b8adde7SWilliam Kucharski // __attribute__ ((aligned(16))); 1901b8adde7SWilliam Kucharski 1911b8adde7SWilliam Kucharski /* Create a static buffer of size PKT_BUF_SZ for each 1921b8adde7SWilliam Kucharski RX Descriptor All descriptors point to a 1931b8adde7SWilliam Kucharski part of this buffer */ 1941b8adde7SWilliam Kucharski static unsigned char rxb[RX_RING_SIZE * PKT_BUF_SZ]; 1951b8adde7SWilliam Kucharski // __attribute__ ((aligned(16))); 1961b8adde7SWilliam Kucharski 1971b8adde7SWilliam Kucharski /* The PCNET32 Rx and Tx ring descriptors. */ 1981b8adde7SWilliam Kucharski struct pcnet32_rx_head { 1991b8adde7SWilliam Kucharski u32 base; 2001b8adde7SWilliam Kucharski s16 buf_length; 2011b8adde7SWilliam Kucharski s16 status; 2021b8adde7SWilliam Kucharski u32 msg_length; 2031b8adde7SWilliam Kucharski u32 reserved; 2041b8adde7SWilliam Kucharski }; 2051b8adde7SWilliam Kucharski 2061b8adde7SWilliam Kucharski struct pcnet32_tx_head { 2071b8adde7SWilliam Kucharski u32 base; 2081b8adde7SWilliam Kucharski s16 length; 2091b8adde7SWilliam Kucharski s16 status; 2101b8adde7SWilliam Kucharski u32 misc; 2111b8adde7SWilliam Kucharski u32 reserved; 2121b8adde7SWilliam Kucharski }; 2131b8adde7SWilliam Kucharski 2141b8adde7SWilliam Kucharski /* The PCNET32 32-Bit initialization block, described in databook. */ 2151b8adde7SWilliam Kucharski struct pcnet32_init_block { 2161b8adde7SWilliam Kucharski u16 mode; 2171b8adde7SWilliam Kucharski u16 tlen_rlen; 2181b8adde7SWilliam Kucharski u8 phys_addr[6]; 2191b8adde7SWilliam Kucharski u16 reserved; 2201b8adde7SWilliam Kucharski u32 filter[2]; 2211b8adde7SWilliam Kucharski /* Receive and transmit ring base, along with extra bits. */ 2221b8adde7SWilliam Kucharski u32 rx_ring; 2231b8adde7SWilliam Kucharski u32 tx_ring; 2241b8adde7SWilliam Kucharski }; 2251b8adde7SWilliam Kucharski /* PCnet32 access functions */ 2261b8adde7SWilliam Kucharski struct pcnet32_access { 2271b8adde7SWilliam Kucharski u16(*read_csr) (unsigned long, int); 2281b8adde7SWilliam Kucharski void (*write_csr) (unsigned long, int, u16); 2291b8adde7SWilliam Kucharski u16(*read_bcr) (unsigned long, int); 2301b8adde7SWilliam Kucharski void (*write_bcr) (unsigned long, int, u16); 2311b8adde7SWilliam Kucharski u16(*read_rap) (unsigned long); 2321b8adde7SWilliam Kucharski void (*write_rap) (unsigned long, u16); 2331b8adde7SWilliam Kucharski void (*reset) (unsigned long); 2341b8adde7SWilliam Kucharski }; 2351b8adde7SWilliam Kucharski 2361b8adde7SWilliam Kucharski /* Define the TX Descriptor */ 2371b8adde7SWilliam Kucharski static struct pcnet32_tx_head tx_ring[TX_RING_SIZE] 2381b8adde7SWilliam Kucharski __attribute__ ((aligned(16))); 2391b8adde7SWilliam Kucharski 2401b8adde7SWilliam Kucharski 2411b8adde7SWilliam Kucharski /* Define the RX Descriptor */ 2421b8adde7SWilliam Kucharski static struct pcnet32_rx_head rx_ring[RX_RING_SIZE] 2431b8adde7SWilliam Kucharski __attribute__ ((aligned(16))); 2441b8adde7SWilliam Kucharski 2451b8adde7SWilliam Kucharski /* May need to be moved to mii.h */ 2461b8adde7SWilliam Kucharski struct mii_if_info { 2471b8adde7SWilliam Kucharski int phy_id; 2481b8adde7SWilliam Kucharski int advertising; 2491b8adde7SWilliam Kucharski unsigned int full_duplex:1; /* is full duplex? */ 2501b8adde7SWilliam Kucharski }; 2511b8adde7SWilliam Kucharski 2521b8adde7SWilliam Kucharski /* 2531b8adde7SWilliam Kucharski * The first three fields of pcnet32_private are read by the ethernet device 2541b8adde7SWilliam Kucharski * so we allocate the structure should be allocated by pci_alloc_consistent(). 2551b8adde7SWilliam Kucharski */ 2561b8adde7SWilliam Kucharski #define MII_CNT 4 2571b8adde7SWilliam Kucharski struct pcnet32_private { 2581b8adde7SWilliam Kucharski struct pcnet32_init_block init_block; 2591b8adde7SWilliam Kucharski struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ 2601b8adde7SWilliam Kucharski const char *name; 2611b8adde7SWilliam Kucharski /* The saved address of a sent-in-place packet/buffer, for skfree(). */ 2621b8adde7SWilliam Kucharski struct sk_buff *tx_skbuff[TX_RING_SIZE]; 2631b8adde7SWilliam Kucharski struct sk_buff *rx_skbuff[RX_RING_SIZE]; 2641b8adde7SWilliam Kucharski struct pcnet32_access a; 2651b8adde7SWilliam Kucharski unsigned int cur_rx, cur_tx; /* The next free ring entry */ 2661b8adde7SWilliam Kucharski char tx_full; 2671b8adde7SWilliam Kucharski int options; 2681b8adde7SWilliam Kucharski int shared_irq:1, /* shared irq possible */ 2691b8adde7SWilliam Kucharski ltint:1, /* enable TxDone-intr inhibitor */ 2701b8adde7SWilliam Kucharski dxsuflo:1, /* disable transmit stop on uflo */ 2711b8adde7SWilliam Kucharski mii:1; /* mii port available */ 2721b8adde7SWilliam Kucharski struct mii_if_info mii_if; 2731b8adde7SWilliam Kucharski unsigned char phys[MII_CNT]; 2741b8adde7SWilliam Kucharski struct net_device *next; 2751b8adde7SWilliam Kucharski int full_duplex:1; 2761b8adde7SWilliam Kucharski } lpx; 2771b8adde7SWilliam Kucharski 2781b8adde7SWilliam Kucharski static struct pcnet32_private *lp; 2791b8adde7SWilliam Kucharski 2801b8adde7SWilliam Kucharski static int mdio_read(struct nic *nic __unused, int phy_id, int reg_num); 2811b8adde7SWilliam Kucharski #if 0 2821b8adde7SWilliam Kucharski static void mdio_write(struct nic *nic __unused, int phy_id, int reg_num, 2831b8adde7SWilliam Kucharski int val); 2841b8adde7SWilliam Kucharski #endif 2851b8adde7SWilliam Kucharski enum pci_flags_bit { 2861b8adde7SWilliam Kucharski PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, 2871b8adde7SWilliam Kucharski PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 = 2881b8adde7SWilliam Kucharski 0x10 << 2, PCI_ADDR3 = 0x10 << 3, 2891b8adde7SWilliam Kucharski }; 2901b8adde7SWilliam Kucharski 2911b8adde7SWilliam Kucharski 2921b8adde7SWilliam Kucharski static u16 pcnet32_wio_read_csr(unsigned long addr, int index) 2931b8adde7SWilliam Kucharski { 2941b8adde7SWilliam Kucharski outw(index, addr + PCNET32_WIO_RAP); 2951b8adde7SWilliam Kucharski return inw(addr + PCNET32_WIO_RDP); 2961b8adde7SWilliam Kucharski } 2971b8adde7SWilliam Kucharski 2981b8adde7SWilliam Kucharski static void pcnet32_wio_write_csr(unsigned long addr, int index, u16 val) 2991b8adde7SWilliam Kucharski { 3001b8adde7SWilliam Kucharski outw(index, addr + PCNET32_WIO_RAP); 3011b8adde7SWilliam Kucharski outw(val, addr + PCNET32_WIO_RDP); 3021b8adde7SWilliam Kucharski } 3031b8adde7SWilliam Kucharski 3041b8adde7SWilliam Kucharski static u16 pcnet32_wio_read_bcr(unsigned long addr, int index) 3051b8adde7SWilliam Kucharski { 3061b8adde7SWilliam Kucharski outw(index, addr + PCNET32_WIO_RAP); 3071b8adde7SWilliam Kucharski return inw(addr + PCNET32_WIO_BDP); 3081b8adde7SWilliam Kucharski } 3091b8adde7SWilliam Kucharski 3101b8adde7SWilliam Kucharski static void pcnet32_wio_write_bcr(unsigned long addr, int index, u16 val) 3111b8adde7SWilliam Kucharski { 3121b8adde7SWilliam Kucharski outw(index, addr + PCNET32_WIO_RAP); 3131b8adde7SWilliam Kucharski outw(val, addr + PCNET32_WIO_BDP); 3141b8adde7SWilliam Kucharski } 3151b8adde7SWilliam Kucharski 3161b8adde7SWilliam Kucharski static u16 pcnet32_wio_read_rap(unsigned long addr) 3171b8adde7SWilliam Kucharski { 3181b8adde7SWilliam Kucharski return inw(addr + PCNET32_WIO_RAP); 3191b8adde7SWilliam Kucharski } 3201b8adde7SWilliam Kucharski 3211b8adde7SWilliam Kucharski static void pcnet32_wio_write_rap(unsigned long addr, u16 val) 3221b8adde7SWilliam Kucharski { 3231b8adde7SWilliam Kucharski outw(val, addr + PCNET32_WIO_RAP); 3241b8adde7SWilliam Kucharski } 3251b8adde7SWilliam Kucharski 3261b8adde7SWilliam Kucharski static void pcnet32_wio_reset(unsigned long addr) 3271b8adde7SWilliam Kucharski { 3281b8adde7SWilliam Kucharski inw(addr + PCNET32_WIO_RESET); 3291b8adde7SWilliam Kucharski } 3301b8adde7SWilliam Kucharski 3311b8adde7SWilliam Kucharski static int pcnet32_wio_check(unsigned long addr) 3321b8adde7SWilliam Kucharski { 3331b8adde7SWilliam Kucharski outw(88, addr + PCNET32_WIO_RAP); 3341b8adde7SWilliam Kucharski return (inw(addr + PCNET32_WIO_RAP) == 88); 3351b8adde7SWilliam Kucharski } 3361b8adde7SWilliam Kucharski 3371b8adde7SWilliam Kucharski static struct pcnet32_access pcnet32_wio = { 3381b8adde7SWilliam Kucharski read_csr:pcnet32_wio_read_csr, 3391b8adde7SWilliam Kucharski write_csr:pcnet32_wio_write_csr, 3401b8adde7SWilliam Kucharski read_bcr:pcnet32_wio_read_bcr, 3411b8adde7SWilliam Kucharski write_bcr:pcnet32_wio_write_bcr, 3421b8adde7SWilliam Kucharski read_rap:pcnet32_wio_read_rap, 3431b8adde7SWilliam Kucharski write_rap:pcnet32_wio_write_rap, 3441b8adde7SWilliam Kucharski reset:pcnet32_wio_reset 3451b8adde7SWilliam Kucharski }; 3461b8adde7SWilliam Kucharski 3471b8adde7SWilliam Kucharski static u16 pcnet32_dwio_read_csr(unsigned long addr, int index) 3481b8adde7SWilliam Kucharski { 3491b8adde7SWilliam Kucharski outl(index, addr + PCNET32_DWIO_RAP); 3501b8adde7SWilliam Kucharski return (inl(addr + PCNET32_DWIO_RDP) & 0xffff); 3511b8adde7SWilliam Kucharski } 3521b8adde7SWilliam Kucharski 3531b8adde7SWilliam Kucharski static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val) 3541b8adde7SWilliam Kucharski { 3551b8adde7SWilliam Kucharski outl(index, addr + PCNET32_DWIO_RAP); 3561b8adde7SWilliam Kucharski outl(val, addr + PCNET32_DWIO_RDP); 3571b8adde7SWilliam Kucharski } 3581b8adde7SWilliam Kucharski 3591b8adde7SWilliam Kucharski static u16 pcnet32_dwio_read_bcr(unsigned long addr, int index) 3601b8adde7SWilliam Kucharski { 3611b8adde7SWilliam Kucharski outl(index, addr + PCNET32_DWIO_RAP); 3621b8adde7SWilliam Kucharski return (inl(addr + PCNET32_DWIO_BDP) & 0xffff); 3631b8adde7SWilliam Kucharski } 3641b8adde7SWilliam Kucharski 3651b8adde7SWilliam Kucharski static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val) 3661b8adde7SWilliam Kucharski { 3671b8adde7SWilliam Kucharski outl(index, addr + PCNET32_DWIO_RAP); 3681b8adde7SWilliam Kucharski outl(val, addr + PCNET32_DWIO_BDP); 3691b8adde7SWilliam Kucharski } 3701b8adde7SWilliam Kucharski 3711b8adde7SWilliam Kucharski static u16 pcnet32_dwio_read_rap(unsigned long addr) 3721b8adde7SWilliam Kucharski { 3731b8adde7SWilliam Kucharski return (inl(addr + PCNET32_DWIO_RAP) & 0xffff); 3741b8adde7SWilliam Kucharski } 3751b8adde7SWilliam Kucharski 3761b8adde7SWilliam Kucharski static void pcnet32_dwio_write_rap(unsigned long addr, u16 val) 3771b8adde7SWilliam Kucharski { 3781b8adde7SWilliam Kucharski outl(val, addr + PCNET32_DWIO_RAP); 3791b8adde7SWilliam Kucharski } 3801b8adde7SWilliam Kucharski 3811b8adde7SWilliam Kucharski static void pcnet32_dwio_reset(unsigned long addr) 3821b8adde7SWilliam Kucharski { 3831b8adde7SWilliam Kucharski inl(addr + PCNET32_DWIO_RESET); 3841b8adde7SWilliam Kucharski } 3851b8adde7SWilliam Kucharski 3861b8adde7SWilliam Kucharski static int pcnet32_dwio_check(unsigned long addr) 3871b8adde7SWilliam Kucharski { 3881b8adde7SWilliam Kucharski outl(88, addr + PCNET32_DWIO_RAP); 3891b8adde7SWilliam Kucharski return ((inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88); 3901b8adde7SWilliam Kucharski } 3911b8adde7SWilliam Kucharski 3921b8adde7SWilliam Kucharski static struct pcnet32_access pcnet32_dwio = { 3931b8adde7SWilliam Kucharski read_csr:pcnet32_dwio_read_csr, 3941b8adde7SWilliam Kucharski write_csr:pcnet32_dwio_write_csr, 3951b8adde7SWilliam Kucharski read_bcr:pcnet32_dwio_read_bcr, 3961b8adde7SWilliam Kucharski write_bcr:pcnet32_dwio_write_bcr, 3971b8adde7SWilliam Kucharski read_rap:pcnet32_dwio_read_rap, 3981b8adde7SWilliam Kucharski write_rap:pcnet32_dwio_write_rap, 3991b8adde7SWilliam Kucharski reset:pcnet32_dwio_reset 4001b8adde7SWilliam Kucharski }; 4011b8adde7SWilliam Kucharski 4021b8adde7SWilliam Kucharski 4031b8adde7SWilliam Kucharski /* Initialize the PCNET32 Rx and Tx rings. */ 4041b8adde7SWilliam Kucharski static int pcnet32_init_ring(struct nic *nic) 4051b8adde7SWilliam Kucharski { 4061b8adde7SWilliam Kucharski int i; 4071b8adde7SWilliam Kucharski 4081b8adde7SWilliam Kucharski lp->tx_full = 0; 4091b8adde7SWilliam Kucharski lp->cur_rx = lp->cur_tx = 0; 4101b8adde7SWilliam Kucharski 4111b8adde7SWilliam Kucharski for (i = 0; i < RX_RING_SIZE; i++) { 4121b8adde7SWilliam Kucharski rx_ring[i].base = (u32) virt_to_le32desc(&rxb[i]); 4131b8adde7SWilliam Kucharski rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); 4141b8adde7SWilliam Kucharski rx_ring[i].status = le16_to_cpu(0x8000); 4151b8adde7SWilliam Kucharski } 4161b8adde7SWilliam Kucharski 4171b8adde7SWilliam Kucharski /* The Tx buffer address is filled in as needed, but we do need to clear 4181b8adde7SWilliam Kucharski the upper ownership bit. */ 4191b8adde7SWilliam Kucharski for (i = 0; i < TX_RING_SIZE; i++) { 4201b8adde7SWilliam Kucharski tx_ring[i].base = 0; 4211b8adde7SWilliam Kucharski tx_ring[i].status = 0; 4221b8adde7SWilliam Kucharski } 4231b8adde7SWilliam Kucharski 4241b8adde7SWilliam Kucharski 4251b8adde7SWilliam Kucharski lp->init_block.tlen_rlen = 4261b8adde7SWilliam Kucharski le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 4271b8adde7SWilliam Kucharski for (i = 0; i < 6; i++) 4281b8adde7SWilliam Kucharski lp->init_block.phys_addr[i] = nic->node_addr[i]; 4291b8adde7SWilliam Kucharski lp->init_block.rx_ring = (u32) virt_to_le32desc(&rx_ring[0]); 4301b8adde7SWilliam Kucharski lp->init_block.tx_ring = (u32) virt_to_le32desc(&tx_ring[0]); 4311b8adde7SWilliam Kucharski return 0; 4321b8adde7SWilliam Kucharski } 4331b8adde7SWilliam Kucharski 4341b8adde7SWilliam Kucharski /************************************************************************** 4351b8adde7SWilliam Kucharski RESET - Reset adapter 4361b8adde7SWilliam Kucharski ***************************************************************************/ 4371b8adde7SWilliam Kucharski static void pcnet32_reset(struct nic *nic) 4381b8adde7SWilliam Kucharski { 4391b8adde7SWilliam Kucharski /* put the card in its initial state */ 4401b8adde7SWilliam Kucharski u16 val; 4411b8adde7SWilliam Kucharski int i; 4421b8adde7SWilliam Kucharski 4431b8adde7SWilliam Kucharski /* Reset the PCNET32 */ 4441b8adde7SWilliam Kucharski lp->a.reset(ioaddr); 4451b8adde7SWilliam Kucharski 4461b8adde7SWilliam Kucharski /* switch pcnet32 to 32bit mode */ 4471b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 20, 2); 4481b8adde7SWilliam Kucharski 4491b8adde7SWilliam Kucharski /* set/reset autoselect bit */ 4501b8adde7SWilliam Kucharski val = lp->a.read_bcr(ioaddr, 2) & ~2; 4511b8adde7SWilliam Kucharski if (lp->options & PCNET32_PORT_ASEL) 4521b8adde7SWilliam Kucharski val |= 2; 4531b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 2, val); 4541b8adde7SWilliam Kucharski /* handle full duplex setting */ 4551b8adde7SWilliam Kucharski if (lp->full_duplex) { 4561b8adde7SWilliam Kucharski val = lp->a.read_bcr(ioaddr, 9) & ~3; 4571b8adde7SWilliam Kucharski if (lp->options & PCNET32_PORT_FD) { 4581b8adde7SWilliam Kucharski val |= 1; 4591b8adde7SWilliam Kucharski if (lp->options == 4601b8adde7SWilliam Kucharski (PCNET32_PORT_FD | PCNET32_PORT_AUI)) 4611b8adde7SWilliam Kucharski val |= 2; 4621b8adde7SWilliam Kucharski } else if (lp->options & PCNET32_PORT_ASEL) { 4631b8adde7SWilliam Kucharski /* workaround of xSeries250, turn on for 79C975 only */ 4641b8adde7SWilliam Kucharski i = ((lp->a. 4651b8adde7SWilliam Kucharski read_csr(ioaddr, 4661b8adde7SWilliam Kucharski 88) | (lp->a.read_csr(ioaddr, 4671b8adde7SWilliam Kucharski 89) << 16)) >> 4681b8adde7SWilliam Kucharski 12) & 0xffff; 4691b8adde7SWilliam Kucharski if (i == 0x2627) 4701b8adde7SWilliam Kucharski val |= 3; 4711b8adde7SWilliam Kucharski } 4721b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 9, val); 4731b8adde7SWilliam Kucharski } 4741b8adde7SWilliam Kucharski 4751b8adde7SWilliam Kucharski /* set/reset GPSI bit in test register */ 4761b8adde7SWilliam Kucharski val = lp->a.read_csr(ioaddr, 124) & ~0x10; 4771b8adde7SWilliam Kucharski if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI) 4781b8adde7SWilliam Kucharski val |= 0x10; 4791b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 124, val); 4801b8adde7SWilliam Kucharski 4811b8adde7SWilliam Kucharski if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { 482*4a3b1d5bSBart Coddens val = lp->a.read_bcr(ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mbps, HD */ 4831b8adde7SWilliam Kucharski if (lp->options & PCNET32_PORT_FD) 4841b8adde7SWilliam Kucharski val |= 0x10; 4851b8adde7SWilliam Kucharski if (lp->options & PCNET32_PORT_100) 4861b8adde7SWilliam Kucharski val |= 0x08; 4871b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 32, val); 4881b8adde7SWilliam Kucharski } else { 4891b8adde7SWilliam Kucharski if (lp->options & PCNET32_PORT_ASEL) { /* enable auto negotiate, setup, disable fd */ 4901b8adde7SWilliam Kucharski val = lp->a.read_bcr(ioaddr, 32) & ~0x98; 4911b8adde7SWilliam Kucharski val |= 0x20; 4921b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 32, val); 4931b8adde7SWilliam Kucharski } 4941b8adde7SWilliam Kucharski } 4951b8adde7SWilliam Kucharski 4961b8adde7SWilliam Kucharski #ifdef DO_DXSUFLO 4971b8adde7SWilliam Kucharski if (lp->dxsuflo) { /* Disable transmit stop on underflow */ 4981b8adde7SWilliam Kucharski val = lp->a.read_csr(ioaddr, 3); 4991b8adde7SWilliam Kucharski val |= 0x40; 5001b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 3, val); 5011b8adde7SWilliam Kucharski } 5021b8adde7SWilliam Kucharski #endif 5031b8adde7SWilliam Kucharski 5041b8adde7SWilliam Kucharski if (lp->ltint) { /* Enable TxDone-intr inhibitor */ 5051b8adde7SWilliam Kucharski val = lp->a.read_csr(ioaddr, 5); 5061b8adde7SWilliam Kucharski val |= (1 << 14); 5071b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 5, val); 5081b8adde7SWilliam Kucharski } 5091b8adde7SWilliam Kucharski lp->init_block.mode = 5101b8adde7SWilliam Kucharski le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); 5111b8adde7SWilliam Kucharski lp->init_block.filter[0] = 0xffffffff; 5121b8adde7SWilliam Kucharski lp->init_block.filter[1] = 0xffffffff; 5131b8adde7SWilliam Kucharski 5141b8adde7SWilliam Kucharski pcnet32_init_ring(nic); 5151b8adde7SWilliam Kucharski 5161b8adde7SWilliam Kucharski 5171b8adde7SWilliam Kucharski /* Re-initialize the PCNET32, and start it when done. */ 5181b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 1, 5191b8adde7SWilliam Kucharski (virt_to_bus(&lp->init_block)) & 0xffff); 5201b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16); 5211b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 4, 0x0915); 5221b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 0, 0x0001); 5231b8adde7SWilliam Kucharski 5241b8adde7SWilliam Kucharski 5251b8adde7SWilliam Kucharski i = 0; 5261b8adde7SWilliam Kucharski while (i++ < 100) 5271b8adde7SWilliam Kucharski if (lp->a.read_csr(ioaddr, 0) & 0x0100) 5281b8adde7SWilliam Kucharski break; 5291b8adde7SWilliam Kucharski /* 5301b8adde7SWilliam Kucharski * We used to clear the InitDone bit, 0x0100, here but Mark Stockton 5311b8adde7SWilliam Kucharski * reports that doing so triggers a bug in the '974. 5321b8adde7SWilliam Kucharski */ 5331b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 0, 0x0042); 5341b8adde7SWilliam Kucharski 5351b8adde7SWilliam Kucharski dprintf(("pcnet32 open, csr0 %hX.\n", lp->a.read_csr(ioaddr, 0))); 5361b8adde7SWilliam Kucharski 5371b8adde7SWilliam Kucharski } 5381b8adde7SWilliam Kucharski 5391b8adde7SWilliam Kucharski /************************************************************************** 5401b8adde7SWilliam Kucharski POLL - Wait for a frame 5411b8adde7SWilliam Kucharski ***************************************************************************/ 5421b8adde7SWilliam Kucharski static int pcnet32_poll(struct nic *nic __unused, int retrieve) 5431b8adde7SWilliam Kucharski { 5441b8adde7SWilliam Kucharski /* return true if there's an ethernet packet ready to read */ 5451b8adde7SWilliam Kucharski /* nic->packet should contain data on return */ 5461b8adde7SWilliam Kucharski /* nic->packetlen should contain length of data */ 5471b8adde7SWilliam Kucharski 5481b8adde7SWilliam Kucharski int status; 5491b8adde7SWilliam Kucharski int entry; 5501b8adde7SWilliam Kucharski 5511b8adde7SWilliam Kucharski entry = lp->cur_rx & RX_RING_MOD_MASK; 5521b8adde7SWilliam Kucharski status = ((short) le16_to_cpu(rx_ring[entry].status) >> 8); 5531b8adde7SWilliam Kucharski 5541b8adde7SWilliam Kucharski if (status < 0) 5551b8adde7SWilliam Kucharski return 0; 5561b8adde7SWilliam Kucharski 5571b8adde7SWilliam Kucharski if ( ! retrieve ) return 1; 5581b8adde7SWilliam Kucharski 5591b8adde7SWilliam Kucharski if (status == 0x03) { 5601b8adde7SWilliam Kucharski nic->packetlen = 5611b8adde7SWilliam Kucharski (le32_to_cpu(rx_ring[entry].msg_length) & 0xfff) - 4; 5621b8adde7SWilliam Kucharski memcpy(nic->packet, &rxb[entry], nic->packetlen); 5631b8adde7SWilliam Kucharski 5641b8adde7SWilliam Kucharski /* Andrew Boyd of QNX reports that some revs of the 79C765 5651b8adde7SWilliam Kucharski * clear the buffer length */ 5661b8adde7SWilliam Kucharski rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); 5671b8adde7SWilliam Kucharski rx_ring[entry].status |= le16_to_cpu(0x8000); /* prime for next receive */ 5681b8adde7SWilliam Kucharski /* Switch to the next Rx ring buffer */ 5691b8adde7SWilliam Kucharski lp->cur_rx++; 5701b8adde7SWilliam Kucharski 5711b8adde7SWilliam Kucharski } else { 5721b8adde7SWilliam Kucharski return 0; 5731b8adde7SWilliam Kucharski } 5741b8adde7SWilliam Kucharski 5751b8adde7SWilliam Kucharski return 1; 5761b8adde7SWilliam Kucharski } 5771b8adde7SWilliam Kucharski 5781b8adde7SWilliam Kucharski /************************************************************************** 5791b8adde7SWilliam Kucharski TRANSMIT - Transmit a frame 5801b8adde7SWilliam Kucharski ***************************************************************************/ 5811b8adde7SWilliam Kucharski static void pcnet32_transmit(struct nic *nic __unused, const char *d, /* Destination */ 5821b8adde7SWilliam Kucharski unsigned int t, /* Type */ 5831b8adde7SWilliam Kucharski unsigned int s, /* size */ 5841b8adde7SWilliam Kucharski const char *p) 5851b8adde7SWilliam Kucharski { /* Packet */ 5861b8adde7SWilliam Kucharski /* send the packet to destination */ 5871b8adde7SWilliam Kucharski unsigned long time; 5881b8adde7SWilliam Kucharski u8 *ptxb; 5891b8adde7SWilliam Kucharski u16 nstype; 5901b8adde7SWilliam Kucharski u16 status; 5911b8adde7SWilliam Kucharski int entry = 0; /*lp->cur_tx & TX_RING_MOD_MASK; */ 5921b8adde7SWilliam Kucharski 5931b8adde7SWilliam Kucharski status = 0x8300; 5941b8adde7SWilliam Kucharski /* point to the current txb incase multiple tx_rings are used */ 5951b8adde7SWilliam Kucharski ptxb = txb + (lp->cur_tx * PKT_BUF_SZ); 5961b8adde7SWilliam Kucharski 5971b8adde7SWilliam Kucharski /* copy the packet to ring buffer */ 5981b8adde7SWilliam Kucharski memcpy(ptxb, d, ETH_ALEN); /* dst */ 5991b8adde7SWilliam Kucharski memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ 6001b8adde7SWilliam Kucharski nstype = htons((u16) t); /* type */ 6011b8adde7SWilliam Kucharski memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* type */ 6021b8adde7SWilliam Kucharski memcpy(ptxb + ETH_HLEN, p, s); 6031b8adde7SWilliam Kucharski 6041b8adde7SWilliam Kucharski s += ETH_HLEN; 6051b8adde7SWilliam Kucharski while (s < ETH_ZLEN) /* pad to min length */ 6061b8adde7SWilliam Kucharski ptxb[s++] = '\0'; 6071b8adde7SWilliam Kucharski 6081b8adde7SWilliam Kucharski tx_ring[entry].length = le16_to_cpu(-s); 6091b8adde7SWilliam Kucharski tx_ring[entry].misc = 0x00000000; 6101b8adde7SWilliam Kucharski tx_ring[entry].base = (u32) virt_to_le32desc(ptxb); 6111b8adde7SWilliam Kucharski 6121b8adde7SWilliam Kucharski /* we set the top byte as the very last thing */ 6131b8adde7SWilliam Kucharski tx_ring[entry].status = le16_to_cpu(status); 6141b8adde7SWilliam Kucharski 6151b8adde7SWilliam Kucharski 6161b8adde7SWilliam Kucharski /* Trigger an immediate send poll */ 6171b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 0, 0x0048); 6181b8adde7SWilliam Kucharski 6191b8adde7SWilliam Kucharski /* wait for transmit complete */ 6201b8adde7SWilliam Kucharski lp->cur_tx = 0; /* (lp->cur_tx + 1); */ 6211b8adde7SWilliam Kucharski time = currticks() + TICKS_PER_SEC; /* wait one second */ 6221b8adde7SWilliam Kucharski while (currticks() < time && 6231b8adde7SWilliam Kucharski ((short) le16_to_cpu(tx_ring[entry].status) < 0)); 6241b8adde7SWilliam Kucharski 6251b8adde7SWilliam Kucharski if ((short) le16_to_cpu(tx_ring[entry].status) < 0) 6261b8adde7SWilliam Kucharski printf("PCNET32 timed out on transmit\n"); 6271b8adde7SWilliam Kucharski 6281b8adde7SWilliam Kucharski /* Stop pointing at the current txb 6291b8adde7SWilliam Kucharski * otherwise the card continues to send the packet */ 6301b8adde7SWilliam Kucharski tx_ring[entry].base = 0; 6311b8adde7SWilliam Kucharski 6321b8adde7SWilliam Kucharski } 6331b8adde7SWilliam Kucharski 6341b8adde7SWilliam Kucharski /************************************************************************** 6351b8adde7SWilliam Kucharski DISABLE - Turn off ethernet interface 6361b8adde7SWilliam Kucharski ***************************************************************************/ 6371b8adde7SWilliam Kucharski static void pcnet32_disable(struct dev *dev __unused) 6381b8adde7SWilliam Kucharski { 6391b8adde7SWilliam Kucharski /* Stop the PCNET32 here -- it ocassionally polls memory if we don't */ 6401b8adde7SWilliam Kucharski lp->a.write_csr(ioaddr, 0, 0x0004); 6411b8adde7SWilliam Kucharski 6421b8adde7SWilliam Kucharski /* 6431b8adde7SWilliam Kucharski * Switch back to 16-bit mode to avoid problesm with dumb 6441b8adde7SWilliam Kucharski * DOS packet driver after a warm reboot 6451b8adde7SWilliam Kucharski */ 6461b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 20, 4); 6471b8adde7SWilliam Kucharski } 6481b8adde7SWilliam Kucharski 6491b8adde7SWilliam Kucharski /************************************************************************** 6501b8adde7SWilliam Kucharski IRQ - Enable, Disable, or Force interrupts 6511b8adde7SWilliam Kucharski ***************************************************************************/ 6521b8adde7SWilliam Kucharski static void pcnet32_irq(struct nic *nic __unused, irq_action_t action __unused) 6531b8adde7SWilliam Kucharski { 6541b8adde7SWilliam Kucharski switch ( action ) { 6551b8adde7SWilliam Kucharski case DISABLE : 6561b8adde7SWilliam Kucharski break; 6571b8adde7SWilliam Kucharski case ENABLE : 6581b8adde7SWilliam Kucharski break; 6591b8adde7SWilliam Kucharski case FORCE : 6601b8adde7SWilliam Kucharski break; 6611b8adde7SWilliam Kucharski } 6621b8adde7SWilliam Kucharski } 6631b8adde7SWilliam Kucharski 6641b8adde7SWilliam Kucharski /************************************************************************** 6651b8adde7SWilliam Kucharski PROBE - Look for an adapter, this routine's visible to the outside 6661b8adde7SWilliam Kucharski You should omit the last argument struct pci_device * for a non-PCI NIC 6671b8adde7SWilliam Kucharski ***************************************************************************/ 6681b8adde7SWilliam Kucharski static int pcnet32_probe(struct dev *dev, struct pci_device *pci) 6691b8adde7SWilliam Kucharski { 6701b8adde7SWilliam Kucharski struct nic *nic = (struct nic *) dev; 6711b8adde7SWilliam Kucharski int i, media; 6721b8adde7SWilliam Kucharski int fdx, mii, fset, dxsuflo, ltint; 6731b8adde7SWilliam Kucharski int chip_version; 6741b8adde7SWilliam Kucharski char *chipname; 6751b8adde7SWilliam Kucharski struct pcnet32_access *a = NULL; 6761b8adde7SWilliam Kucharski u8 promaddr[6]; 6771b8adde7SWilliam Kucharski 6781b8adde7SWilliam Kucharski int shared = 1; 6791b8adde7SWilliam Kucharski if (pci->ioaddr == 0) 6801b8adde7SWilliam Kucharski return 0; 6811b8adde7SWilliam Kucharski 6821b8adde7SWilliam Kucharski /* BASE is used throughout to address the card */ 6831b8adde7SWilliam Kucharski ioaddr = pci->ioaddr; 6841b8adde7SWilliam Kucharski printf("pcnet32.c: Found %s, Vendor=0x%hX Device=0x%hX\n", 6851b8adde7SWilliam Kucharski pci->name, pci->vendor, pci->dev_id); 6861b8adde7SWilliam Kucharski 6871b8adde7SWilliam Kucharski nic->irqno = 0; 6881b8adde7SWilliam Kucharski nic->ioaddr = pci->ioaddr & ~3; 6891b8adde7SWilliam Kucharski 6901b8adde7SWilliam Kucharski /* reset the chip */ 6911b8adde7SWilliam Kucharski pcnet32_wio_reset(ioaddr); 6921b8adde7SWilliam Kucharski 6931b8adde7SWilliam Kucharski /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ 6941b8adde7SWilliam Kucharski if (pcnet32_wio_read_csr(ioaddr, 0) == 4 6951b8adde7SWilliam Kucharski && pcnet32_wio_check(ioaddr)) { 6961b8adde7SWilliam Kucharski a = &pcnet32_wio; 6971b8adde7SWilliam Kucharski } else { 6981b8adde7SWilliam Kucharski pcnet32_dwio_reset(ioaddr); 6991b8adde7SWilliam Kucharski if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 7001b8adde7SWilliam Kucharski && pcnet32_dwio_check(ioaddr)) { 7011b8adde7SWilliam Kucharski a = &pcnet32_dwio; 7021b8adde7SWilliam Kucharski } else 7031b8adde7SWilliam Kucharski return 0; 7041b8adde7SWilliam Kucharski } 7051b8adde7SWilliam Kucharski 7061b8adde7SWilliam Kucharski chip_version = 7071b8adde7SWilliam Kucharski a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16); 7081b8adde7SWilliam Kucharski 7091b8adde7SWilliam Kucharski dprintf(("PCnet chip version is %0xhX\n", chip_version)); 7101b8adde7SWilliam Kucharski if ((chip_version & 0xfff) != 0x003) 7111b8adde7SWilliam Kucharski return 0; 7121b8adde7SWilliam Kucharski 7131b8adde7SWilliam Kucharski /* initialize variables */ 7141b8adde7SWilliam Kucharski fdx = mii = fset = dxsuflo = ltint = 0; 7151b8adde7SWilliam Kucharski chip_version = (chip_version >> 12) & 0xffff; 7161b8adde7SWilliam Kucharski 7171b8adde7SWilliam Kucharski switch (chip_version) { 7181b8adde7SWilliam Kucharski case 0x2420: 7191b8adde7SWilliam Kucharski chipname = "PCnet/PCI 79C970"; /* PCI */ 7201b8adde7SWilliam Kucharski break; 7211b8adde7SWilliam Kucharski case 0x2430: 7221b8adde7SWilliam Kucharski if (shared) 7231b8adde7SWilliam Kucharski chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ 7241b8adde7SWilliam Kucharski else 7251b8adde7SWilliam Kucharski chipname = "PCnet/32 79C965"; /* 486/VL bus */ 7261b8adde7SWilliam Kucharski break; 7271b8adde7SWilliam Kucharski case 0x2621: 7281b8adde7SWilliam Kucharski chipname = "PCnet/PCI II 79C970A"; /* PCI */ 7291b8adde7SWilliam Kucharski fdx = 1; 7301b8adde7SWilliam Kucharski break; 7311b8adde7SWilliam Kucharski case 0x2623: 7321b8adde7SWilliam Kucharski chipname = "PCnet/FAST 79C971"; /* PCI */ 7331b8adde7SWilliam Kucharski fdx = 1; 7341b8adde7SWilliam Kucharski mii = 1; 7351b8adde7SWilliam Kucharski fset = 1; 7361b8adde7SWilliam Kucharski ltint = 1; 7371b8adde7SWilliam Kucharski break; 7381b8adde7SWilliam Kucharski case 0x2624: 7391b8adde7SWilliam Kucharski chipname = "PCnet/FAST+ 79C972"; /* PCI */ 7401b8adde7SWilliam Kucharski fdx = 1; 7411b8adde7SWilliam Kucharski mii = 1; 7421b8adde7SWilliam Kucharski fset = 1; 7431b8adde7SWilliam Kucharski break; 7441b8adde7SWilliam Kucharski case 0x2625: 7451b8adde7SWilliam Kucharski chipname = "PCnet/FAST III 79C973"; /* PCI */ 7461b8adde7SWilliam Kucharski fdx = 1; 7471b8adde7SWilliam Kucharski mii = 1; 7481b8adde7SWilliam Kucharski break; 7491b8adde7SWilliam Kucharski case 0x2626: 7501b8adde7SWilliam Kucharski chipname = "PCnet/Home 79C978"; /* PCI */ 7511b8adde7SWilliam Kucharski fdx = 1; 7521b8adde7SWilliam Kucharski /* 7531b8adde7SWilliam Kucharski * This is based on specs published at www.amd.com. This section 7541b8adde7SWilliam Kucharski * assumes that a card with a 79C978 wants to go into 1Mb HomePNA 7551b8adde7SWilliam Kucharski * mode. The 79C978 can also go into standard ethernet, and there 7561b8adde7SWilliam Kucharski * probably should be some sort of module option to select the 7571b8adde7SWilliam Kucharski * mode by which the card should operate 7581b8adde7SWilliam Kucharski */ 7591b8adde7SWilliam Kucharski /* switch to home wiring mode */ 7601b8adde7SWilliam Kucharski media = a->read_bcr(ioaddr, 49); 7611b8adde7SWilliam Kucharski 7621b8adde7SWilliam Kucharski printf("media reset to %#x.\n", media); 7631b8adde7SWilliam Kucharski a->write_bcr(ioaddr, 49, media); 7641b8adde7SWilliam Kucharski break; 7651b8adde7SWilliam Kucharski case 0x2627: 7661b8adde7SWilliam Kucharski chipname = "PCnet/FAST III 79C975"; /* PCI */ 7671b8adde7SWilliam Kucharski fdx = 1; 7681b8adde7SWilliam Kucharski mii = 1; 7691b8adde7SWilliam Kucharski break; 7701b8adde7SWilliam Kucharski default: 7711b8adde7SWilliam Kucharski printf("PCnet version %#x, no PCnet32 chip.\n", 7721b8adde7SWilliam Kucharski chip_version); 7731b8adde7SWilliam Kucharski return 0; 7741b8adde7SWilliam Kucharski } 7751b8adde7SWilliam Kucharski 7761b8adde7SWilliam Kucharski /* 7771b8adde7SWilliam Kucharski * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit 7781b8adde7SWilliam Kucharski * starting until the packet is loaded. Strike one for reliability, lose 7791b8adde7SWilliam Kucharski * one for latency - although on PCI this isnt a big loss. Older chips 7801b8adde7SWilliam Kucharski * have FIFO's smaller than a packet, so you can't do this. 7811b8adde7SWilliam Kucharski */ 7821b8adde7SWilliam Kucharski 7831b8adde7SWilliam Kucharski if (fset) { 7841b8adde7SWilliam Kucharski a->write_bcr(ioaddr, 18, 7851b8adde7SWilliam Kucharski (a->read_bcr(ioaddr, 18) | 0x0800)); 7861b8adde7SWilliam Kucharski a->write_csr(ioaddr, 80, 7871b8adde7SWilliam Kucharski (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); 7881b8adde7SWilliam Kucharski dxsuflo = 1; 7891b8adde7SWilliam Kucharski ltint = 1; 7901b8adde7SWilliam Kucharski } 7911b8adde7SWilliam Kucharski 7921b8adde7SWilliam Kucharski dprintf(("%s at %hX,", chipname, ioaddr)); 7931b8adde7SWilliam Kucharski 7941b8adde7SWilliam Kucharski /* read PROM address */ 7951b8adde7SWilliam Kucharski for (i = 0; i < 6; i++) 7961b8adde7SWilliam Kucharski promaddr[i] = inb(ioaddr + i); 7971b8adde7SWilliam Kucharski 7981b8adde7SWilliam Kucharski /* Update the nic structure with the MAC Address */ 7991b8adde7SWilliam Kucharski for (i = 0; i < ETH_ALEN; i++) { 8001b8adde7SWilliam Kucharski nic->node_addr[i] = promaddr[i]; 8011b8adde7SWilliam Kucharski } 8021b8adde7SWilliam Kucharski /* Print out some hardware info */ 8031b8adde7SWilliam Kucharski printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr, 8041b8adde7SWilliam Kucharski ioaddr); 8051b8adde7SWilliam Kucharski 8061b8adde7SWilliam Kucharski /* Set to pci bus master */ 8071b8adde7SWilliam Kucharski adjust_pci_device(pci); 8081b8adde7SWilliam Kucharski 8091b8adde7SWilliam Kucharski /* point to private storage */ 8101b8adde7SWilliam Kucharski lp = &lpx; 8111b8adde7SWilliam Kucharski 8121b8adde7SWilliam Kucharski #if EBDEBUG 8131b8adde7SWilliam Kucharski if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ 8141b8adde7SWilliam Kucharski i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ 8151b8adde7SWilliam Kucharski dprintf((" tx_start_pt(0x%hX):", i)); 8161b8adde7SWilliam Kucharski switch (i >> 10) { 8171b8adde7SWilliam Kucharski case 0: 8181b8adde7SWilliam Kucharski dprintf((" 20 bytes,")); 8191b8adde7SWilliam Kucharski break; 8201b8adde7SWilliam Kucharski case 1: 8211b8adde7SWilliam Kucharski dprintf((" 64 bytes,")); 8221b8adde7SWilliam Kucharski break; 8231b8adde7SWilliam Kucharski case 2: 8241b8adde7SWilliam Kucharski dprintf((" 128 bytes,")); 8251b8adde7SWilliam Kucharski break; 8261b8adde7SWilliam Kucharski case 3: 8271b8adde7SWilliam Kucharski dprintf(("~220 bytes,")); 8281b8adde7SWilliam Kucharski break; 8291b8adde7SWilliam Kucharski } 8301b8adde7SWilliam Kucharski i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ 8311b8adde7SWilliam Kucharski dprintf((" BCR18(%hX):", i & 0xffff)); 8321b8adde7SWilliam Kucharski if (i & (1 << 5)) 8331b8adde7SWilliam Kucharski dprintf(("BurstWrEn ")); 8341b8adde7SWilliam Kucharski if (i & (1 << 6)) 8351b8adde7SWilliam Kucharski dprintf(("BurstRdEn ")); 8361b8adde7SWilliam Kucharski if (i & (1 << 7)) 8371b8adde7SWilliam Kucharski dprintf(("DWordIO ")); 8381b8adde7SWilliam Kucharski if (i & (1 << 11)) 8391b8adde7SWilliam Kucharski dprintf(("NoUFlow ")); 8401b8adde7SWilliam Kucharski i = a->read_bcr(ioaddr, 25); 8411b8adde7SWilliam Kucharski dprintf((" SRAMSIZE=0x%hX,", i << 8)); 8421b8adde7SWilliam Kucharski i = a->read_bcr(ioaddr, 26); 8431b8adde7SWilliam Kucharski dprintf((" SRAM_BND=0x%hX,", i << 8)); 8441b8adde7SWilliam Kucharski i = a->read_bcr(ioaddr, 27); 8451b8adde7SWilliam Kucharski if (i & (1 << 14)) 8461b8adde7SWilliam Kucharski dprintf(("LowLatRx")); 8471b8adde7SWilliam Kucharski } 8481b8adde7SWilliam Kucharski #endif 8491b8adde7SWilliam Kucharski lp->name = chipname; 8501b8adde7SWilliam Kucharski lp->shared_irq = shared; 8511b8adde7SWilliam Kucharski lp->full_duplex = fdx; 8521b8adde7SWilliam Kucharski lp->dxsuflo = dxsuflo; 8531b8adde7SWilliam Kucharski lp->ltint = ltint; 8541b8adde7SWilliam Kucharski lp->mii = mii; 8551b8adde7SWilliam Kucharski /* FIXME: Fix Options for only one card */ 8561b8adde7SWilliam Kucharski if ((cards_found >= MAX_UNITS) 8571b8adde7SWilliam Kucharski || ((unsigned int) options[cards_found] > sizeof(options_mapping))) 8581b8adde7SWilliam Kucharski lp->options = PCNET32_PORT_ASEL; 8591b8adde7SWilliam Kucharski else 8601b8adde7SWilliam Kucharski lp->options = options_mapping[options[cards_found]]; 8611b8adde7SWilliam Kucharski 8621b8adde7SWilliam Kucharski if (fdx && !(lp->options & PCNET32_PORT_ASEL) && 8631b8adde7SWilliam Kucharski ((cards_found >= MAX_UNITS) || full_duplex[cards_found])) 8641b8adde7SWilliam Kucharski lp->options |= PCNET32_PORT_FD; 8651b8adde7SWilliam Kucharski 8661b8adde7SWilliam Kucharski if (!a) { 8671b8adde7SWilliam Kucharski printf("No access methods\n"); 8681b8adde7SWilliam Kucharski return 0; 8691b8adde7SWilliam Kucharski } 8701b8adde7SWilliam Kucharski lp->a = *a; 8711b8adde7SWilliam Kucharski 8721b8adde7SWilliam Kucharski /* detect special T1/E1 WAN card by checking for MAC address */ 8731b8adde7SWilliam Kucharski if (nic->node_addr[0] == 0x00 && nic->node_addr[1] == 0xe0 8741b8adde7SWilliam Kucharski && nic->node_addr[2] == 0x75) 8751b8adde7SWilliam Kucharski lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; 8761b8adde7SWilliam Kucharski 8771b8adde7SWilliam Kucharski lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ 8781b8adde7SWilliam Kucharski lp->init_block.tlen_rlen = 8791b8adde7SWilliam Kucharski le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 8801b8adde7SWilliam Kucharski for (i = 0; i < 6; i++) 8811b8adde7SWilliam Kucharski lp->init_block.phys_addr[i] = nic->node_addr[i]; 8821b8adde7SWilliam Kucharski lp->init_block.filter[0] = 0xffffffff; 8831b8adde7SWilliam Kucharski lp->init_block.filter[1] = 0xffffffff; 8841b8adde7SWilliam Kucharski lp->init_block.rx_ring = virt_to_bus(&rx_ring); 8851b8adde7SWilliam Kucharski lp->init_block.tx_ring = virt_to_bus(&tx_ring); 8861b8adde7SWilliam Kucharski 8871b8adde7SWilliam Kucharski /* switch pcnet32 to 32bit mode */ 8881b8adde7SWilliam Kucharski a->write_bcr(ioaddr, 20, 2); 8891b8adde7SWilliam Kucharski 8901b8adde7SWilliam Kucharski 8911b8adde7SWilliam Kucharski a->write_csr(ioaddr, 1, (virt_to_bus(&lp->init_block)) & 0xffff); 8921b8adde7SWilliam Kucharski a->write_csr(ioaddr, 2, (virt_to_bus(&lp->init_block)) >> 16); 8931b8adde7SWilliam Kucharski 8941b8adde7SWilliam Kucharski /* 8951b8adde7SWilliam Kucharski * To auto-IRQ we enable the initialization-done and DMA error 8961b8adde7SWilliam Kucharski * interrupts. For ISA boards we get a DMA error, but VLB and PCI 8971b8adde7SWilliam Kucharski * boards will work. 8981b8adde7SWilliam Kucharski */ 8991b8adde7SWilliam Kucharski /* Trigger an initialization just for the interrupt. */ 9001b8adde7SWilliam Kucharski 9011b8adde7SWilliam Kucharski a->write_csr(ioaddr, 0, 0x41); 9021b8adde7SWilliam Kucharski mdelay(1); 9031b8adde7SWilliam Kucharski 9041b8adde7SWilliam Kucharski cards_found++; 9051b8adde7SWilliam Kucharski 9061b8adde7SWilliam Kucharski /* point to NIC specific routines */ 9071b8adde7SWilliam Kucharski pcnet32_reset(nic); 9081b8adde7SWilliam Kucharski if (1) { 9091b8adde7SWilliam Kucharski int tmp; 9101b8adde7SWilliam Kucharski int phy, phy_idx = 0; 9111b8adde7SWilliam Kucharski u16 mii_lpa; 9121b8adde7SWilliam Kucharski lp->phys[0] = 1; /* Default Setting */ 9131b8adde7SWilliam Kucharski for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { 9141b8adde7SWilliam Kucharski int mii_status = mdio_read(nic, phy, MII_BMSR); 9151b8adde7SWilliam Kucharski if (mii_status != 0xffff && mii_status != 0x0000) { 9161b8adde7SWilliam Kucharski lp->phys[phy_idx++] = phy; 9171b8adde7SWilliam Kucharski lp->mii_if.advertising = 9181b8adde7SWilliam Kucharski mdio_read(nic, phy, MII_ADVERTISE); 9191b8adde7SWilliam Kucharski if ((mii_status & 0x0040) == 0) { 9201b8adde7SWilliam Kucharski tmp = phy; 9211b8adde7SWilliam Kucharski dprintf (("MII PHY found at address %d, status " 9221b8adde7SWilliam Kucharski "%hX advertising %hX\n", phy, mii_status, 9231b8adde7SWilliam Kucharski lp->mii_if.advertising)); 9241b8adde7SWilliam Kucharski } 9251b8adde7SWilliam Kucharski } 9261b8adde7SWilliam Kucharski } 9271b8adde7SWilliam Kucharski if (phy_idx == 0) 9281b8adde7SWilliam Kucharski printf("No MII transceiver found!\n"); 9291b8adde7SWilliam Kucharski lp->mii_if.phy_id = lp->phys[0]; 9301b8adde7SWilliam Kucharski 9311b8adde7SWilliam Kucharski lp->mii_if.advertising = 9321b8adde7SWilliam Kucharski mdio_read(nic, lp->phys[0], MII_ADVERTISE); 9331b8adde7SWilliam Kucharski 9341b8adde7SWilliam Kucharski mii_lpa = mdio_read(nic, lp->phys[0], MII_LPA); 9351b8adde7SWilliam Kucharski lp->mii_if.advertising &= mii_lpa; 9361b8adde7SWilliam Kucharski if (lp->mii_if.advertising & ADVERTISE_100FULL) 9371b8adde7SWilliam Kucharski printf("100Mbps Full-Duplex\n"); 9381b8adde7SWilliam Kucharski else if (lp->mii_if.advertising & ADVERTISE_100HALF) 9391b8adde7SWilliam Kucharski printf("100Mbps Half-Duplex\n"); 9401b8adde7SWilliam Kucharski else if (lp->mii_if.advertising & ADVERTISE_10FULL) 9411b8adde7SWilliam Kucharski printf("10Mbps Full-Duplex\n"); 9421b8adde7SWilliam Kucharski else if (lp->mii_if.advertising & ADVERTISE_10HALF) 9431b8adde7SWilliam Kucharski printf("10Mbps Half-Duplex\n"); 9441b8adde7SWilliam Kucharski else 9451b8adde7SWilliam Kucharski printf("\n"); 9461b8adde7SWilliam Kucharski } 9471b8adde7SWilliam Kucharski 9481b8adde7SWilliam Kucharski nic->poll = pcnet32_poll; 9491b8adde7SWilliam Kucharski nic->transmit = pcnet32_transmit; 9501b8adde7SWilliam Kucharski dev->disable = pcnet32_disable; 9511b8adde7SWilliam Kucharski nic->irq = pcnet32_irq; 9521b8adde7SWilliam Kucharski 9531b8adde7SWilliam Kucharski return 1; 9541b8adde7SWilliam Kucharski } 9551b8adde7SWilliam Kucharski static int mdio_read(struct nic *nic __unused, int phy_id, int reg_num) 9561b8adde7SWilliam Kucharski { 9571b8adde7SWilliam Kucharski u16 val_out; 9581b8adde7SWilliam Kucharski int phyaddr; 9591b8adde7SWilliam Kucharski 9601b8adde7SWilliam Kucharski if (!lp->mii) 9611b8adde7SWilliam Kucharski return 0; 9621b8adde7SWilliam Kucharski 9631b8adde7SWilliam Kucharski phyaddr = lp->a.read_bcr(ioaddr, 33); 9641b8adde7SWilliam Kucharski 9651b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 33, 9661b8adde7SWilliam Kucharski ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); 9671b8adde7SWilliam Kucharski val_out = lp->a.read_bcr(ioaddr, 34); 9681b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 33, phyaddr); 9691b8adde7SWilliam Kucharski 9701b8adde7SWilliam Kucharski return val_out; 9711b8adde7SWilliam Kucharski } 9721b8adde7SWilliam Kucharski 9731b8adde7SWilliam Kucharski #if 0 9741b8adde7SWilliam Kucharski static void mdio_write(struct nic *nic __unused, int phy_id, int reg_num, 9751b8adde7SWilliam Kucharski int val) 9761b8adde7SWilliam Kucharski { 9771b8adde7SWilliam Kucharski int phyaddr; 9781b8adde7SWilliam Kucharski 9791b8adde7SWilliam Kucharski if (!lp->mii) 9801b8adde7SWilliam Kucharski return; 9811b8adde7SWilliam Kucharski 9821b8adde7SWilliam Kucharski phyaddr = lp->a.read_bcr(ioaddr, 33); 9831b8adde7SWilliam Kucharski 9841b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 33, 9851b8adde7SWilliam Kucharski ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); 9861b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 34, val); 9871b8adde7SWilliam Kucharski lp->a.write_bcr(ioaddr, 33, phyaddr); 9881b8adde7SWilliam Kucharski } 9891b8adde7SWilliam Kucharski #endif 9901b8adde7SWilliam Kucharski 9911b8adde7SWilliam Kucharski static struct pci_id pcnet32_nics[] = { 9921b8adde7SWilliam Kucharski PCI_ROM(0x1022, 0x2000, "lancepci", "AMD Lance/PCI"), 9931b8adde7SWilliam Kucharski PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD Lance/PCI PCNet/32"), 9941b8adde7SWilliam Kucharski PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD Lance/HomePNA"), 9951b8adde7SWilliam Kucharski }; 9961b8adde7SWilliam Kucharski 9971b8adde7SWilliam Kucharski struct pci_driver pcnet32_driver = { 9981b8adde7SWilliam Kucharski .type = NIC_DRIVER, 9991b8adde7SWilliam Kucharski .name = "PCNET32/PCI", 10001b8adde7SWilliam Kucharski .probe = pcnet32_probe, 10011b8adde7SWilliam Kucharski .ids = pcnet32_nics, 10021b8adde7SWilliam Kucharski .id_count = sizeof(pcnet32_nics) / sizeof(pcnet32_nics[0]), 10031b8adde7SWilliam Kucharski .class = 0, 10041b8adde7SWilliam Kucharski }; 1005