/* winbond-840.c: A Linux PCI network adapter device driver. */ /* Written 1998-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this code fall under the GPL and must retain the authorship, copyright and license notice. This file is not a complete program and may only be used when the entire operating system is licensed under the GPL. The author may be reached as [email protected], or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 Annapolis MD 21403 Support and updates available at http://www.scyld.com/network/drivers.html Do not remove the copyright information. Do not change the version information unless an improvement has been made. Merely removing my name, as Compex has done in the past, does not count as an improvement. Changelog: * ported to 2.4 ??? * spin lock update, memory barriers, new style dma mappings limit each tx buffer to < 1024 bytes remove DescIntr from Rx descriptors (that's an Tx flag) remove next pointer from Tx descriptors synchronize tx_q_bytes software reset in tx_timeout Copyright (C) 2000 Manfred Spraul * further cleanups power management. support for big endian descriptors Copyright (C) 2001 Manfred Spraul * ethtool support (jgarzik) * Replace some MII-related magic numbers with constants (jgarzik) TODO: * enable pci_power_off * Wake-On-LAN */ #define pr_fmt(fmt) … #define DRV_NAME … /* Automatically extracted configuration info: probe-func: winbond840_probe config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 c-help-name: Winbond W89c840 PCI Ethernet support c-help-symbol: CONFIG_WINBOND_840 c-help: This driver is for the Winbond W89c840 chip. It also works with c-help: the TX9882 chip on the Compex RL100-ATX board. c-help: More specific information and updates are available from c-help: http://www.scyld.com/network/drivers.html */ /* The user-configurable values. These may be modified when a driver module is loaded.*/ static int debug = …; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = …; /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The '840 uses a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = …; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver interoperability. The media type is usually passed in 'options[]'. */ #define MAX_UNITS … static int options[MAX_UNITS] = …; static int full_duplex[MAX_UNITS] = …; /* Operational parameters that are set at compile time. */ /* Keep the ring sizes a power of two for compile efficiency. The compiler will convert <unsigned>'%'<2^N> into a bit mask. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_QUEUE_LEN … #define TX_QUEUE_LEN_RESTART … #define TX_BUFLIMIT … /* The presumed FIFO size for working around the Tx-FIFO-overflow bug. To avoid overflowing we don't queue again until we have room for a full-size packet. */ #define TX_FIFO_SIZE … #define TX_BUG_FIFO_LIMIT … /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT … /* Include files, designed to support most kernel versions 2.0.0 and later. */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/ethtool.h> #include <linux/mii.h> #include <linux/rtnetlink.h> #include <linux/crc32.h> #include <linux/bitops.h> #include <linux/uaccess.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/io.h> #include <asm/irq.h> #include "tulip.h" #undef PKT_BUF_SZ /* tulip.h also defines this */ #define PKT_BUF_SZ … MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; module_param(max_interrupt_work, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); module_param(multicast_filter_limit, int, 0); module_param_array(…); module_param_array(…); MODULE_PARM_DESC(…) …; MODULE_PARM_DESC(…) …; MODULE_PARM_DESC(…) …; MODULE_PARM_DESC(…) …; MODULE_PARM_DESC(…) …; MODULE_PARM_DESC(…) …; /* Theory of Operation I. Board Compatibility This driver is for the Winbond w89c840 chip. II. Board-specific settings None. III. Driver operation This chip is very similar to the Digital 21*4* "Tulip" family. The first twelve registers and the descriptor format are nearly identical. Read a Tulip manual for operational details. A significant difference is that the multicast filter and station address are stored in registers rather than loaded through a pseudo-transmit packet. Unlike the Tulip, transmit buffers are limited to 1KB. To transmit a full-sized packet we must use both data buffers in a descriptor. Thus the driver uses ring mode where descriptors are implicitly sequential in memory, rather than using the second descriptor address as a chain pointer to subsequent descriptors. IV. Notes If you are going to almost clone a Tulip, why not go all the way and avoid the need for a new driver? IVb. References http://www.scyld.com/expert/100mbps.html http://www.scyld.com/expert/NWay.html http://www.winbond.com.tw/ IVc. Errata A horrible bug exists in the transmit FIFO. Apparently the chip doesn't correctly detect a full FIFO, and queuing more than 2048 bytes may result in silent data corruption. Test with 'ping -s 10000' on a fast computer. */ /* PCI probe table. */ enum chip_capability_flags { … }; static const struct pci_device_id w840_pci_tbl[] = …; MODULE_DEVICE_TABLE(pci, w840_pci_tbl); enum { … }; struct pci_id_info { … }; static const struct pci_id_info pci_id_tbl[] = …; /* This driver was written to use PCI memory space, however some x86 systems work only with I/O space accesses. See CONFIG_TULIP_MMIO in .config */ /* Offsets to the Command and Status Registers, "CSRs". While similar to the Tulip, these registers are longword aligned. Note: It's not useful to define symbolic names for every register bit in the device. The name can only partially document the semantics and make the driver longer and more difficult to read. */ enum w840_offsets { … }; /* Bits in the NetworkConfig register. */ enum rx_mode_bits { … }; enum mii_reg_bits { … }; /* The Tulip Rx and Tx buffer descriptors. */ struct w840_rx_desc { … }; struct w840_tx_desc { … }; #define MII_CNT … struct netdev_private { … }; static int eeprom_read(void __iomem *ioaddr, int location); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); static int update_link(struct net_device *dev); static void netdev_timer(struct timer_list *t); static void init_rxtx_rings(struct net_device *dev); static void free_rxtx_rings(struct netdev_private *np); static void init_registers(struct net_device *dev); static void tx_timeout(struct net_device *dev, unsigned int txqueue); static int alloc_ringdesc(struct net_device *dev); static void free_ringdesc(struct netdev_private *np); static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); static u32 __set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; static int netdev_close(struct net_device *dev); static const struct net_device_ops netdev_ops = …; static int w840_probe1(struct pci_dev *pdev, const struct pci_device_id *ent) { … } /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are often serial bit streams generated by the host processor. The example below is for the common 93c46 EEPROM, 64 16 bit words. */ /* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that made udelay() unreliable. */ #define eeprom_delay(ee_addr) … enum EEPROM_Ctrl_Bits { … }; /* The EEPROM commands include the alway-set leading bit. */ enum EEPROM_Cmds { … }; static int eeprom_read(void __iomem *addr, int location) { … } /* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back 33Mhz PCI cycles. */ #define mdio_delay(mdio_addr) … /* Set iff a MII transceiver on any interface requires mdio preamble. This only set with older transceivers, so the extra code size of a per-interface flag is not worthwhile. */ static char mii_preamble_required = …; #define MDIO_WRITE0 … #define MDIO_WRITE1 … /* Generate the preamble required for initial synchronization and a few older transceivers. */ static void mdio_sync(void __iomem *mdio_addr) { … } static int mdio_read(struct net_device *dev, int phy_id, int location) { … } static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { … } static int netdev_open(struct net_device *dev) { … } #define MII_DAVICOM_DM9101 … static int update_link(struct net_device *dev) { … } #define RXTX_TIMEOUT … static inline void update_csr6(struct net_device *dev, int new) { … } static void netdev_timer(struct timer_list *t) { … } static void init_rxtx_rings(struct net_device *dev) { … } static void free_rxtx_rings(struct netdev_private* np) { … } static void init_registers(struct net_device *dev) { … } static void tx_timeout(struct net_device *dev, unsigned int txqueue) { … } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static int alloc_ringdesc(struct net_device *dev) { … } static void free_ringdesc(struct netdev_private *np) { … } static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { … } static void netdev_tx_done(struct net_device *dev) { … } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t intr_handler(int irq, void *dev_instance) { … } /* This routine is logically part of the interrupt handler, but separated for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { … } static void netdev_error(struct net_device *dev, int intr_status) { … } static struct net_device_stats *get_stats(struct net_device *dev) { … } static u32 __set_rx_mode(struct net_device *dev) { … } static void set_rx_mode(struct net_device *dev) { … } static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { … } static int netdev_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { … } static int netdev_set_link_ksettings(struct net_device *dev, const struct ethtool_link_ksettings *cmd) { … } static int netdev_nway_reset(struct net_device *dev) { … } static u32 netdev_get_link(struct net_device *dev) { … } static u32 netdev_get_msglevel(struct net_device *dev) { … } static void netdev_set_msglevel(struct net_device *dev, u32 value) { … } static const struct ethtool_ops netdev_ethtool_ops = …; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { … } static int netdev_close(struct net_device *dev) { … } static void w840_remove1(struct pci_dev *pdev) { … } /* * suspend/resume synchronization: * - open, close, do_ioctl: * rtnl_lock, & netif_device_detach after the rtnl_unlock. * - get_stats: * spin_lock_irq(np->lock), doesn't touch hw if not present * - start_xmit: * synchronize_irq + netif_tx_disable; * - tx_timeout: * netif_device_detach + netif_tx_disable; * - set_multicast_list * netif_device_detach + netif_tx_disable; * - interrupt handler * doesn't touch hw if not present, synchronize_irq waits for * running instances of the interrupt handler. * * Disabling hw requires clearing csr6 & IntrEnable. * update_csr6 & all function that write IntrEnable check netif_device_present * before settings any bits. * * Detach must occur under spin_unlock_irq(), interrupts from a detached * device would cause an irq storm. */ static int __maybe_unused w840_suspend(struct device *dev_d) { … } static int __maybe_unused w840_resume(struct device *dev_d) { … } static SIMPLE_DEV_PM_OPS(w840_pm_ops, w840_suspend, w840_resume); static struct pci_driver w840_driver = …; module_pci_driver(…) …;