/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. *//* * Copyright 1996-1999 Thomas Bogendoerfer * * Derived from the lance driver written 1993,1994,1995 by Donald Becker. * * Copyright 1993 United States Government as represented by the * Director, National Security Agency. * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * This driver is for PCnet32 and PCnetPCI based ethercards *//************************************************************************** * 23 Oct, 2000. * Fixed a few bugs, related to running the controller in 32bit mode. * * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. * *************************************************************************/ #define DRV_NAME "pcnet32"#define DRV_VERSION "1.32"#define DRV_RELDATE "18.Mar.2006"#define PFX DRV_NAME ": " static const char *const version = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; #include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/crc32.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/spinlock.h>#include <linux/moduleparam.h>#include <linux/bitops.h> #include <asm/dma.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/irq.h> /* * PCI device identifiers for "new style" Linux PCI Device Drivers */static struct pci_device_id pcnet32_pci_tbl[] = { { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* * Adapters that were sold with IBM's RS/6000 or pSeries hardware have * the incorrect vendor id. */ { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0}, { } /* terminate list */}; MODULE_DEVICE_TABLE(pci, pcnet32_pci_tbl); static int cards_found; /* * VLB I/O addresses */static unsigned int pcnet32_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0 }; static int pcnet32_debug = 0;static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */static int pcnet32vlb; /* check for VLB cards ? */ static struct net_device *pcnet32_dev; static int max_interrupt_work = 2;static int rx_copybreak = 200; #define PCNET32_PORT_AUI 0x00#define PCNET32_PORT_10BT 0x01#define PCNET32_PORT_GPSI 0x02#define PCNET32_PORT_MII 0x03 #define PCNET32_PORT_PORTSEL 0x03#define PCNET32_PORT_ASEL 0x04#define PCNET32_PORT_100 0x40#define PCNET32_PORT_FD 0x80 #define PCNET32_DMA_MASK 0xffffffff #define PCNET32_WATCHDOG_TIMEOUT (jiffies + (2 * HZ))#define PCNET32_BLINK_TIMEOUT (jiffies + (HZ/4)) /* * table to translate option values from tulip * to internal options */static const unsigned char options_mapping[] = { PCNET32_PORT_ASEL, /* 0 Auto-select */ PCNET32_PORT_AUI, /* 1 BNC/AUI */ PCNET32_PORT_AUI, /* 2 AUI/BNC */ PCNET32_PORT_ASEL, /* 3 not supported */ PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ PCNET32_PORT_ASEL, /* 5 not supported */ PCNET32_PORT_ASEL, /* 6 not supported */ PCNET32_PORT_ASEL, /* 7 not supported */ PCNET32_PORT_ASEL, /* 8 not supported */ PCNET32_PORT_MII, /* 9 MII 10baseT */ PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ PCNET32_PORT_MII, /* 11 MII (autosel) */ PCNET32_PORT_10BT, /* 12 10BaseT */ PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ /* 14 MII 100BaseTx-FD */ PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, PCNET32_PORT_ASEL /* 15 not supported */}; static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { "Loopback test (offline)"}; #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) #define PCNET32_NUM_REGS 136 #define MAX_UNITS 8 /* More are supported, limit only on options */static int options[MAX_UNITS];static int full_duplex[MAX_UNITS];static int homepna[MAX_UNITS]; /* * Theory of Operation * * This driver uses the same software structure as the normal lance * driver. So look for a verbose description in lance.c. The differences * to the normal lance driver is the use of the 32bit mode of PCnet32 * and PCnetPCI chips. Because these chips are 32bit chips, there is no * 16MB limitation and we don't need bounce buffers. */ /* * Set the number of Tx and Rx buffers, using Log_2(# buffers). * Reasonable default values are 4 Tx buffers, and 16 Rx buffers. * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */#ifndef PCNET32_LOG_TX_BUFFERS#define PCNET32_LOG_TX_BUFFERS 4#define PCNET32_LOG_RX_BUFFERS 5#define PCNET32_LOG_MAX_TX_BUFFERS 9 /* 2^9 == 512 */#define PCNET32_LOG_MAX_RX_BUFFERS 9#endif #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS))#define TX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_TX_BUFFERS)) #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS))#define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS)) #define PKT_BUF_SZ 1544 /* Offsets from base I/O address. */#define PCNET32_WIO_RDP 0x10#define PCNET32_WIO_RAP 0x12#define PCNET32_WIO_RESET 0x14#define PCNET32_WIO_BDP 0x16 #define PCNET32_DWIO_RDP 0x10#define PCNET32_DWIO_RAP 0x14#define PCNET32_DWIO_RESET 0x18#define PCNET32_DWIO_BDP 0x1C #define PCNET32_TOTAL_SIZE 0x20 /* The PCNET32 Rx and Tx ring descriptors. */struct pcnet32_rx_head { u32 base; s16 buf_length; s16 status; u32 msg_length; u32 reserved;}; struct pcnet32_tx_head { u32 base; s16 length; s16 status; u32 misc; u32 reserved;}; /* The PCNET32 32-Bit initialization block, described in databook. */struct pcnet32_init_block { u16 mode; u16 tlen_rlen; u8 phys_addr[6]; u16 reserved; u32 filter[2]; /* Receive and transmit ring base, along with extra bits. */ u32 rx_ring; u32 tx_ring;}; /* PCnet32 access functions */struct pcnet32_access { u16 (*read_csr) (unsigned long, int); void (*write_csr) (unsigned long, int, u16); u16 (*read_bcr) (unsigned long, int); void (*write_bcr) (unsigned long, int, u16); u16 (*read_rap) (unsigned long); void (*write_rap) (unsigned long, u16); void (*reset) (unsigned long);}; /* * The first field of pcnet32_private is read by the ethernet device * so the structure should be allocated using pci_alloc_consistent(). */struct pcnet32_private { struct pcnet32_init_block init_block; /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ struct pcnet32_rx_head *rx_ring; struct pcnet32_tx_head *tx_ring; dma_addr_t dma_addr;/* DMA address of beginning of this object, returned by pci_alloc_consistent */ struct pci_dev *pci_dev; const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff **tx_skbuff; struct sk_buff **rx_skbuff; dma_addr_t *tx_dma_addr; dma_addr_t *rx_dma_addr; struct pcnet32_access a; spinlock_t lock; /* Guard lock */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int rx_ring_size; /* current rx ring size */ unsigned int tx_ring_size; /* current tx ring size */ unsigned int rx_mod_mask; /* rx ring modular mask */ unsigned int tx_mod_mask; /* tx ring modular mask */ unsigned short rx_len_bits; unsigned short tx_len_bits; dma_addr_t rx_ring_dma_addr; dma_addr_t tx_ring_dma_addr; unsigned int dirty_rx, /* ring entries to be freed. */ dirty_tx; struct net_device_stats stats; char tx_full; char phycount; /* number of phys found */ int options; unsigned int shared_irq:1, /* shared irq possible */ dxsuflo:1, /* disable transmit stop on uflo */ mii:1; /* mii port available */ struct net_device *next; struct mii_if_info mii_if; struct timer_list watchdog_timer; struct timer_list blink_timer; u32 msg_enable; /* debug message level */ /* each bit indicates an available PHY */ u32 phymask;}; static void pcnet32_probe_vlbus(void);static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);static int pcnet32_probe1(unsigned long, int, struct pci_dev *);static int pcnet32_open(struct net_device *);static int pcnet32_init_ring(struct net_device *);static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);static int pcnet32_rx(struct net_device *);static void pcnet32_tx_timeout(struct net_device *dev);static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);static int pcnet32_close(struct net_device *);static struct net_device_stats *pcnet32_get_stats(struct net_device *);static void pcnet32_load_multicast(struct net_device *dev);static void pcnet32_set_multicast_list(struct net_device *);static int pcnet32_ioctl(struct net_device *, struct ifreq *, int);static void pcnet32_watchdog(struct net_device *);static int mdio_read(struct net_device *dev, int phy_id, int reg_num);static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val);static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits);static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *eth_test, u64 * data);static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1);static int pcnet32_phys_id(struct net_device *dev, u32 data);static void pcnet32_led_blink_callback(struct net_device *dev);static int pcnet32_get_regs_len(struct net_device *dev);static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr);static void pcnet32_purge_tx_ring(struct net_device *dev);static int pcnet32_alloc_ring(struct net_device *dev, char *name);static void pcnet32_free_ring(struct net_device *dev);static void pcnet32_check_media(struct net_device *dev, int verbose); enum pci_flags_bit { PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 = 0x10 << 2, PCI_ADDR3 = 0x10 << 3,}; static u16 pcnet32_wio_read_csr(unsigned long addr, int index){ outw(index, addr + PCNET32_WIO_RAP); return inw(addr + PCNET32_WIO_RDP);} static void pcnet32_wio_write_csr(unsigned long addr, int index, u16 val){ outw(index, addr + PCNET32_WIO_RAP); outw(val, addr + PCNET32_WIO_RDP);} static u16 pcnet32_wio_read_bcr(unsigned long addr, int index){ outw(index, addr + PCNET32_WIO_RAP); return inw(addr + PCNET32_WIO_BDP);} static void pcnet32_wio_write_bcr(unsigned long addr, int index, u16 val){ outw(index, addr + PCNET32_WIO_RAP); outw(val, addr + PCNET32_WIO_BDP);} static u16 pcnet32_wio_read_rap(unsigned long addr){ return inw(addr + PCNET32_WIO_RAP);} static void pcnet32_wio_write_rap(unsigned long addr, u16 val){ outw(val, addr + PCNET32_WIO_RAP);} static void pcnet32_wio_reset(unsigned long addr){ inw(addr + PCNET32_WIO_RESET);} static int pcnet32_wio_check(unsigned long addr){ outw(88, addr + PCNET32_WIO_RAP); return (inw(addr + PCNET32_WIO_RAP) == 88);} static struct pcnet32_access pcnet32_wio = { .read_csr = pcnet32_wio_read_csr, .write_csr = pcnet32_wio_write_csr, .read_bcr = pcnet32_wio_read_bcr, .write_bcr = pcnet32_wio_write_bcr, .read_rap = pcnet32_wio_read_rap, .write_rap = pcnet32_wio_write_rap, .reset = pcnet32_wio_reset}; static u16 pcnet32_dwio_read_csr(unsigned long addr, int index){ outl(index, addr + PCNET32_DWIO_RAP); return (inl(addr + PCNET32_DWIO_RDP) & 0xffff);} static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val){ outl(index, addr + PCNET32_DWIO_RAP); outl(val, addr + PCNET32_DWIO_RDP);} static u16 pcnet32_dwio_read_bcr(unsigned long addr, int index){ outl(index, addr + PCNET32_DWIO_RAP); return (inl(addr + PCNET32_DWIO_BDP) & 0xffff);} static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val){ outl(index, addr + PCNET32_DWIO_RAP); outl(val, addr + PCNET32_DWIO_BDP);} static u16 pcnet32_dwio_read_rap(unsigned long addr){ return (inl(addr + PCNET32_DWIO_RAP) & 0xffff);} static void pcnet32_dwio_write_rap(unsigned long addr, u16 val){ outl(val, addr + PCNET32_DWIO_RAP);} static void pcnet32_dwio_reset(unsigned long addr){ inl(addr + PCNET32_DWIO_RESET);} static int pcnet32_dwio_check(unsigned long addr){ outl(88, addr + PCNET32_DWIO_RAP); return ((inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88);} static struct pcnet32_access pcnet32_dwio = { .read_csr = pcnet32_dwio_read_csr, .write_csr = pcnet32_dwio_write_csr, .read_bcr = pcnet32_dwio_read_bcr, .write_bcr = pcnet32_dwio_write_bcr, .read_rap = pcnet32_dwio_read_rap, .write_rap = pcnet32_dwio_write_rap, .reset = pcnet32_dwio_reset}; #ifdef CONFIG_NET_POLL_CONTROLLERstatic void pcnet32_poll_controller(struct net_device *dev){ disable_irq(dev->irq); pcnet32_interrupt(0, dev, NULL); enable_irq(dev->irq);}#endif static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); mii_ethtool_gset(&lp->mii_if, cmd); spin_unlock_irqrestore(&lp->lock, flags); r = 0; } return r;} static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); r = mii_ethtool_sset(&lp->mii_if, cmd); spin_unlock_irqrestore(&lp->lock, flags); } return r;} static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct pcnet32_private *lp = dev->priv; strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); if (lp->pci_dev) strcpy(info->bus_info, pci_name(lp->pci_dev)); else sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr);} static u32 pcnet32_get_link(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; unsigned long flags; int r; spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { r = mii_link_ok(&lp->mii_if); } else { ulong ioaddr = dev->base_addr; /* card base I/O address */ r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); } spin_unlock_irqrestore(&lp->lock, flags); return r;} static u32 pcnet32_get_msglevel(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; return lp->msg_enable;Lines 1–500 of 2774. Load more
/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */ /* * Copyright 1996-1999 Thomas Bogendoerfer * * Derived from the lance driver written 1993,1994,1995 by Donald Becker. * * Copyright 1993 United States Government as represented by the * Director, National Security Agency. * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * * This driver is for PCnet32 and PCnetPCI based ethercards */ /************************************************************************** * 23 Oct, 2000. * Fixed a few bugs, related to running the controller in 32bit mode. * * Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. * *************************************************************************/ #define DRV_NAME "pcnet32" #define DRV_VERSION "1.32" #define DRV_RELDATE "18.Mar.2006" #define PFX DRV_NAME ": " static const char *const version = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/crc32.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/moduleparam.h> #include <linux/bitops.h> #include <asm/dma.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/irq.h> /* * PCI device identifiers for "new style" Linux PCI Device Drivers */ static struct pci_device_id pcnet32_pci_tbl[] = { { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* * Adapters that were sold with IBM's RS/6000 or pSeries hardware have * the incorrect vendor id. */ { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0}, { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, pcnet32_pci_tbl); static int cards_found; /* * VLB I/O addresses */ static unsigned int pcnet32_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0 }; static int pcnet32_debug = 0; static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ static int pcnet32vlb; /* check for VLB cards ? */ static struct net_device *pcnet32_dev; static int max_interrupt_work = 2; static int rx_copybreak = 200; #define PCNET32_PORT_AUI 0x00 #define PCNET32_PORT_10BT 0x01 #define PCNET32_PORT_GPSI 0x02 #define PCNET32_PORT_MII 0x03 #define PCNET32_PORT_PORTSEL 0x03 #define PCNET32_PORT_ASEL 0x04 #define PCNET32_PORT_100 0x40 #define PCNET32_PORT_FD 0x80 #define PCNET32_DMA_MASK 0xffffffff #define PCNET32_WATCHDOG_TIMEOUT (jiffies + (2 * HZ)) #define PCNET32_BLINK_TIMEOUT (jiffies + (HZ/4)) /* * table to translate option values from tulip * to internal options */ static const unsigned char options_mapping[] = { PCNET32_PORT_ASEL, /* 0 Auto-select */ PCNET32_PORT_AUI, /* 1 BNC/AUI */ PCNET32_PORT_AUI, /* 2 AUI/BNC */ PCNET32_PORT_ASEL, /* 3 not supported */ PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ PCNET32_PORT_ASEL, /* 5 not supported */ PCNET32_PORT_ASEL, /* 6 not supported */ PCNET32_PORT_ASEL, /* 7 not supported */ PCNET32_PORT_ASEL, /* 8 not supported */ PCNET32_PORT_MII, /* 9 MII 10baseT */ PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ PCNET32_PORT_MII, /* 11 MII (autosel) */ PCNET32_PORT_10BT, /* 12 10BaseT */ PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ /* 14 MII 100BaseTx-FD */ PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, PCNET32_PORT_ASEL /* 15 not supported */ }; static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { "Loopback test (offline)" }; #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) #define PCNET32_NUM_REGS 136 #define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; static int homepna[MAX_UNITS]; /* * Theory of Operation * * This driver uses the same software structure as the normal lance * driver. So look for a verbose description in lance.c. The differences * to the normal lance driver is the use of the 32bit mode of PCnet32 * and PCnetPCI chips. Because these chips are 32bit chips, there is no * 16MB limitation and we don't need bounce buffers. */ /* * Set the number of Tx and Rx buffers, using Log_2(# buffers). * Reasonable default values are 4 Tx buffers, and 16 Rx buffers. * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */ #ifndef PCNET32_LOG_TX_BUFFERS #define PCNET32_LOG_TX_BUFFERS 4 #define PCNET32_LOG_RX_BUFFERS 5 #define PCNET32_LOG_MAX_TX_BUFFERS 9 /* 2^9 == 512 */ #define PCNET32_LOG_MAX_RX_BUFFERS 9 #endif #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) #define TX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_TX_BUFFERS)) #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) #define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS)) #define PKT_BUF_SZ 1544 /* Offsets from base I/O address. */ #define PCNET32_WIO_RDP 0x10 #define PCNET32_WIO_RAP 0x12 #define PCNET32_WIO_RESET 0x14 #define PCNET32_WIO_BDP 0x16 #define PCNET32_DWIO_RDP 0x10 #define PCNET32_DWIO_RAP 0x14 #define PCNET32_DWIO_RESET 0x18 #define PCNET32_DWIO_BDP 0x1C #define PCNET32_TOTAL_SIZE 0x20 /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { u32 base; s16 buf_length; s16 status; u32 msg_length; u32 reserved; }; struct pcnet32_tx_head { u32 base; s16 length; s16 status; u32 misc; u32 reserved; }; /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { u16 mode; u16 tlen_rlen; u8 phys_addr[6]; u16 reserved; u32 filter[2]; /* Receive and transmit ring base, along with extra bits. */ u32 rx_ring; u32 tx_ring; }; /* PCnet32 access functions */ struct pcnet32_access { u16 (*read_csr) (unsigned long, int); void (*write_csr) (unsigned long, int, u16); u16 (*read_bcr) (unsigned long, int); void (*write_bcr) (unsigned long, int, u16); u16 (*read_rap) (unsigned long); void (*write_rap) (unsigned long, u16); void (*reset) (unsigned long); }; /* * The first field of pcnet32_private is read by the ethernet device * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { struct pcnet32_init_block init_block; /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ struct pcnet32_rx_head *rx_ring; struct pcnet32_tx_head *tx_ring; dma_addr_t dma_addr;/* DMA address of beginning of this object, returned by pci_alloc_consistent */ struct pci_dev *pci_dev; const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff **tx_skbuff; struct sk_buff **rx_skbuff; dma_addr_t *tx_dma_addr; dma_addr_t *rx_dma_addr; struct pcnet32_access a; spinlock_t lock; /* Guard lock */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int rx_ring_size; /* current rx ring size */ unsigned int tx_ring_size; /* current tx ring size */ unsigned int rx_mod_mask; /* rx ring modular mask */ unsigned int tx_mod_mask; /* tx ring modular mask */ unsigned short rx_len_bits; unsigned short tx_len_bits; dma_addr_t rx_ring_dma_addr; dma_addr_t tx_ring_dma_addr; unsigned int dirty_rx, /* ring entries to be freed. */ dirty_tx; struct net_device_stats stats; char tx_full; char phycount; /* number of phys found */ int options; unsigned int shared_irq:1, /* shared irq possible */ dxsuflo:1, /* disable transmit stop on uflo */ mii:1; /* mii port available */ struct net_device *next; struct mii_if_info mii_if; struct timer_list watchdog_timer; struct timer_list blink_timer; u32 msg_enable; /* debug message level */ /* each bit indicates an available PHY */ u32 phymask; }; static void pcnet32_probe_vlbus(void); static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); static int pcnet32_probe1(unsigned long, int, struct pci_dev *); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); static int pcnet32_rx(struct net_device *); static void pcnet32_tx_timeout(struct net_device *dev); static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *); static int pcnet32_close(struct net_device *); static struct net_device_stats *pcnet32_get_stats(struct net_device *); static void pcnet32_load_multicast(struct net_device *dev); static void pcnet32_set_multicast_list(struct net_device *); static int pcnet32_ioctl(struct net_device *, struct ifreq *, int); static void pcnet32_watchdog(struct net_device *); static int mdio_read(struct net_device *dev, int phy_id, int reg_num); static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val); static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits); static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *eth_test, u64 * data); static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1); static int pcnet32_phys_id(struct net_device *dev, u32 data); static void pcnet32_led_blink_callback(struct net_device *dev); static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *ptr); static void pcnet32_purge_tx_ring(struct net_device *dev); static int pcnet32_alloc_ring(struct net_device *dev, char *name); static void pcnet32_free_ring(struct net_device *dev); static void pcnet32_check_media(struct net_device *dev, int verbose); enum pci_flags_bit { PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 = 0x10 << 2, PCI_ADDR3 = 0x10 << 3, }; static u16 pcnet32_wio_read_csr(unsigned long addr, int index) { outw(index, addr + PCNET32_WIO_RAP); return inw(addr + PCNET32_WIO_RDP); } static void pcnet32_wio_write_csr(unsigned long addr, int index, u16 val) { outw(index, addr + PCNET32_WIO_RAP); outw(val, addr + PCNET32_WIO_RDP); } static u16 pcnet32_wio_read_bcr(unsigned long addr, int index) { outw(index, addr + PCNET32_WIO_RAP); return inw(addr + PCNET32_WIO_BDP); } static void pcnet32_wio_write_bcr(unsigned long addr, int index, u16 val) { outw(index, addr + PCNET32_WIO_RAP); outw(val, addr + PCNET32_WIO_BDP); } static u16 pcnet32_wio_read_rap(unsigned long addr) { return inw(addr + PCNET32_WIO_RAP); } static void pcnet32_wio_write_rap(unsigned long addr, u16 val) { outw(val, addr + PCNET32_WIO_RAP); } static void pcnet32_wio_reset(unsigned long addr) { inw(addr + PCNET32_WIO_RESET); } static int pcnet32_wio_check(unsigned long addr) { outw(88, addr + PCNET32_WIO_RAP); return (inw(addr + PCNET32_WIO_RAP) == 88); } static struct pcnet32_access pcnet32_wio = { .read_csr = pcnet32_wio_read_csr, .write_csr = pcnet32_wio_write_csr, .read_bcr = pcnet32_wio_read_bcr, .write_bcr = pcnet32_wio_write_bcr, .read_rap = pcnet32_wio_read_rap, .write_rap = pcnet32_wio_write_rap, .reset = pcnet32_wio_reset }; static u16 pcnet32_dwio_read_csr(unsigned long addr, int index) { outl(index, addr + PCNET32_DWIO_RAP); return (inl(addr + PCNET32_DWIO_RDP) & 0xffff); } static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val) { outl(index, addr + PCNET32_DWIO_RAP); outl(val, addr + PCNET32_DWIO_RDP); } static u16 pcnet32_dwio_read_bcr(unsigned long addr, int index) { outl(index, addr + PCNET32_DWIO_RAP); return (inl(addr + PCNET32_DWIO_BDP) & 0xffff); } static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val) { outl(index, addr + PCNET32_DWIO_RAP); outl(val, addr + PCNET32_DWIO_BDP); } static u16 pcnet32_dwio_read_rap(unsigned long addr) { return (inl(addr + PCNET32_DWIO_RAP) & 0xffff); } static void pcnet32_dwio_write_rap(unsigned long addr, u16 val) { outl(val, addr + PCNET32_DWIO_RAP); } static void pcnet32_dwio_reset(unsigned long addr) { inl(addr + PCNET32_DWIO_RESET); } static int pcnet32_dwio_check(unsigned long addr) { outl(88, addr + PCNET32_DWIO_RAP); return ((inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88); } static struct pcnet32_access pcnet32_dwio = { .read_csr = pcnet32_dwio_read_csr, .write_csr = pcnet32_dwio_write_csr, .read_bcr = pcnet32_dwio_read_bcr, .write_bcr = pcnet32_dwio_write_bcr, .read_rap = pcnet32_dwio_read_rap, .write_rap = pcnet32_dwio_write_rap, .reset = pcnet32_dwio_reset }; #ifdef CONFIG_NET_POLL_CONTROLLER static void pcnet32_poll_controller(struct net_device *dev) { disable_irq(dev->irq); pcnet32_interrupt(0, dev, NULL); enable_irq(dev->irq); } #endif static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); mii_ethtool_gset(&lp->mii_if, cmd); spin_unlock_irqrestore(&lp->lock, flags); r = 0; } return r; } static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct pcnet32_private *lp = dev->priv; unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); r = mii_ethtool_sset(&lp->mii_if, cmd); spin_unlock_irqrestore(&lp->lock, flags); } return r; } static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct pcnet32_private *lp = dev->priv; strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); if (lp->pci_dev) strcpy(info->bus_info, pci_name(lp->pci_dev)); else sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr); } static u32 pcnet32_get_link(struct net_device *dev) { struct pcnet32_private *lp = dev->priv; unsigned long flags; int r; spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { r = mii_link_ok(&lp->mii_if); } else { ulong ioaddr = dev->base_addr; /* card base I/O address */ r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); } spin_unlock_irqrestore(&lp->lock, flags); return r; } static u32 pcnet32_get_msglevel(struct net_device *dev) { struct pcnet32_private *lp = dev->priv; return lp->msg_enable;