pcnet32.c
来自「linux 内核源代码」· C语言 代码 · 共 2,361 行 · 第 1/5 页
C
2,361 行
/* 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"#ifdef CONFIG_PCNET32_NAPI#define DRV_VERSION "1.34-NAPI"#else#define DRV_VERSION "1.34"#endif#define DRV_RELDATE "14.Aug.2007"#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_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), }, /* * Adapters that were sold with IBM's RS/6000 or pSeries hardware have * the incorrect vendor id. */ { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE), .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, }, { } /* 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#define CSR0 0#define CSR0_INIT 0x1#define CSR0_START 0x2#define CSR0_STOP 0x4#define CSR0_TXPOLL 0x8#define CSR0_INTEN 0x40#define CSR0_IDON 0x0100#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)#define PCNET32_INIT_LOW 1#define PCNET32_INIT_HIGH 2#define CSR3 3#define CSR4 4#define CSR5 5#define CSR5_SUSPEND 0x0001#define CSR15 15#define PCNET32_MC_FILTER 8#define PCNET32_79C970A 0x2621/* The PCNET32 Rx and Tx ring descriptors. */struct pcnet32_rx_head { __le32 base; __le16 buf_length; /* two`s complement of length */ __le16 status; __le32 msg_length; __le32 reserved;};struct pcnet32_tx_head { __le32 base; __le16 length; /* two`s complement of length */ __le16 status; __le32 misc; __le32 reserved;};/* The PCNET32 32-Bit initialization block, described in databook. */struct pcnet32_init_block { __le16 mode; __le16 tlen_rlen; u8 phys_addr[6]; __le16 reserved; __le32 filter[2]; /* Receive and transmit ring base, along with extra bits. */ __le32 rx_ring; __le32 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 init_dma_addr;/* DMA address of beginning of the init block, 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 *dev; struct napi_struct napi; 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; unsigned short chip_version; /* which variant this is */};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 void pcnet32_tx_timeout(struct net_device *dev);static irqreturn_t pcnet32_interrupt(int, void *);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);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};static void pcnet32_netif_stop(struct net_device *dev){#ifdef CONFIG_PCNET32_NAPI struct pcnet32_private *lp = netdev_priv(dev);#endif dev->trans_start = jiffies;#ifdef CONFIG_PCNET32_NAPI napi_disable(&lp->napi);#endif netif_tx_disable(dev);}static void pcnet32_netif_start(struct net_device *dev){#ifdef CONFIG_PCNET32_NAPI struct pcnet32_private *lp = netdev_priv(dev); ulong ioaddr = dev->base_addr; u16 val;#endif netif_wake_queue(dev);#ifdef CONFIG_PCNET32_NAPI val = lp->a.read_csr(ioaddr, CSR3); val &= 0x00ff; lp->a.write_csr(ioaddr, CSR3, val); napi_enable(&lp->napi);#endif}/* * Allocate space for the new sized tx ring. * Free old resources * Save new resources.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?