sis900.c
来自「linux 内核源代码」· C语言 代码 · 共 2,188 行 · 第 1/5 页
C
2,188 行
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation Revision: 1.08.10 Apr. 2 2006 Modified from the driver which is originally written 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 this skeleton fall under the GPL and must retain the authorship (implicit copyright) notice. References: SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support, preliminary Rev. 1.0 Jan. 14, 1998 SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support, preliminary Rev. 1.0 Nov. 10, 1998 SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, preliminary Rev. 1.0 Jan. 18, 1998 Rev 1.08.10 Apr. 2 2006 Daniele Venzano add vlan (jumbo packets) support Rev 1.08.09 Sep. 19 2005 Daniele Venzano add Wake on LAN support Rev 1.08.08 Jan. 22 2005 Daniele Venzano use netif_msg for debugging messages Rev 1.08.07 Nov. 2 2003 Daniele Venzano <venza@brownhat.org> add suspend/resume support Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support Rev 1.08.05 Jun. 6 2002 Mufasa Yang bug fix for read_eeprom & Tx descriptor over-boundary Rev 1.08.04 Apr. 25 2002 Mufasa Yang <mufasa@sis.com.tw> added SiS962 support Rev 1.08.03 Feb. 1 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3 Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support Rev 1.07.09 Feb. 9 2001 Dave Jones <davej@suse.de> PCI enable cleanup Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix Rev 1.07.06 Nov. 7 2000 Jeff Garzik <jgarzik@pobox.com> some bug fix and cleaning Rev 1.07.05 Nov. 6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaround rule Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1 Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@pobox.com> softnet and init for kernel 2.4 Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com) Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release*/#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/init.h>#include <linux/mii.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/ethtool.h>#include <linux/crc32.h>#include <linux/bitops.h>#include <linux/dma-mapping.h>#include <asm/processor.h> /* Processor type for cache alignment. */#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h> /* User space memory access functions */#include "sis900.h"#define SIS900_MODULE_NAME "sis900"#define SIS900_DRV_VERSION "v1.08.10 Apr. 2 2006"static char version[] __devinitdata =KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";static int max_interrupt_work = 40;static int multicast_filter_limit = 128;static int sis900_debug = -1; /* Use SIS900_DEF_MSG as value */#define SIS900_DEF_MSG \ (NETIF_MSG_DRV | \ NETIF_MSG_LINK | \ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR)/* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT (4*HZ)enum { SIS_900 = 0, SIS_7016};static const char * card_names[] = { "SiS 900 PCI Fast Ethernet", "SiS 7016 PCI Fast Ethernet"};static struct pci_device_id sis900_pci_tbl [] = { {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900}, {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7016}, {0,}};MODULE_DEVICE_TABLE (pci, sis900_pci_tbl);static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex);static const struct mii_chip_info { const char * name; u16 phy_id0; u16 phy_id1; u8 phy_types;#define HOME 0x0001#define LAN 0x0002#define MIX 0x0003#define UNKNOWN 0x0} mii_chip_table[] = { { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, { "SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, LAN }, { "Altimata AC101LF PHY", 0x0022, 0x5520, LAN }, { "ADM 7001 LAN PHY", 0x002e, 0xcc60, LAN }, { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, { "ICS LAN PHY", 0x0015, 0xF440, LAN }, { "ICS LAN PHY", 0x0143, 0xBC70, LAN }, { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, { "NS 83847 PHY", 0x2000, 0x5C30, MIX }, { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN }, { "VIA 6103 PHY", 0x0101, 0x8f20, LAN }, {NULL,},};struct mii_phy { struct mii_phy * next; int phy_addr; u16 phy_id0; u16 phy_id1; u16 status; u8 phy_types;};typedef struct _BufferDesc { u32 link; u32 cmdsts; u32 bufptr;} BufferDesc;struct sis900_private { struct pci_dev * pci_dev; spinlock_t lock; struct mii_phy * mii; struct mii_phy * first_mii; /* record the first mii structure */ unsigned int cur_phy; struct mii_if_info mii_info; struct timer_list timer; /* Link status detection timer. */ u8 autong_complete; /* 1: auto-negotiate complete */ u32 msg_enable; unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ unsigned int cur_tx, dirty_tx; /* The saved address of a sent/receive-in-place packet buffer */ struct sk_buff *tx_skbuff[NUM_TX_DESC]; struct sk_buff *rx_skbuff[NUM_RX_DESC]; BufferDesc *tx_ring; BufferDesc *rx_ring; dma_addr_t tx_ring_dma; dma_addr_t rx_ring_dma; unsigned int tx_full; /* The Tx queue is full. */ u8 host_bridge_rev; u8 chipset_rev;};MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver");MODULE_LICENSE("GPL");module_param(multicast_filter_limit, int, 0444);module_param(max_interrupt_work, int, 0444);module_param(sis900_debug, int, 0444);MODULE_PARM_DESC(multicast_filter_limit, "SiS 900/7016 maximum number of filtered multicast addresses");MODULE_PARM_DESC(max_interrupt_work, "SiS 900/7016 maximum events handled per interrupt");MODULE_PARM_DESC(sis900_debug, "SiS 900/7016 bitmapped debugging message level");#ifdef CONFIG_NET_POLL_CONTROLLERstatic void sis900_poll(struct net_device *dev);#endifstatic int sis900_open(struct net_device *net_dev);static int sis900_mii_probe (struct net_device * net_dev);static void sis900_init_rxfilter (struct net_device * net_dev);static u16 read_eeprom(long ioaddr, int location);static int mdio_read(struct net_device *net_dev, int phy_id, int location);static void mdio_write(struct net_device *net_dev, int phy_id, int location, int val);static void sis900_timer(unsigned long data);static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy);static void sis900_tx_timeout(struct net_device *net_dev);static void sis900_init_tx_ring(struct net_device *net_dev);static void sis900_init_rx_ring(struct net_device *net_dev);static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev);static int sis900_rx(struct net_device *net_dev);static void sis900_finish_xmit (struct net_device *net_dev);static irqreturn_t sis900_interrupt(int irq, void *dev_instance);static int sis900_close(struct net_device *net_dev);static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);static u16 sis900_mcast_bitnr(u8 *addr, u8 revision);static void set_rx_mode(struct net_device *net_dev);static void sis900_reset(struct net_device *net_dev);static void sis630_set_eq(struct net_device *net_dev, u8 revision);static int sis900_set_config(struct net_device *dev, struct ifmap *map);static u16 sis900_default_phy(struct net_device * net_dev);static void sis900_set_capability( struct net_device *net_dev ,struct mii_phy *phy);static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr);static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr);static void sis900_set_mode (long ioaddr, int speed, int duplex);static const struct ethtool_ops sis900_ethtool_ops;/** * sis900_get_mac_addr - Get MAC address for stand alone SiS900 model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * * Older SiS900 and friends, use EEPROM to store MAC address. * MAC address is read from read_eeprom() into @net_dev->dev_addr. */static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev){ long ioaddr = pci_resource_start(pci_dev, 0); u16 signature; int i; /* check to see if we have sane EEPROM */ signature = (u16) read_eeprom(ioaddr, EEPROMSignature); if (signature == 0xffff || signature == 0x0000) { printk (KERN_WARNING "%s: Error EERPOM read %x\n", pci_name(pci_dev), signature); return 0; } /* get MAC address from EEPROM */ for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); return 1;}/** * sis630e_get_mac_addr - Get MAC address for SiS630E model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * * SiS630E model, use APC CMOS RAM to store MAC address. * APC CMOS RAM is accessed through ISA bridge. * MAC address is read into @net_dev->dev_addr. */static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev){ struct pci_dev *isa_bridge = NULL; u8 reg; int i; isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, isa_bridge); if (!isa_bridge) isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge); if (!isa_bridge) { printk(KERN_WARNING "%s: Can not find ISA bridge\n", pci_name(pci_dev)); return 0; } pci_read_config_byte(isa_bridge, 0x48, ®); pci_write_config_byte(isa_bridge, 0x48, reg | 0x40); for (i = 0; i < 6; i++) { outb(0x09 + i, 0x70); ((u8 *)(net_dev->dev_addr))[i] = inb(0x71); } pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40); pci_dev_put(isa_bridge); return 1;}/** * sis635_get_mac_addr - Get MAC address for SIS635 model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * * SiS635 model, set MAC Reload Bit to load Mac address from APC * to rfdr. rfdr is accessed through rfcr. MAC address is read into * @net_dev->dev_addr. */static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev){ long ioaddr = net_dev->base_addr; u32 rfcrSave; u32 i; rfcrSave = inl(rfcr + ioaddr); outl(rfcrSave | RELOAD, ioaddr + cr); outl(0, ioaddr + cr); /* disable packet filtering before setting filter */ outl(rfcrSave & ~RFEN, rfcr + ioaddr); /* load MAC addr to filter data register */ for (i = 0 ; i < 3 ; i++) { outl((i << RFADDR_shift), ioaddr + rfcr); *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr); } /* enable packet filtering */ outl(rfcrSave | RFEN, rfcr + ioaddr); return 1;}/** * sis96x_get_mac_addr - Get MAC address for SiS962 or SiS963 model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM * is shared by * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access * by LAN, otherwise is not. After MAC address is read from EEPROM, send * EEDONE signal to refuse EEPROM access by LAN. * The EEPROM map of SiS962 or SiS963 is different to SiS900. * The signature field in SiS962 or SiS963 spec is meaningless. * MAC address is read into @net_dev->dev_addr. */static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev){ long ioaddr = net_dev->base_addr; long ee_addr = ioaddr + mear; u32 waittime = 0; int i; outl(EEREQ, ee_addr); while(waittime < 2000) { if(inl(ee_addr) & EEGNT) { /* get MAC address from EEPROM */ for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); outl(EEDONE, ee_addr); return 1; } else { udelay(1); waittime ++; } } outl(EEDONE, ee_addr); return 0;}/** * sis900_probe - Probe for sis900 device * @pci_dev: the sis900 pci device * @pci_id: the pci device ID * * Check and probe sis900 net device for @pci_dev. * Get mac address according to the chip revision, * and assign SiS900-specific entries in the device structure. * ie: sis900_open(), sis900_start_xmit(), sis900_close(), etc. */static int __devinit sis900_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id){ struct sis900_private *sis_priv; struct net_device *net_dev; struct pci_dev *dev; dma_addr_t ring_dma; void *ring_space; long ioaddr; int i, ret; const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); DECLARE_MAC_BUF(mac);/* when built into the kernel, we only print version if device is found */#ifndef MODULE static int printed_version; if (!printed_version++) printk(version);#endif /* setup various bits in PCI command register */ ret = pci_enable_device(pci_dev); if(ret) return ret; i = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); if(i){ printk(KERN_ERR "sis900.c: architecture does not support" "32bit PCI busmaster DMA\n"); return i; } pci_set_master(pci_dev); net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; SET_NETDEV_DEV(net_dev, &pci_dev->dev); /* We do a request_region() to register /proc/ioports info. */ ioaddr = pci_resource_start(pci_dev, 0); ret = pci_request_regions(pci_dev, "sis900"); if (ret) goto err_out;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?