diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/ethernet/smsc')
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/Kconfig | 136 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/Makefile | 11 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/epic100.c | 1608 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.c | 2198 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.h | 924 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.c | 1589 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.h | 241 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91c92_cs.c | 2069 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.c | 2419 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.h | 1180 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.c | 2597 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.h | 406 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.c | 1760 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.h | 276 |
14 files changed, 0 insertions, 17414 deletions
diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/Kconfig b/ANDROID_3.4.5/drivers/net/ethernet/smsc/Kconfig deleted file mode 100644 index 5a689af5..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/Kconfig +++ /dev/null @@ -1,136 +0,0 @@ -# -# Western Digital/SMC network device configuration -# - -config NET_VENDOR_SMSC - bool "SMC (SMSC)/Western Digital devices" - default y - depends on ARM || ISA || MAC || ARM || MIPS || M32R || SUPERH || \ - BLACKFIN || MN10300 || COLDFIRE || PCI || PCMCIA - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about SMC/Western Digital cards. If you say Y, you will - be asked for your specific card in the following questions. - -if NET_VENDOR_SMSC - -config SMC9194 - tristate "SMC 9194 support" - depends on (ISA || MAC && BROKEN) - select CRC32 - ---help--- - This is support for the SMC9xxx based Ethernet cards. Choose this - option if you have a DELL laptop with the docking station, or - another SMC9192/9194 based chipset. Say Y if you want it compiled - into the kernel, and read the file - <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO, - available from <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here. The module - will be called smc9194. - -config SMC91X - tristate "SMC 91C9x/91C1xxx support" - select CRC32 - select NET_CORE - select MII - depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \ - MN10300 || COLDFIRE) - ---help--- - This is a driver for SMC's 91x series of Ethernet chipsets, - including the SMC91C94 and the SMC91C111. Say Y if you want it - compiled into the kernel, and read the file - <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO, - available from <http://www.tldp.org/docs.html#howto>. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called smc91x. If you want to compile it as a - module, say M here and read <file:Documentation/kbuild/modules.txt>. - -config PCMCIA_SMC91C92 - tristate "SMC 91Cxx PCMCIA support" - depends on PCMCIA - select CRC32 - select NET_CORE - select MII - ---help--- - Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA - (PC-card) Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called smc91c92_cs. If unsure, say N. - -config EPIC100 - tristate "SMC EtherPower II" - depends on PCI - select CRC32 - select NET_CORE - select MII - ---help--- - This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, - which is based on the SMC83c17x (EPIC/100). - More specific information and updates are available from - <http://www.scyld.com/network/epic100.html>. - -config SMC911X - tristate "SMSC LAN911[5678] support" - select CRC32 - select NET_CORE - select MII - depends on (ARM || SUPERH || MN10300) - ---help--- - This is a driver for SMSC's LAN911x series of Ethernet chipsets - including the new LAN9115, LAN9116, LAN9117, and LAN9118. - Say Y if you want it compiled into the kernel, - and read the Ethernet-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - This driver is also available as a module. The module will be - called smc911x. If you want to compile it as a module, say M - here and read <file:Documentation/kbuild/modules.txt> - -config SMSC911X - tristate "SMSC LAN911x/LAN921x families embedded ethernet support" - depends on (ARM || SUPERH || BLACKFIN || MIPS || MN10300) - select CRC32 - select NET_CORE - select MII - select PHYLIB - ---help--- - Say Y here if you want support for SMSC LAN911x and LAN921x families - of ethernet controllers. - - To compile this driver as a module, choose M here. The module - will be called smsc911x. - -config SMSC911X_ARCH_HOOKS - def_bool n - depends on SMSC911X - ---help--- - If the arch enables this, it allows the arch to implement various - hooks for more comprehensive interrupt control and also to override - the source of the MAC address. - -config SMSC9420 - tristate "SMSC LAN9420 PCI ethernet adapter support" - depends on PCI - select CRC32 - select PHYLIB - select SMSC_PHY - ---help--- - This is a driver for SMSC's LAN9420 PCI ethernet adapter. - Say Y if you want it compiled into the kernel, - and read the Ethernet-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - This driver is also available as a module. The module will be - called smsc9420. If you want to compile it as a module, say M - here and read <file:Documentation/kbuild/modules.txt> - -endif # NET_VENDOR_SMSC diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/Makefile b/ANDROID_3.4.5/drivers/net/ethernet/smsc/Makefile deleted file mode 100644 index f3438dec..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the SMSC network device drivers. -# - -obj-$(CONFIG_SMC9194) += smc9194.o -obj-$(CONFIG_SMC91X) += smc91x.o -obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o -obj-$(CONFIG_EPIC100) += epic100.o -obj-$(CONFIG_SMSC9420) += smsc9420.o -obj-$(CONFIG_SMC911X) += smc911x.o -obj-$(CONFIG_SMSC911X) += smsc911x.o diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/epic100.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/epic100.c deleted file mode 100644 index 2a662e61..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/epic100.c +++ /dev/null @@ -1,1608 +0,0 @@ -/* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */ -/* - Written/copyright 1997-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. - - This driver is for the SMC83c170/175 "EPIC" series, as used on the - SMC EtherPower II 9432 PCI adapter, and several CardBus cards. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Information and updates available at - http://www.scyld.com/network/epic100.html - [this link no longer provides anything useful -jgarzik] - - --------------------------------------------------------------------- - -*/ - -#define DRV_NAME "epic100" -#define DRV_VERSION "2.1" -#define DRV_RELDATE "Sept 11, 2006" - -/* The user-configurable values. - These may be modified when a driver module is loaded.*/ - -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ - -/* Used to pass the full-duplex flag, etc. */ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak; - -/* Operational parameters that are set at compile time. */ - -/* Keep the ring sizes a power of two for operational 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_RING_SIZE 256 -#define TX_QUEUE_LEN 240 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 256 -#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) -#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) - -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - -/* Bytes transferred to chip before transmission starts. */ -/* Initial threshold, increased on underflow, rounded down to 4 byte units. */ -#define TX_FIFO_THRESH 256 -#define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */ - -#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/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/crc32.h> -#include <linux/bitops.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/byteorder.h> - -/* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = -DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n"; -static char version2[] __devinitdata = -" (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; - -MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); -MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); -MODULE_LICENSE("GPL"); - -module_param(debug, int, 0); -module_param(rx_copybreak, int, 0); -module_param_array(options, int, NULL, 0); -module_param_array(full_duplex, int, NULL, 0); -MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)"); -MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex"); -MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)"); - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the SMC "EPIC/100", the SMC -single-chip Ethernet controllers for PCI. This chip is used on -the SMC EtherPower II boards. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. -Note: Kernel versions earlier than 1.3.73 do not support shared PCI -interrupt lines. - -III. Driver operation - -IIIa. Ring buffers - -IVb. References - -http://www.smsc.com/media/Downloads_Public/discontinued/83c171.pdf -http://www.smsc.com/media/Downloads_Public/discontinued/83c175.pdf -http://scyld.com/expert/NWay.html -http://www.national.com/pf/DP/DP83840A.html - -IVc. Errata - -*/ - - -enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; - -#define EPIC_TOTAL_SIZE 0x100 -#define USE_IO_OPS 1 - -typedef enum { - SMSC_83C170_0, - SMSC_83C170, - SMSC_83C175, -} chip_t; - - -struct epic_chip_info { - const char *name; - int drv_flags; /* Driver use, intended as capability flags. */ -}; - - -/* indexed by chip_t */ -static const struct epic_chip_info pci_id_tbl[] = { - { "SMSC EPIC/100 83c170", TYPE2_INTR | NO_MII | MII_PWRDWN }, - { "SMSC EPIC/100 83c170", TYPE2_INTR }, - { "SMSC EPIC/C 83c175", TYPE2_INTR | MII_PWRDWN }, -}; - - -static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = { - { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 }, - { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 }, - { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, SMSC_83C175 }, - { 0,} -}; -MODULE_DEVICE_TABLE (pci, epic_pci_tbl); - - -#ifndef USE_IO_OPS -#undef inb -#undef inw -#undef inl -#undef outb -#undef outw -#undef outl -#define inb readb -#define inw readw -#define inl readl -#define outb writeb -#define outw writew -#define outl writel -#endif - -/* Offsets to registers, using the (ugh) SMC names. */ -enum epic_registers { - COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14, - PCIBurstCnt=0x18, - TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28, /* Rx error counters. */ - MIICtrl=0x30, MIIData=0x34, MIICfg=0x38, - LAN0=64, /* MAC address. */ - MC0=80, /* Multicast filter table. */ - RxCtrl=96, TxCtrl=112, TxSTAT=0x74, - PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC, -}; - -/* Interrupt register bits, using my own meaningful names. */ -enum IntrStatus { - TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000, - PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000, - RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100, - TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010, - RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001, -}; -enum CommandBits { - StopRx=1, StartRx=2, TxQueued=4, RxQueued=8, - StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80, -}; - -#define EpicRemoved 0xffffffff /* Chip failed or removed (CardBus) */ - -#define EpicNapiEvent (TxEmpty | TxDone | \ - RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull) -#define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent) - -static const u16 media2miictl[16] = { - 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }; - -/* - * The EPIC100 Rx and Tx buffer descriptors. Note that these - * really ARE host-endian; it's not a misannotation. We tell - * the card to byteswap them internally on big-endian hosts - - * look for #ifdef __BIG_ENDIAN in epic_open(). - */ - -struct epic_tx_desc { - u32 txstatus; - u32 bufaddr; - u32 buflength; - u32 next; -}; - -struct epic_rx_desc { - u32 rxstatus; - u32 bufaddr; - u32 buflength; - u32 next; -}; - -enum desc_status_bits { - DescOwn=0x8000, -}; - -#define PRIV_ALIGN 15 /* Required alignment mask */ -struct epic_private { - struct epic_rx_desc *rx_ring; - struct epic_tx_desc *tx_ring; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - - dma_addr_t tx_ring_dma; - dma_addr_t rx_ring_dma; - - /* Ring pointers. */ - spinlock_t lock; /* Group with Tx control cache line. */ - spinlock_t napi_lock; - struct napi_struct napi; - unsigned int reschedule_in_poll; - unsigned int cur_tx, dirty_tx; - - unsigned int cur_rx, dirty_rx; - u32 irq_mask; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - - struct pci_dev *pci_dev; /* PCI bus location. */ - int chip_id, chip_flags; - - struct timer_list timer; /* Media selection timer. */ - int tx_threshold; - unsigned char mc_filter[8]; - signed char phys[4]; /* MII device addresses. */ - u16 advertising; /* NWay media advertisement */ - int mii_phy_cnt; - struct mii_if_info mii; - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int default_port:4; /* Last dev->if_port value. */ -}; - -static int epic_open(struct net_device *dev); -static int read_eeprom(long 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 loc, int val); -static void epic_restart(struct net_device *dev); -static void epic_timer(unsigned long data); -static void epic_tx_timeout(struct net_device *dev); -static void epic_init_ring(struct net_device *dev); -static netdev_tx_t epic_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int epic_rx(struct net_device *dev, int budget); -static int epic_poll(struct napi_struct *napi, int budget); -static irqreturn_t epic_interrupt(int irq, void *dev_instance); -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static const struct ethtool_ops netdev_ethtool_ops; -static int epic_close(struct net_device *dev); -static struct net_device_stats *epic_get_stats(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); - -static const struct net_device_ops epic_netdev_ops = { - .ndo_open = epic_open, - .ndo_stop = epic_close, - .ndo_start_xmit = epic_start_xmit, - .ndo_tx_timeout = epic_tx_timeout, - .ndo_get_stats = epic_get_stats, - .ndo_set_rx_mode = set_rx_mode, - .ndo_do_ioctl = netdev_ioctl, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int __devinit epic_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int card_idx = -1; - long ioaddr; - int chip_idx = (int) ent->driver_data; - int irq; - struct net_device *dev; - struct epic_private *ep; - int i, ret, option = 0, duplex = 0; - void *ring_space; - dma_addr_t ring_dma; - -/* when built into the kernel, we only print version if device is found */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(KERN_INFO "%s%s", version, version2); -#endif - - card_idx++; - - ret = pci_enable_device(pdev); - if (ret) - goto out; - irq = pdev->irq; - - if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) { - dev_err(&pdev->dev, "no PCI region space\n"); - ret = -ENODEV; - goto err_out_disable; - } - - pci_set_master(pdev); - - ret = pci_request_regions(pdev, DRV_NAME); - if (ret < 0) - goto err_out_disable; - - ret = -ENOMEM; - - dev = alloc_etherdev(sizeof (*ep)); - if (!dev) - goto err_out_free_res; - - SET_NETDEV_DEV(dev, &pdev->dev); - -#ifdef USE_IO_OPS - ioaddr = pci_resource_start (pdev, 0); -#else - ioaddr = pci_resource_start (pdev, 1); - ioaddr = (long) pci_ioremap_bar(pdev, 1); - if (!ioaddr) { - dev_err(&pdev->dev, "ioremap failed\n"); - goto err_out_free_netdev; - } -#endif - - pci_set_drvdata(pdev, dev); - ep = netdev_priv(dev); - ep->mii.dev = dev; - ep->mii.mdio_read = mdio_read; - ep->mii.mdio_write = mdio_write; - ep->mii.phy_id_mask = 0x1f; - ep->mii.reg_num_mask = 0x1f; - - ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); - if (!ring_space) - goto err_out_iounmap; - ep->tx_ring = ring_space; - ep->tx_ring_dma = ring_dma; - - ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); - if (!ring_space) - goto err_out_unmap_tx; - ep->rx_ring = ring_space; - ep->rx_ring_dma = ring_dma; - - if (dev->mem_start) { - option = dev->mem_start; - duplex = (dev->mem_start & 16) ? 1 : 0; - } else if (card_idx >= 0 && card_idx < MAX_UNITS) { - if (options[card_idx] >= 0) - option = options[card_idx]; - if (full_duplex[card_idx] >= 0) - duplex = full_duplex[card_idx]; - } - - dev->base_addr = ioaddr; - dev->irq = irq; - - spin_lock_init(&ep->lock); - spin_lock_init(&ep->napi_lock); - ep->reschedule_in_poll = 0; - - /* Bring the chip out of low-power mode. */ - outl(0x4200, ioaddr + GENCTL); - /* Magic?! If we don't set this bit the MII interface won't work. */ - /* This magic is documented in SMSC app note 7.15 */ - for (i = 16; i > 0; i--) - outl(0x0008, ioaddr + TEST1); - - /* Turn on the MII transceiver. */ - outl(0x12, ioaddr + MIICfg); - if (chip_idx == 1) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - outl(0x0200, ioaddr + GENCTL); - - /* Note: the '175 does not have a serial EEPROM. */ - for (i = 0; i < 3; i++) - ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(inw(ioaddr + LAN0 + i*4)); - - if (debug > 2) { - dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n"); - for (i = 0; i < 64; i++) - printk(" %4.4x%s", read_eeprom(ioaddr, i), - i % 16 == 15 ? "\n" : ""); - } - - ep->pci_dev = pdev; - ep->chip_id = chip_idx; - ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; - ep->irq_mask = - (ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | EpicNapiEvent; - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes much time and no cards have external MII. */ - { - int phy, phy_idx = 0; - for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); - if (mii_status != 0xffff && mii_status != 0x0000) { - ep->phys[phy_idx++] = phy; - dev_info(&pdev->dev, - "MII transceiver #%d control " - "%4.4x status %4.4x.\n", - phy, mdio_read(dev, phy, 0), mii_status); - } - } - ep->mii_phy_cnt = phy_idx; - if (phy_idx != 0) { - phy = ep->phys[0]; - ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE); - dev_info(&pdev->dev, - "Autonegotiation advertising %4.4x link " - "partner %4.4x.\n", - ep->mii.advertising, mdio_read(dev, phy, 5)); - } else if ( ! (ep->chip_flags & NO_MII)) { - dev_warn(&pdev->dev, - "***WARNING***: No MII transceiver found!\n"); - /* Use the known PHY address of the EPII. */ - ep->phys[0] = 3; - } - ep->mii.phy_id = ep->phys[0]; - } - - /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */ - if (ep->chip_flags & MII_PWRDWN) - outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL); - outl(0x0008, ioaddr + GENCTL); - - /* The lower four bits are the media type. */ - if (duplex) { - ep->mii.force_media = ep->mii.full_duplex = 1; - dev_info(&pdev->dev, "Forced full duplex requested.\n"); - } - dev->if_port = ep->default_port = option; - - /* The Epic-specific entries in the device structure. */ - dev->netdev_ops = &epic_netdev_ops; - dev->ethtool_ops = &netdev_ethtool_ops; - dev->watchdog_timeo = TX_TIMEOUT; - netif_napi_add(dev, &ep->napi, epic_poll, 64); - - ret = register_netdev(dev); - if (ret < 0) - goto err_out_unmap_rx; - - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", - dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq, - dev->dev_addr); - -out: - return ret; - -err_out_unmap_rx: - pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); -err_out_unmap_tx: - pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); -err_out_iounmap: -#ifndef USE_IO_OPS - iounmap(ioaddr); -err_out_free_netdev: -#endif - free_netdev(dev); -err_out_free_res: - pci_release_regions(pdev); -err_out_disable: - pci_disable_device(pdev); - goto out; -} - -/* Serial EEPROM section. */ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ -#define EE_CS 0x02 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x08 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x09 -#define EE_DATA_READ 0x10 /* EEPROM chip data out. */ -#define EE_ENB (0x0001 | EE_CS) - -/* Delay between EEPROM clock transitions. - This serves to flush the operation to the PCI bus. - */ - -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ64_CMD (6 << 6) -#define EE_READ256_CMD (6 << 8) -#define EE_ERASE_CMD (7 << 6) - -static void epic_disable_int(struct net_device *dev, struct epic_private *ep) -{ - long ioaddr = dev->base_addr; - - outl(0x00000000, ioaddr + INTMASK); -} - -static inline void __epic_pci_commit(long ioaddr) -{ -#ifndef USE_IO_OPS - inl(ioaddr + INTMASK); -#endif -} - -static inline void epic_napi_irq_off(struct net_device *dev, - struct epic_private *ep) -{ - long ioaddr = dev->base_addr; - - outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); - __epic_pci_commit(ioaddr); -} - -static inline void epic_napi_irq_on(struct net_device *dev, - struct epic_private *ep) -{ - long ioaddr = dev->base_addr; - - /* No need to commit possible posted write */ - outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK); -} - -static int __devinit read_eeprom(long ioaddr, int location) -{ - int i; - int retval = 0; - long ee_addr = ioaddr + EECTL; - int read_cmd = location | - (inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD); - - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 12; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0; - outl(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - } - outl(EE_ENB, ee_addr); - - for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - outl(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); - return retval; -} - -#define MII_READOP 1 -#define MII_WRITEOP 2 -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - long ioaddr = dev->base_addr; - int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP; - int i; - - outl(read_cmd, ioaddr + MIICtrl); - /* Typical operation takes 25 loops. */ - for (i = 400; i > 0; i--) { - barrier(); - if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) { - /* Work around read failure bug. */ - if (phy_id == 1 && location < 6 && - inw(ioaddr + MIIData) == 0xffff) { - outl(read_cmd, ioaddr + MIICtrl); - continue; - } - return inw(ioaddr + MIIData); - } - } - return 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) -{ - long ioaddr = dev->base_addr; - int i; - - outw(value, ioaddr + MIIData); - outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl); - for (i = 10000; i > 0; i--) { - barrier(); - if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) - break; - } -} - - -static int epic_open(struct net_device *dev) -{ - struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; - int i; - int retval; - - /* Soft reset the chip. */ - outl(0x4001, ioaddr + GENCTL); - - napi_enable(&ep->napi); - if ((retval = request_irq(dev->irq, epic_interrupt, IRQF_SHARED, dev->name, dev))) { - napi_disable(&ep->napi); - return retval; - } - - epic_init_ring(dev); - - outl(0x4000, ioaddr + GENCTL); - /* This magic is documented in SMSC app note 7.15 */ - for (i = 16; i > 0; i--) - outl(0x0008, ioaddr + TEST1); - - /* Pull the chip out of low-power mode, enable interrupts, and set for - PCI read multiple. The MIIcfg setting and strange write order are - required by the details of which bits are reset and the transceiver - wiring on the Ositech CardBus card. - */ -#if 0 - outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); -#endif - if (ep->chip_flags & MII_PWRDWN) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - - /* Tell the chip to byteswap descriptors on big-endian hosts */ -#ifdef __BIG_ENDIAN - outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); - inl(ioaddr + GENCTL); - outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); -#else - outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); - inl(ioaddr + GENCTL); - outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); -#endif - - udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */ - - for (i = 0; i < 3; i++) - outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); - - ep->tx_threshold = TX_FIFO_THRESH; - outl(ep->tx_threshold, ioaddr + TxThresh); - - if (media2miictl[dev->if_port & 15]) { - if (ep->mii_phy_cnt) - mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]); - if (dev->if_port == 1) { - if (debug > 1) - printk(KERN_INFO "%s: Using the 10base2 transceiver, MII " - "status %4.4x.\n", - dev->name, mdio_read(dev, ep->phys[0], MII_BMSR)); - } - } else { - int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA); - if (mii_lpa != 0xffff) { - if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL) - ep->mii.full_duplex = 1; - else if (! (mii_lpa & LPA_LPACK)) - mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART); - if (debug > 1) - printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d" - " register read of %4.4x.\n", dev->name, - ep->mii.full_duplex ? "full" : "half", - ep->phys[0], mii_lpa); - } - } - - outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(ep->rx_ring_dma, ioaddr + PRxCDAR); - outl(ep->tx_ring_dma, ioaddr + PTxCDAR); - - /* Start the chip's Rx process. */ - set_rx_mode(dev); - outl(StartRx | RxQueued, ioaddr + COMMAND); - - netif_start_queue(dev); - - /* Enable interrupts by setting the interrupt mask. */ - outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun - | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); - - if (debug > 1) - printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " - "%s-duplex.\n", - dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), - ep->mii.full_duplex ? "full" : "half"); - - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&ep->timer); - ep->timer.expires = jiffies + 3*HZ; - ep->timer.data = (unsigned long)dev; - ep->timer.function = epic_timer; /* timer handler */ - add_timer(&ep->timer); - - return 0; -} - -/* Reset the chip to recover from a PCI transaction error. - This may occur at interrupt time. */ -static void epic_pause(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - - netif_stop_queue (dev); - - /* Disable interrupts by clearing the interrupt mask. */ - outl(0x00000000, ioaddr + INTMASK); - /* Stop the chip's Tx and Rx DMA processes. */ - outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND); - - /* Update the error counts. */ - if (inw(ioaddr + COMMAND) != 0xffff) { - dev->stats.rx_missed_errors += inb(ioaddr + MPCNT); - dev->stats.rx_frame_errors += inb(ioaddr + ALICNT); - dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - } - - /* Remove the packets on the Rx queue. */ - epic_rx(dev, RX_RING_SIZE); -} - -static void epic_restart(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct epic_private *ep = netdev_priv(dev); - int i; - - /* Soft reset the chip. */ - outl(0x4001, ioaddr + GENCTL); - - printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", - dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); - udelay(1); - - /* This magic is documented in SMSC app note 7.15 */ - for (i = 16; i > 0; i--) - outl(0x0008, ioaddr + TEST1); - -#ifdef __BIG_ENDIAN - outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); -#else - outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); -#endif - outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); - if (ep->chip_flags & MII_PWRDWN) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - - for (i = 0; i < 3; i++) - outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); - - ep->tx_threshold = TX_FIFO_THRESH; - outl(ep->tx_threshold, ioaddr + TxThresh); - outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)* - sizeof(struct epic_rx_desc), ioaddr + PRxCDAR); - outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)* - sizeof(struct epic_tx_desc), ioaddr + PTxCDAR); - - /* Start the chip's Rx process. */ - set_rx_mode(dev); - outl(StartRx | RxQueued, ioaddr + COMMAND); - - /* Enable interrupts by setting the interrupt mask. */ - outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun - | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); - - printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" - " interrupt %4.4x.\n", - dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), - (int)inl(ioaddr + INTSTAT)); -} - -static void check_media(struct net_device *dev) -{ - struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; - int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0; - int negotiated = mii_lpa & ep->mii.advertising; - int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - - if (ep->mii.force_media) - return; - if (mii_lpa == 0xffff) /* Bogus read */ - return; - if (ep->mii.full_duplex != duplex) { - ep->mii.full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner capability of %4.4x.\n", dev->name, - ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa); - outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - } -} - -static void epic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; - int next_tick = 5*HZ; - - if (debug > 3) { - printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", - dev->name, (int)inl(ioaddr + TxSTAT)); - printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x " - "IntStatus %4.4x RxStatus %4.4x.\n", - dev->name, (int)inl(ioaddr + INTMASK), - (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); - } - - check_media(dev); - - ep->timer.expires = jiffies + next_tick; - add_timer(&ep->timer); -} - -static void epic_tx_timeout(struct net_device *dev) -{ - struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; - - if (debug > 0) { - printk(KERN_WARNING "%s: Transmit timeout using MII device, " - "Tx status %4.4x.\n", - dev->name, (int)inw(ioaddr + TxSTAT)); - if (debug > 1) { - printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n", - dev->name, ep->dirty_tx, ep->cur_tx); - } - } - if (inw(ioaddr + TxSTAT) & 0x10) { /* Tx FIFO underflow. */ - dev->stats.tx_fifo_errors++; - outl(RestartTx, ioaddr + COMMAND); - } else { - epic_restart(dev); - outl(TxQueued, dev->base_addr + COMMAND); - } - - dev->trans_start = jiffies; /* prevent tx timeout */ - dev->stats.tx_errors++; - if (!ep->tx_full) - netif_wake_queue(dev); -} - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void epic_init_ring(struct net_device *dev) -{ - struct epic_private *ep = netdev_priv(dev); - int i; - - ep->tx_full = 0; - ep->dirty_tx = ep->cur_tx = 0; - ep->cur_rx = ep->dirty_rx = 0; - ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - - /* Initialize all Rx descriptors. */ - for (i = 0; i < RX_RING_SIZE; i++) { - ep->rx_ring[i].rxstatus = 0; - ep->rx_ring[i].buflength = ep->rx_buf_sz; - ep->rx_ring[i].next = ep->rx_ring_dma + - (i+1)*sizeof(struct epic_rx_desc); - ep->rx_skbuff[i] = NULL; - } - /* Mark the last entry as wrapping the ring. */ - ep->rx_ring[i-1].next = ep->rx_ring_dma; - - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = netdev_alloc_skb(dev, ep->rx_buf_sz + 2); - ep->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb_reserve(skb, 2); /* 16 byte align the IP header. */ - ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, - skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - ep->rx_ring[i].rxstatus = DescOwn; - } - ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - ep->tx_skbuff[i] = NULL; - ep->tx_ring[i].txstatus = 0x0000; - ep->tx_ring[i].next = ep->tx_ring_dma + - (i+1)*sizeof(struct epic_tx_desc); - } - ep->tx_ring[i-1].next = ep->tx_ring_dma; -} - -static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct epic_private *ep = netdev_priv(dev); - int entry, free_count; - u32 ctrl_word; - unsigned long flags; - - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - - /* Caution: the write order is important here, set the field with the - "ownership" bit last. */ - - /* Calculate the next Tx descriptor entry. */ - spin_lock_irqsave(&ep->lock, flags); - free_count = ep->cur_tx - ep->dirty_tx; - entry = ep->cur_tx % TX_RING_SIZE; - - ep->tx_skbuff[entry] = skb; - ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data, - skb->len, PCI_DMA_TODEVICE); - if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ - ctrl_word = 0x100000; /* No interrupt */ - } else if (free_count == TX_QUEUE_LEN/2) { - ctrl_word = 0x140000; /* Tx-done intr. */ - } else if (free_count < TX_QUEUE_LEN - 1) { - ctrl_word = 0x100000; /* No Tx-done intr. */ - } else { - /* Leave room for an additional entry. */ - ctrl_word = 0x140000; /* Tx-done intr. */ - ep->tx_full = 1; - } - ep->tx_ring[entry].buflength = ctrl_word | skb->len; - ep->tx_ring[entry].txstatus = - ((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16) - | DescOwn; - - ep->cur_tx++; - if (ep->tx_full) - netif_stop_queue(dev); - - spin_unlock_irqrestore(&ep->lock, flags); - /* Trigger an immediate transmit demand. */ - outl(TxQueued, dev->base_addr + COMMAND); - - if (debug > 4) - printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, " - "flag %2.2x Tx status %8.8x.\n", - dev->name, (int)skb->len, entry, ctrl_word, - (int)inl(dev->base_addr + TxSTAT)); - - return NETDEV_TX_OK; -} - -static void epic_tx_error(struct net_device *dev, struct epic_private *ep, - int status) -{ - struct net_device_stats *stats = &dev->stats; - -#ifndef final_version - /* There was an major error, log it. */ - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, status); -#endif - stats->tx_errors++; - if (status & 0x1050) - stats->tx_aborted_errors++; - if (status & 0x0008) - stats->tx_carrier_errors++; - if (status & 0x0040) - stats->tx_window_errors++; - if (status & 0x0010) - stats->tx_fifo_errors++; -} - -static void epic_tx(struct net_device *dev, struct epic_private *ep) -{ - unsigned int dirty_tx, cur_tx; - - /* - * Note: if this lock becomes a problem we can narrow the locked - * region at the cost of occasionally grabbing the lock more times. - */ - cur_tx = ep->cur_tx; - for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) { - struct sk_buff *skb; - int entry = dirty_tx % TX_RING_SIZE; - int txstatus = ep->tx_ring[entry].txstatus; - - if (txstatus & DescOwn) - break; /* It still hasn't been Txed */ - - if (likely(txstatus & 0x0001)) { - dev->stats.collisions += (txstatus >> 8) & 15; - dev->stats.tx_packets++; - dev->stats.tx_bytes += ep->tx_skbuff[entry]->len; - } else - epic_tx_error(dev, ep, txstatus); - - /* Free the original skb. */ - skb = ep->tx_skbuff[entry]; - pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - ep->tx_skbuff[entry] = NULL; - } - -#ifndef final_version - if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_WARNING - "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, cur_tx, ep->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - ep->dirty_tx = dirty_tx; - if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, allow new TX entries. */ - ep->tx_full = 0; - netif_wake_queue(dev); - } -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t epic_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = dev_instance; - struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; - unsigned int handled = 0; - int status; - - status = inl(ioaddr + INTSTAT); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status & EpicNormalEvent, ioaddr + INTSTAT); - - if (debug > 4) { - printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " - "intstat=%#8.8x.\n", dev->name, status, - (int)inl(ioaddr + INTSTAT)); - } - - if ((status & IntrSummary) == 0) - goto out; - - handled = 1; - - if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { - spin_lock(&ep->napi_lock); - if (napi_schedule_prep(&ep->napi)) { - epic_napi_irq_off(dev, ep); - __napi_schedule(&ep->napi); - } else - ep->reschedule_in_poll++; - spin_unlock(&ep->napi_lock); - } - status &= ~EpicNapiEvent; - - /* Check uncommon events all at once. */ - if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) { - if (status == EpicRemoved) - goto out; - - /* Always update the error counts to avoid overhead later. */ - dev->stats.rx_missed_errors += inb(ioaddr + MPCNT); - dev->stats.rx_frame_errors += inb(ioaddr + ALICNT); - dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - - if (status & TxUnderrun) { /* Tx FIFO underflow. */ - dev->stats.tx_fifo_errors++; - outl(ep->tx_threshold += 128, ioaddr + TxThresh); - /* Restart the transmit process. */ - outl(RestartTx, ioaddr + COMMAND); - } - if (status & PCIBusErr170) { - printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n", - dev->name, status); - epic_pause(dev); - epic_restart(dev); - } - /* Clear all error sources. */ - outl(status & 0x7f18, ioaddr + INTSTAT); - } - -out: - if (debug > 3) { - printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n", - dev->name, status); - } - - return IRQ_RETVAL(handled); -} - -static int epic_rx(struct net_device *dev, int budget) -{ - struct epic_private *ep = netdev_priv(dev); - int entry = ep->cur_rx % RX_RING_SIZE; - int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx; - int work_done = 0; - - if (debug > 4) - printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, - ep->rx_ring[entry].rxstatus); - - if (rx_work_limit > budget) - rx_work_limit = budget; - - /* If we own the next entry, it's a new packet. Send it up. */ - while ((ep->rx_ring[entry].rxstatus & DescOwn) == 0) { - int status = ep->rx_ring[entry].rxstatus; - - if (debug > 4) - printk(KERN_DEBUG " epic_rx() status was %8.8x.\n", status); - if (--rx_work_limit < 0) - break; - if (status & 0x2006) { - if (debug > 2) - printk(KERN_DEBUG "%s: epic_rx() error status was %8.8x.\n", - dev->name, status); - if (status & 0x2000) { - printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " - "multiple buffers, status %4.4x!\n", dev->name, status); - dev->stats.rx_length_errors++; - } else if (status & 0x0006) - /* Rx Frame errors are counted in hardware. */ - dev->stats.rx_errors++; - } else { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - short pkt_len = (status >> 16) - 4; - struct sk_buff *skb; - - if (pkt_len > PKT_BUF_SZ - 4) { - printk(KERN_ERR "%s: Oversized Ethernet frame, status %x " - "%d bytes.\n", - dev->name, status, pkt_len); - pkt_len = 1514; - } - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { - skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single_for_cpu(ep->pci_dev, - ep->rx_ring[entry].bufaddr, - ep->rx_buf_sz, - PCI_DMA_FROMDEVICE); - skb_copy_to_linear_data(skb, ep->rx_skbuff[entry]->data, pkt_len); - skb_put(skb, pkt_len); - pci_dma_sync_single_for_device(ep->pci_dev, - ep->rx_ring[entry].bufaddr, - ep->rx_buf_sz, - PCI_DMA_FROMDEVICE); - } else { - pci_unmap_single(ep->pci_dev, - ep->rx_ring[entry].bufaddr, - ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - skb_put(skb = ep->rx_skbuff[entry], pkt_len); - ep->rx_skbuff[entry] = NULL; - } - skb->protocol = eth_type_trans(skb, dev); - netif_receive_skb(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - work_done++; - entry = (++ep->cur_rx) % RX_RING_SIZE; - } - - /* Refill the Rx ring buffers. */ - for (; ep->cur_rx - ep->dirty_rx > 0; ep->dirty_rx++) { - entry = ep->dirty_rx % RX_RING_SIZE; - if (ep->rx_skbuff[entry] == NULL) { - struct sk_buff *skb; - skb = ep->rx_skbuff[entry] = netdev_alloc_skb(dev, ep->rx_buf_sz + 2); - if (skb == NULL) - break; - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, - skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - work_done++; - } - /* AV: shouldn't we add a barrier here? */ - ep->rx_ring[entry].rxstatus = DescOwn; - } - return work_done; -} - -static void epic_rx_err(struct net_device *dev, struct epic_private *ep) -{ - long ioaddr = dev->base_addr; - int status; - - status = inl(ioaddr + INTSTAT); - - if (status == EpicRemoved) - return; - if (status & RxOverflow) /* Missed a Rx frame. */ - dev->stats.rx_errors++; - if (status & (RxOverflow | RxFull)) - outw(RxQueued, ioaddr + COMMAND); -} - -static int epic_poll(struct napi_struct *napi, int budget) -{ - struct epic_private *ep = container_of(napi, struct epic_private, napi); - struct net_device *dev = ep->mii.dev; - int work_done = 0; - long ioaddr = dev->base_addr; - -rx_action: - - epic_tx(dev, ep); - - work_done += epic_rx(dev, budget); - - epic_rx_err(dev, ep); - - if (work_done < budget) { - unsigned long flags; - int more; - - /* A bit baroque but it avoids a (space hungry) spin_unlock */ - - spin_lock_irqsave(&ep->napi_lock, flags); - - more = ep->reschedule_in_poll; - if (!more) { - __napi_complete(napi); - outl(EpicNapiEvent, ioaddr + INTSTAT); - epic_napi_irq_on(dev, ep); - } else - ep->reschedule_in_poll--; - - spin_unlock_irqrestore(&ep->napi_lock, flags); - - if (more) - goto rx_action; - } - - return work_done; -} - -static int epic_close(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct epic_private *ep = netdev_priv(dev); - struct sk_buff *skb; - int i; - - netif_stop_queue(dev); - napi_disable(&ep->napi); - - if (debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, (int)inl(ioaddr + INTSTAT)); - - del_timer_sync(&ep->timer); - - epic_disable_int(dev, ep); - - free_irq(dev->irq, dev); - - epic_pause(dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - skb = ep->rx_skbuff[i]; - ep->rx_skbuff[i] = NULL; - ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */ - ep->rx_ring[i].buflength = 0; - if (skb) { - pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr, - ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb(skb); - } - ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ - } - for (i = 0; i < TX_RING_SIZE; i++) { - skb = ep->tx_skbuff[i]; - ep->tx_skbuff[i] = NULL; - if (!skb) - continue; - pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - } - - /* Green! Leave the chip in low-power mode. */ - outl(0x0008, ioaddr + GENCTL); - - return 0; -} - -static struct net_device_stats *epic_get_stats(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - - if (netif_running(dev)) { - /* Update the error counts. */ - dev->stats.rx_missed_errors += inb(ioaddr + MPCNT); - dev->stats.rx_frame_errors += inb(ioaddr + ALICNT); - dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - } - - return &dev->stats; -} - -/* Set or clear the multicast filter for this adaptor. - Note that we only use exclusion around actually queueing the - new frame, not around filling ep->setup_frame. This is non-deterministic - when re-entered but still correct. */ - -static void set_rx_mode(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct epic_private *ep = netdev_priv(dev); - unsigned char mc_filter[8]; /* Multicast hash filter */ - int i; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - outl(0x002C, ioaddr + RxCtrl); - /* Unconditionally log net taps. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) { - /* There is apparently a chip bug, so the multicast filter - is never enabled. */ - /* Too many to filter perfectly -- accept all multicasts. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - outl(0x000C, ioaddr + RxCtrl); - } else if (netdev_mc_empty(dev)) { - outl(0x0004, ioaddr + RxCtrl); - return; - } else { /* Never executed, for now. */ - struct netdev_hw_addr *ha; - - memset(mc_filter, 0, sizeof(mc_filter)); - netdev_for_each_mc_addr(ha, dev) { - unsigned int bit_nr = - ether_crc_le(ETH_ALEN, ha->addr) & 0x3f; - mc_filter[bit_nr >> 3] |= (1 << bit_nr); - } - } - /* ToDo: perhaps we need to stop the Tx and Rx process here? */ - if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) { - for (i = 0; i < 4; i++) - outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4); - memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter)); - } -} - -static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct epic_private *np = netdev_priv(dev); - - strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); -} - -static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct epic_private *np = netdev_priv(dev); - int rc; - - spin_lock_irq(&np->lock); - rc = mii_ethtool_gset(&np->mii, cmd); - spin_unlock_irq(&np->lock); - - return rc; -} - -static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct epic_private *np = netdev_priv(dev); - int rc; - - spin_lock_irq(&np->lock); - rc = mii_ethtool_sset(&np->mii, cmd); - spin_unlock_irq(&np->lock); - - return rc; -} - -static int netdev_nway_reset(struct net_device *dev) -{ - struct epic_private *np = netdev_priv(dev); - return mii_nway_restart(&np->mii); -} - -static u32 netdev_get_link(struct net_device *dev) -{ - struct epic_private *np = netdev_priv(dev); - return mii_link_ok(&np->mii); -} - -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 value) -{ - debug = value; -} - -static int ethtool_begin(struct net_device *dev) -{ - unsigned long ioaddr = dev->base_addr; - /* power-up, if interface is down */ - if (! netif_running(dev)) { - outl(0x0200, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - } - return 0; -} - -static void ethtool_complete(struct net_device *dev) -{ - unsigned long ioaddr = dev->base_addr; - /* power-down, if interface is down */ - if (! netif_running(dev)) { - outl(0x0008, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); - } -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, - .get_settings = netdev_get_settings, - .set_settings = netdev_set_settings, - .nway_reset = netdev_nway_reset, - .get_link = netdev_get_link, - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, - .begin = ethtool_begin, - .complete = ethtool_complete -}; - -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct epic_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; - struct mii_ioctl_data *data = if_mii(rq); - int rc; - - /* power-up, if interface is down */ - if (! netif_running(dev)) { - outl(0x0200, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - } - - /* all non-ethtool ioctls (the SIOC[GS]MIIxxx ioctls) */ - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii, data, cmd, NULL); - spin_unlock_irq(&np->lock); - - /* power-down, if interface is down */ - if (! netif_running(dev)) { - outl(0x0008, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); - } - return rc; -} - - -static void __devexit epic_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct epic_private *ep = netdev_priv(dev); - - pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); - pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); - unregister_netdev(dev); -#ifndef USE_IO_OPS - iounmap((void*) dev->base_addr); -#endif - pci_release_regions(pdev); - free_netdev(dev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - /* pci_power_off(pdev, -1); */ -} - - -#ifdef CONFIG_PM - -static int epic_suspend (struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - long ioaddr = dev->base_addr; - - if (!netif_running(dev)) - return 0; - epic_pause(dev); - /* Put the chip into low-power mode. */ - outl(0x0008, ioaddr + GENCTL); - /* pci_power_off(pdev, -1); */ - return 0; -} - - -static int epic_resume (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (!netif_running(dev)) - return 0; - epic_restart(dev); - /* pci_power_on(pdev); */ - return 0; -} - -#endif /* CONFIG_PM */ - - -static struct pci_driver epic_driver = { - .name = DRV_NAME, - .id_table = epic_pci_tbl, - .probe = epic_init_one, - .remove = __devexit_p(epic_remove_one), -#ifdef CONFIG_PM - .suspend = epic_suspend, - .resume = epic_resume, -#endif /* CONFIG_PM */ -}; - - -static int __init epic_init (void) -{ -/* when a module, this is printed whether or not devices are found in probe */ -#ifdef MODULE - printk (KERN_INFO "%s%s", - version, version2); -#endif - - return pci_register_driver(&epic_driver); -} - - -static void __exit epic_cleanup (void) -{ - pci_unregister_driver (&epic_driver); -} - - -module_init(epic_init); -module_exit(epic_cleanup); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.c deleted file mode 100644 index 8814b2f5..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.c +++ /dev/null @@ -1,2198 +0,0 @@ -/* - * smc911x.c - * This is a driver for SMSC's LAN911{5,6,7,8} single-chip Ethernet devices. - * - * Copyright (C) 2005 Sensoria Corp - * Derived from the unified SMC91x driver by Nicolas Pitre - * and the smsc911x.c reference driver by SMSC - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Arguments: - * watchdog = TX watchdog timeout - * tx_fifo_kb = Size of TX FIFO in KB - * - * History: - * 04/16/05 Dustin McIntire Initial version - */ -static const char version[] = - "smc911x.c: v1.0 04-16-2005 by Dustin McIntire <dustin@sensoria.com>\n"; - -/* Debugging options */ -#define ENABLE_SMC_DEBUG_RX 0 -#define ENABLE_SMC_DEBUG_TX 0 -#define ENABLE_SMC_DEBUG_DMA 0 -#define ENABLE_SMC_DEBUG_PKTS 0 -#define ENABLE_SMC_DEBUG_MISC 0 -#define ENABLE_SMC_DEBUG_FUNC 0 - -#define SMC_DEBUG_RX ((ENABLE_SMC_DEBUG_RX ? 1 : 0) << 0) -#define SMC_DEBUG_TX ((ENABLE_SMC_DEBUG_TX ? 1 : 0) << 1) -#define SMC_DEBUG_DMA ((ENABLE_SMC_DEBUG_DMA ? 1 : 0) << 2) -#define SMC_DEBUG_PKTS ((ENABLE_SMC_DEBUG_PKTS ? 1 : 0) << 3) -#define SMC_DEBUG_MISC ((ENABLE_SMC_DEBUG_MISC ? 1 : 0) << 4) -#define SMC_DEBUG_FUNC ((ENABLE_SMC_DEBUG_FUNC ? 1 : 0) << 5) - -#ifndef SMC_DEBUG -#define SMC_DEBUG ( SMC_DEBUG_RX | \ - SMC_DEBUG_TX | \ - SMC_DEBUG_DMA | \ - SMC_DEBUG_PKTS | \ - SMC_DEBUG_MISC | \ - SMC_DEBUG_FUNC \ - ) -#endif - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/crc32.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/workqueue.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include <asm/io.h> - -#include "smc911x.h" - -/* - * Transmit timeout, default 5 seconds. - */ -static int watchdog = 5000; -module_param(watchdog, int, 0400); -MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); - -static int tx_fifo_kb=8; -module_param(tx_fifo_kb, int, 0400); -MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)"); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:smc911x"); - -/* - * The internal workings of the driver. If you are changing anything - * here with the SMC stuff, you should have the datasheet and know - * what you are doing. - */ -#define CARDNAME "smc911x" - -/* - * Use power-down feature of the chip - */ -#define POWER_DOWN 1 - -#if SMC_DEBUG > 0 -#define DBG(n, args...) \ - do { \ - if (SMC_DEBUG & (n)) \ - printk(args); \ - } while (0) - -#define PRINTK(args...) printk(args) -#else -#define DBG(n, args...) do { } while (0) -#define PRINTK(args...) printk(KERN_DEBUG args) -#endif - -#if SMC_DEBUG_PKTS > 0 -static void PRINT_PKT(u_char *buf, int length) -{ - int i; - int remainder; - int lines; - - lines = length / 16; - remainder = length % 16; - - for (i = 0; i < lines ; i ++) { - int cur; - for (cur = 0; cur < 8; cur++) { - u_char a, b; - a = *buf++; - b = *buf++; - printk("%02x%02x ", a, b); - } - printk("\n"); - } - for (i = 0; i < remainder/2 ; i++) { - u_char a, b; - a = *buf++; - b = *buf++; - printk("%02x%02x ", a, b); - } - printk("\n"); -} -#else -#define PRINT_PKT(x...) do { } while (0) -#endif - - -/* this enables an interrupt in the interrupt mask register */ -#define SMC_ENABLE_INT(lp, x) do { \ - unsigned int __mask; \ - __mask = SMC_GET_INT_EN((lp)); \ - __mask |= (x); \ - SMC_SET_INT_EN((lp), __mask); \ -} while (0) - -/* this disables an interrupt from the interrupt mask register */ -#define SMC_DISABLE_INT(lp, x) do { \ - unsigned int __mask; \ - __mask = SMC_GET_INT_EN((lp)); \ - __mask &= ~(x); \ - SMC_SET_INT_EN((lp), __mask); \ -} while (0) - -/* - * this does a soft reset on the device - */ -static void smc911x_reset(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int reg, timeout=0, resets=1, irq_cfg; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - /* Take out of PM setting first */ - if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) { - /* Write to the bytetest will take out of powerdown */ - SMC_SET_BYTE_TEST(lp, 0); - timeout=10; - do { - udelay(10); - reg = SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_; - } while (--timeout && !reg); - if (timeout == 0) { - PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name); - return; - } - } - - /* Disable all interrupts */ - spin_lock_irqsave(&lp->lock, flags); - SMC_SET_INT_EN(lp, 0); - spin_unlock_irqrestore(&lp->lock, flags); - - while (resets--) { - SMC_SET_HW_CFG(lp, HW_CFG_SRST_); - timeout=10; - do { - udelay(10); - reg = SMC_GET_HW_CFG(lp); - /* If chip indicates reset timeout then try again */ - if (reg & HW_CFG_SRST_TO_) { - PRINTK("%s: chip reset timeout, retrying...\n", dev->name); - resets++; - break; - } - } while (--timeout && (reg & HW_CFG_SRST_)); - } - if (timeout == 0) { - PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name); - return; - } - - /* make sure EEPROM has finished loading before setting GPIO_CFG */ - timeout=1000; - while (--timeout && (SMC_GET_E2P_CMD(lp) & E2P_CMD_EPC_BUSY_)) - udelay(10); - - if (timeout == 0){ - PRINTK("%s: smc911x_reset timeout waiting for EEPROM busy\n", dev->name); - return; - } - - /* Initialize interrupts */ - SMC_SET_INT_EN(lp, 0); - SMC_ACK_INT(lp, -1); - - /* Reset the FIFO level and flow control settings */ - SMC_SET_HW_CFG(lp, (lp->tx_fifo_kb & 0xF) << 16); -//TODO: Figure out what appropriate pause time is - SMC_SET_FLOW(lp, FLOW_FCPT_ | FLOW_FCEN_); - SMC_SET_AFC_CFG(lp, lp->afc_cfg); - - - /* Set to LED outputs */ - SMC_SET_GPIO_CFG(lp, 0x70070000); - - /* - * Deassert IRQ for 1*10us for edge type interrupts - * and drive IRQ pin push-pull - */ - irq_cfg = (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_; -#ifdef SMC_DYNAMIC_BUS_CONFIG - if (lp->cfg.irq_polarity) - irq_cfg |= INT_CFG_IRQ_POL_; -#endif - SMC_SET_IRQ_CFG(lp, irq_cfg); - - /* clear anything saved */ - if (lp->pending_tx_skb != NULL) { - dev_kfree_skb (lp->pending_tx_skb); - lp->pending_tx_skb = NULL; - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - } -} - -/* - * Enable Interrupts, Receive, and Transmit - */ -static void smc911x_enable(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned mask, cfg, cr; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - spin_lock_irqsave(&lp->lock, flags); - - SMC_SET_MAC_ADDR(lp, dev->dev_addr); - - /* Enable TX */ - cfg = SMC_GET_HW_CFG(lp); - cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF; - cfg |= HW_CFG_SF_; - SMC_SET_HW_CFG(lp, cfg); - SMC_SET_FIFO_TDA(lp, 0xFF); - /* Update TX stats on every 64 packets received or every 1 sec */ - SMC_SET_FIFO_TSL(lp, 64); - SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - - SMC_GET_MAC_CR(lp, cr); - cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_; - SMC_SET_MAC_CR(lp, cr); - SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_); - - /* Add 2 byte padding to start of packets */ - SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_); - - /* Turn on receiver and enable RX */ - if (cr & MAC_CR_RXEN_) - DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name); - - SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_); - - /* Interrupt on every received packet */ - SMC_SET_FIFO_RSA(lp, 0x01); - SMC_SET_FIFO_RSL(lp, 0x00); - - /* now, enable interrupts */ - mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ | - INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ | - INT_EN_PHY_INT_EN_; - if (IS_REV_A(lp->revision)) - mask|=INT_EN_RDFL_EN_; - else { - mask|=INT_EN_RDFO_EN_; - } - SMC_ENABLE_INT(lp, mask); - - spin_unlock_irqrestore(&lp->lock, flags); -} - -/* - * this puts the device in an inactive state - */ -static void smc911x_shutdown(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned cr; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__); - - /* Disable IRQ's */ - SMC_SET_INT_EN(lp, 0); - - /* Turn of Rx and TX */ - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(lp, cr); - cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_); - SMC_SET_MAC_CR(lp, cr); - SMC_SET_TX_CFG(lp, TX_CFG_STOP_TX_); - spin_unlock_irqrestore(&lp->lock, flags); -} - -static inline void smc911x_drop_pkt(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int fifo_count, timeout, reg; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __func__); - fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF; - if (fifo_count <= 4) { - /* Manually dump the packet data */ - while (fifo_count--) - SMC_GET_RX_FIFO(lp); - } else { - /* Fast forward through the bad packet */ - SMC_SET_RX_DP_CTRL(lp, RX_DP_CTRL_FFWD_BUSY_); - timeout=50; - do { - udelay(10); - reg = SMC_GET_RX_DP_CTRL(lp) & RX_DP_CTRL_FFWD_BUSY_; - } while (--timeout && reg); - if (timeout == 0) { - PRINTK("%s: timeout waiting for RX fast forward\n", dev->name); - } - } -} - -/* - * This is the procedure to handle the receipt of a packet. - * It should be called after checking for packet presence in - * the RX status FIFO. It must be called with the spin lock - * already held. - */ -static inline void smc911x_rcv(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int pkt_len, status; - struct sk_buff *skb; - unsigned char *data; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", - dev->name, __func__); - status = SMC_GET_RX_STS_FIFO(lp); - DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x\n", - dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff); - pkt_len = (status & RX_STS_PKT_LEN_) >> 16; - if (status & RX_STS_ES_) { - /* Deal with a bad packet */ - dev->stats.rx_errors++; - if (status & RX_STS_CRC_ERR_) - dev->stats.rx_crc_errors++; - else { - if (status & RX_STS_LEN_ERR_) - dev->stats.rx_length_errors++; - if (status & RX_STS_MCAST_) - dev->stats.multicast++; - } - /* Remove the bad packet data from the RX FIFO */ - smc911x_drop_pkt(dev); - } else { - /* Receive a valid packet */ - /* Alloc a buffer with extra room for DMA alignment */ - skb = netdev_alloc_skb(dev, pkt_len+32); - if (unlikely(skb == NULL)) { - PRINTK( "%s: Low memory, rcvd packet dropped.\n", - dev->name); - dev->stats.rx_dropped++; - smc911x_drop_pkt(dev); - return; - } - /* Align IP header to 32 bits - * Note that the device is configured to add a 2 - * byte padding to the packet start, so we really - * want to write to the orignal data pointer */ - data = skb->data; - skb_reserve(skb, 2); - skb_put(skb,pkt_len-4); -#ifdef SMC_USE_DMA - { - unsigned int fifo; - /* Lower the FIFO threshold if possible */ - fifo = SMC_GET_FIFO_INT(lp); - if (fifo & 0xFF) fifo--; - DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n", - dev->name, fifo & 0xff); - SMC_SET_FIFO_INT(lp, fifo); - /* Setup RX DMA */ - SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_)); - lp->rxdma_active = 1; - lp->current_rx_skb = skb; - SMC_PULL_DATA(lp, data, (pkt_len+2+15) & ~15); - /* Packet processing deferred to DMA RX interrupt */ - } -#else - SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); - SMC_PULL_DATA(lp, data, pkt_len+2+3); - - DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name); - PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len-4; -#endif - } -} - -/* - * This is called to actually send a packet to the chip. - */ -static void smc911x_hardware_send_pkt(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - struct sk_buff *skb; - unsigned int cmdA, cmdB, len; - unsigned char *buf; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__); - BUG_ON(lp->pending_tx_skb == NULL); - - skb = lp->pending_tx_skb; - lp->pending_tx_skb = NULL; - - /* cmdA {25:24] data alignment [20:16] start offset [10:0] buffer length */ - /* cmdB {31:16] pkt tag [10:0] length */ -#ifdef SMC_USE_DMA - /* 16 byte buffer alignment mode */ - buf = (char*)((u32)(skb->data) & ~0xF); - len = (skb->len + 0xF + ((u32)skb->data & 0xF)) & ~0xF; - cmdA = (1<<24) | (((u32)skb->data & 0xF)<<16) | - TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ | - skb->len; -#else - buf = (char*)((u32)skb->data & ~0x3); - len = (skb->len + 3 + ((u32)skb->data & 3)) & ~0x3; - cmdA = (((u32)skb->data & 0x3) << 16) | - TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ | - skb->len; -#endif - /* tag is packet length so we can use this in stats update later */ - cmdB = (skb->len << 16) | (skb->len & 0x7FF); - - DBG(SMC_DEBUG_TX, "%s: TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n", - dev->name, len, len, buf, cmdA, cmdB); - SMC_SET_TX_FIFO(lp, cmdA); - SMC_SET_TX_FIFO(lp, cmdB); - - DBG(SMC_DEBUG_PKTS, "%s: Transmitted packet\n", dev->name); - PRINT_PKT(buf, len <= 64 ? len : 64); - - /* Send pkt via PIO or DMA */ -#ifdef SMC_USE_DMA - lp->current_tx_skb = skb; - SMC_PUSH_DATA(lp, buf, len); - /* DMA complete IRQ will free buffer and set jiffies */ -#else - SMC_PUSH_DATA(lp, buf, len); - dev->trans_start = jiffies; - dev_kfree_skb_irq(skb); -#endif - if (!lp->tx_throttle) { - netif_wake_queue(dev); - } - SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_); -} - -/* - * Since I am not sure if I will have enough room in the chip's ram - * to store the packet, I call this routine which either sends it - * now, or set the card to generates an interrupt when ready - * for the packet. - */ -static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int free; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", - dev->name, __func__); - - spin_lock_irqsave(&lp->lock, flags); - - BUG_ON(lp->pending_tx_skb != NULL); - - free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_; - DBG(SMC_DEBUG_TX, "%s: TX free space %d\n", dev->name, free); - - /* Turn off the flow when running out of space in FIFO */ - if (free <= SMC911X_TX_FIFO_LOW_THRESHOLD) { - DBG(SMC_DEBUG_TX, "%s: Disabling data flow due to low FIFO space (%d)\n", - dev->name, free); - /* Reenable when at least 1 packet of size MTU present */ - SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64); - lp->tx_throttle = 1; - netif_stop_queue(dev); - } - - /* Drop packets when we run out of space in TX FIFO - * Account for overhead required for: - * - * Tx command words 8 bytes - * Start offset 15 bytes - * End padding 15 bytes - */ - if (unlikely(free < (skb->len + 8 + 15 + 15))) { - printk("%s: No Tx free space %d < %d\n", - dev->name, free, skb->len); - lp->pending_tx_skb = NULL; - dev->stats.tx_errors++; - dev->stats.tx_dropped++; - spin_unlock_irqrestore(&lp->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - -#ifdef SMC_USE_DMA - { - /* If the DMA is already running then defer this packet Tx until - * the DMA IRQ starts it - */ - if (lp->txdma_active) { - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Tx DMA running, deferring packet\n", dev->name); - lp->pending_tx_skb = skb; - netif_stop_queue(dev); - spin_unlock_irqrestore(&lp->lock, flags); - return NETDEV_TX_OK; - } else { - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name); - lp->txdma_active = 1; - } - } -#endif - lp->pending_tx_skb = skb; - smc911x_hardware_send_pkt(dev); - spin_unlock_irqrestore(&lp->lock, flags); - - return NETDEV_TX_OK; -} - -/* - * This handles a TX status interrupt, which is only called when: - * - a TX error occurred, or - * - TX of a packet completed. - */ -static void smc911x_tx(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int tx_status; - - DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", - dev->name, __func__); - - /* Collect the TX status */ - while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) { - DBG(SMC_DEBUG_TX, "%s: Tx stat FIFO used 0x%04x\n", - dev->name, - (SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16); - tx_status = SMC_GET_TX_STS_FIFO(lp); - dev->stats.tx_packets++; - dev->stats.tx_bytes+=tx_status>>16; - DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n", - dev->name, (tx_status & 0xffff0000) >> 16, - tx_status & 0x0000ffff); - /* count Tx errors, but ignore lost carrier errors when in - * full-duplex mode */ - if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx && - !(tx_status & 0x00000306))) { - dev->stats.tx_errors++; - } - if (tx_status & TX_STS_MANY_COLL_) { - dev->stats.collisions+=16; - dev->stats.tx_aborted_errors++; - } else { - dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3; - } - /* carrier error only has meaning for half-duplex communication */ - if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) && - !lp->ctl_rfduplx) { - dev->stats.tx_carrier_errors++; - } - if (tx_status & TX_STS_LATE_COLL_) { - dev->stats.collisions++; - dev->stats.tx_aborted_errors++; - } - } -} - - -/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ -/* - * Reads a register from the MII Management serial interface - */ - -static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int phydata; - - SMC_GET_MII(lp, phyreg, phyaddr, phydata); - - DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n", - __func__, phyaddr, phyreg, phydata); - return phydata; -} - - -/* - * Writes a register to the MII Management serial interface - */ -static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg, - int phydata) -{ - struct smc911x_local *lp = netdev_priv(dev); - - DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __func__, phyaddr, phyreg, phydata); - - SMC_SET_MII(lp, phyreg, phyaddr, phydata); -} - -/* - * Finds and reports the PHY address (115 and 117 have external - * PHY interface 118 has internal only - */ -static void smc911x_phy_detect(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr; - unsigned int cfg, id1, id2; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - lp->phy_type = 0; - - /* - * Scan all 32 PHY addresses if necessary, starting at - * PHY#1 to PHY#31, and then PHY#0 last. - */ - switch(lp->version) { - case CHIP_9115: - case CHIP_9117: - case CHIP_9215: - case CHIP_9217: - cfg = SMC_GET_HW_CFG(lp); - if (cfg & HW_CFG_EXT_PHY_DET_) { - cfg &= ~HW_CFG_PHY_CLK_SEL_; - cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - SMC_SET_HW_CFG(lp, cfg); - udelay(10); /* Wait for clocks to stop */ - - cfg |= HW_CFG_EXT_PHY_EN_; - SMC_SET_HW_CFG(lp, cfg); - udelay(10); /* Wait for clocks to stop */ - - cfg &= ~HW_CFG_PHY_CLK_SEL_; - cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; - SMC_SET_HW_CFG(lp, cfg); - udelay(10); /* Wait for clocks to stop */ - - cfg |= HW_CFG_SMI_SEL_; - SMC_SET_HW_CFG(lp, cfg); - - for (phyaddr = 1; phyaddr < 32; ++phyaddr) { - - /* Read the PHY identifiers */ - SMC_GET_PHY_ID1(lp, phyaddr & 31, id1); - SMC_GET_PHY_ID2(lp, phyaddr & 31, id2); - - /* Make sure it is a valid identifier */ - if (id1 != 0x0000 && id1 != 0xffff && - id1 != 0x8000 && id2 != 0x0000 && - id2 != 0xffff && id2 != 0x8000) { - /* Save the PHY's address */ - lp->mii.phy_id = phyaddr & 31; - lp->phy_type = id1 << 16 | id2; - break; - } - } - if (phyaddr < 32) - /* Found an external PHY */ - break; - } - default: - /* Internal media only */ - SMC_GET_PHY_ID1(lp, 1, id1); - SMC_GET_PHY_ID2(lp, 1, id2); - /* Save the PHY's address */ - lp->mii.phy_id = 1; - lp->phy_type = id1 << 16 | id2; - } - - DBG(SMC_DEBUG_MISC, "%s: phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%d\n", - dev->name, id1, id2, lp->mii.phy_id); -} - -/* - * Sets the PHY to a configuration as determined by the user. - * Called with spin_lock held. - */ -static int smc911x_phy_fixed(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - int bmcr; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - /* Enter Link Disable state */ - SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); - bmcr |= BMCR_PDOWN; - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - - /* - * Set our fixed capabilities - * Disable auto-negotiation - */ - bmcr &= ~BMCR_ANENABLE; - if (lp->ctl_rfduplx) - bmcr |= BMCR_FULLDPLX; - - if (lp->ctl_rspeed == 100) - bmcr |= BMCR_SPEED100; - - /* Write our capabilities to the phy control register */ - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - - /* Re-Configure the Receive/Phy Control register */ - bmcr &= ~BMCR_PDOWN; - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - - return 1; -} - -/* - * smc911x_phy_reset - reset the phy - * @dev: net device - * @phy: phy address - * - * Issue a software reset for the specified PHY and - * wait up to 100ms for the reset to complete. We should - * not access the PHY for 50ms after issuing the reset. - * - * The time to wait appears to be dependent on the PHY. - * - */ -static int smc911x_phy_reset(struct net_device *dev, int phy) -{ - struct smc911x_local *lp = netdev_priv(dev); - int timeout; - unsigned long flags; - unsigned int reg; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__); - - spin_lock_irqsave(&lp->lock, flags); - reg = SMC_GET_PMT_CTRL(lp); - reg &= ~0xfffff030; - reg |= PMT_CTRL_PHY_RST_; - SMC_SET_PMT_CTRL(lp, reg); - spin_unlock_irqrestore(&lp->lock, flags); - for (timeout = 2; timeout; timeout--) { - msleep(50); - spin_lock_irqsave(&lp->lock, flags); - reg = SMC_GET_PMT_CTRL(lp); - spin_unlock_irqrestore(&lp->lock, flags); - if (!(reg & PMT_CTRL_PHY_RST_)) { - /* extra delay required because the phy may - * not be completed with its reset - * when PHY_BCR_RESET_ is cleared. 256us - * should suffice, but use 500us to be safe - */ - udelay(500); - break; - } - } - - return reg & PMT_CTRL_PHY_RST_; -} - -/* - * smc911x_phy_powerdown - powerdown phy - * @dev: net device - * @phy: phy address - * - * Power down the specified PHY - */ -static void smc911x_phy_powerdown(struct net_device *dev, int phy) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int bmcr; - - /* Enter Link Disable state */ - SMC_GET_PHY_BMCR(lp, phy, bmcr); - bmcr |= BMCR_PDOWN; - SMC_SET_PHY_BMCR(lp, phy, bmcr); -} - -/* - * smc911x_phy_check_media - check the media status and adjust BMCR - * @dev: net device - * @init: set true for initialisation - * - * Select duplex mode depending on negotiation state. This - * also updates our carrier state. - */ -static void smc911x_phy_check_media(struct net_device *dev, int init) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - unsigned int bmcr, cr; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { - /* duplex state has changed */ - SMC_GET_PHY_BMCR(lp, phyaddr, bmcr); - SMC_GET_MAC_CR(lp, cr); - if (lp->mii.full_duplex) { - DBG(SMC_DEBUG_MISC, "%s: Configuring for full-duplex mode\n", dev->name); - bmcr |= BMCR_FULLDPLX; - cr |= MAC_CR_RCVOWN_; - } else { - DBG(SMC_DEBUG_MISC, "%s: Configuring for half-duplex mode\n", dev->name); - bmcr &= ~BMCR_FULLDPLX; - cr &= ~MAC_CR_RCVOWN_; - } - SMC_SET_PHY_BMCR(lp, phyaddr, bmcr); - SMC_SET_MAC_CR(lp, cr); - } -} - -/* - * Configures the specified PHY through the MII management interface - * using Autonegotiation. - * Calls smc911x_phy_fixed() if the user has requested a certain config. - * If RPC ANEG bit is set, the media selection is dependent purely on - * the selection by the MII (either in the MII BMCR reg or the result - * of autonegotiation.) If the RPC ANEG bit is cleared, the selection - * is controlled by the RPC SPEED and RPC DPLX bits. - */ -static void smc911x_phy_configure(struct work_struct *work) -{ - struct smc911x_local *lp = container_of(work, struct smc911x_local, - phy_configure); - struct net_device *dev = lp->netdev; - int phyaddr = lp->mii.phy_id; - int my_phy_caps; /* My PHY capabilities */ - int my_ad_caps; /* My Advertised capabilities */ - int status; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__); - - /* - * We should not be called if phy_type is zero. - */ - if (lp->phy_type == 0) - return; - - if (smc911x_phy_reset(dev, phyaddr)) { - printk("%s: PHY reset timed out\n", dev->name); - return; - } - spin_lock_irqsave(&lp->lock, flags); - - /* - * Enable PHY Interrupts (for register 18) - * Interrupts listed here are enabled - */ - SMC_SET_PHY_INT_MASK(lp, phyaddr, PHY_INT_MASK_ENERGY_ON_ | - PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ | - PHY_INT_MASK_LINK_DOWN_); - - /* If the user requested no auto neg, then go set his request */ - if (lp->mii.force_media) { - smc911x_phy_fixed(dev); - goto smc911x_phy_configure_exit; - } - - /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ - SMC_GET_PHY_BMSR(lp, phyaddr, my_phy_caps); - if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { - printk(KERN_INFO "Auto negotiation NOT supported\n"); - smc911x_phy_fixed(dev); - goto smc911x_phy_configure_exit; - } - - /* CSMA capable w/ both pauses */ - my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - - if (my_phy_caps & BMSR_100BASE4) - my_ad_caps |= ADVERTISE_100BASE4; - if (my_phy_caps & BMSR_100FULL) - my_ad_caps |= ADVERTISE_100FULL; - if (my_phy_caps & BMSR_100HALF) - my_ad_caps |= ADVERTISE_100HALF; - if (my_phy_caps & BMSR_10FULL) - my_ad_caps |= ADVERTISE_10FULL; - if (my_phy_caps & BMSR_10HALF) - my_ad_caps |= ADVERTISE_10HALF; - - /* Disable capabilities not selected by our user */ - if (lp->ctl_rspeed != 100) - my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); - - if (!lp->ctl_rfduplx) - my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); - - /* Update our Auto-Neg Advertisement Register */ - SMC_SET_PHY_MII_ADV(lp, phyaddr, my_ad_caps); - lp->mii.advertising = my_ad_caps; - - /* - * Read the register back. Without this, it appears that when - * auto-negotiation is restarted, sometimes it isn't ready and - * the link does not come up. - */ - udelay(10); - SMC_GET_PHY_MII_ADV(lp, phyaddr, status); - - DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps); - DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps); - - /* Restart auto-negotiation process in order to advertise my caps */ - SMC_SET_PHY_BMCR(lp, phyaddr, BMCR_ANENABLE | BMCR_ANRESTART); - - smc911x_phy_check_media(dev, 1); - -smc911x_phy_configure_exit: - spin_unlock_irqrestore(&lp->lock, flags); -} - -/* - * smc911x_phy_interrupt - * - * Purpose: Handle interrupts relating to PHY register 18. This is - * called from the "hard" interrupt handler under our private spinlock. - */ -static void smc911x_phy_interrupt(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - int status; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - if (lp->phy_type == 0) - return; - - smc911x_phy_check_media(dev, 0); - /* read to clear status bits */ - SMC_GET_PHY_INT_SRC(lp, phyaddr,status); - DBG(SMC_DEBUG_MISC, "%s: PHY interrupt status 0x%04x\n", - dev->name, status & 0xffff); - DBG(SMC_DEBUG_MISC, "%s: AFC_CFG 0x%08x\n", - dev->name, SMC_GET_AFC_CFG(lp)); -} - -/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ - -/* - * This is the main routine of the driver, to handle the device when - * it needs some attention. - */ -static irqreturn_t smc911x_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smc911x_local *lp = netdev_priv(dev); - unsigned int status, mask, timeout; - unsigned int rx_overrun=0, cr, pkts; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - spin_lock_irqsave(&lp->lock, flags); - - /* Spurious interrupt check */ - if ((SMC_GET_IRQ_CFG(lp) & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != - (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) { - spin_unlock_irqrestore(&lp->lock, flags); - return IRQ_NONE; - } - - mask = SMC_GET_INT_EN(lp); - SMC_SET_INT_EN(lp, 0); - - /* set a timeout value, so I don't stay here forever */ - timeout = 8; - - - do { - status = SMC_GET_INT(lp); - - DBG(SMC_DEBUG_MISC, "%s: INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n", - dev->name, status, mask, status & ~mask); - - status &= mask; - if (!status) - break; - - /* Handle SW interrupt condition */ - if (status & INT_STS_SW_INT_) { - SMC_ACK_INT(lp, INT_STS_SW_INT_); - mask &= ~INT_EN_SW_INT_EN_; - } - /* Handle various error conditions */ - if (status & INT_STS_RXE_) { - SMC_ACK_INT(lp, INT_STS_RXE_); - dev->stats.rx_errors++; - } - if (status & INT_STS_RXDFH_INT_) { - SMC_ACK_INT(lp, INT_STS_RXDFH_INT_); - dev->stats.rx_dropped+=SMC_GET_RX_DROP(lp); - } - /* Undocumented interrupt-what is the right thing to do here? */ - if (status & INT_STS_RXDF_INT_) { - SMC_ACK_INT(lp, INT_STS_RXDF_INT_); - } - - /* Rx Data FIFO exceeds set level */ - if (status & INT_STS_RDFL_) { - if (IS_REV_A(lp->revision)) { - rx_overrun=1; - SMC_GET_MAC_CR(lp, cr); - cr &= ~MAC_CR_RXEN_; - SMC_SET_MAC_CR(lp, cr); - DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - } - SMC_ACK_INT(lp, INT_STS_RDFL_); - } - if (status & INT_STS_RDFO_) { - if (!IS_REV_A(lp->revision)) { - SMC_GET_MAC_CR(lp, cr); - cr &= ~MAC_CR_RXEN_; - SMC_SET_MAC_CR(lp, cr); - rx_overrun=1; - DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name); - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - } - SMC_ACK_INT(lp, INT_STS_RDFO_); - } - /* Handle receive condition */ - if ((status & INT_STS_RSFL_) || rx_overrun) { - unsigned int fifo; - DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name); - fifo = SMC_GET_RX_FIFO_INF(lp); - pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16; - DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n", - dev->name, pkts, fifo & 0xFFFF ); - if (pkts != 0) { -#ifdef SMC_USE_DMA - unsigned int fifo; - if (lp->rxdma_active){ - DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, - "%s: RX DMA active\n", dev->name); - /* The DMA is already running so up the IRQ threshold */ - fifo = SMC_GET_FIFO_INT(lp) & ~0xFF; - fifo |= pkts & 0xFF; - DBG(SMC_DEBUG_RX, - "%s: Setting RX stat FIFO threshold to %d\n", - dev->name, fifo & 0xff); - SMC_SET_FIFO_INT(lp, fifo); - } else -#endif - smc911x_rcv(dev); - } - SMC_ACK_INT(lp, INT_STS_RSFL_); - } - /* Handle transmit FIFO available */ - if (status & INT_STS_TDFA_) { - DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name); - SMC_SET_FIFO_TDA(lp, 0xFF); - lp->tx_throttle = 0; -#ifdef SMC_USE_DMA - if (!lp->txdma_active) -#endif - netif_wake_queue(dev); - SMC_ACK_INT(lp, INT_STS_TDFA_); - } - /* Handle transmit done condition */ -#if 1 - if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) { - DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC, - "%s: Tx stat FIFO limit (%d) /GPT irq\n", - dev->name, (SMC_GET_FIFO_INT(lp) & 0x00ff0000) >> 16); - smc911x_tx(dev); - SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - SMC_ACK_INT(lp, INT_STS_TSFL_); - SMC_ACK_INT(lp, INT_STS_TSFL_ | INT_STS_GPT_INT_); - } -#else - if (status & INT_STS_TSFL_) { - DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq\n", dev->name, ); - smc911x_tx(dev); - SMC_ACK_INT(lp, INT_STS_TSFL_); - } - - if (status & INT_STS_GPT_INT_) { - DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n", - dev->name, - SMC_GET_IRQ_CFG(lp), - SMC_GET_FIFO_INT(lp), - SMC_GET_RX_CFG(lp)); - DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x " - "Data FIFO Used 0x%04x Stat FIFO 0x%08x\n", - dev->name, - (SMC_GET_RX_FIFO_INF(lp) & 0x00ff0000) >> 16, - SMC_GET_RX_FIFO_INF(lp) & 0xffff, - SMC_GET_RX_STS_FIFO_PEEK(lp)); - SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000); - SMC_ACK_INT(lp, INT_STS_GPT_INT_); - } -#endif - - /* Handle PHY interrupt condition */ - if (status & INT_STS_PHY_INT_) { - DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name); - smc911x_phy_interrupt(dev); - SMC_ACK_INT(lp, INT_STS_PHY_INT_); - } - } while (--timeout); - - /* restore mask state */ - SMC_SET_INT_EN(lp, mask); - - DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n", - dev->name, 8-timeout); - - spin_unlock_irqrestore(&lp->lock, flags); - - return IRQ_HANDLED; -} - -#ifdef SMC_USE_DMA -static void -smc911x_tx_dma_irq(int dma, void *data) -{ - struct net_device *dev = (struct net_device *)data; - struct smc911x_local *lp = netdev_priv(dev); - struct sk_buff *skb = lp->current_tx_skb; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name); - /* Clear the DMA interrupt sources */ - SMC_DMA_ACK_IRQ(dev, dma); - BUG_ON(skb == NULL); - dma_unmap_single(NULL, tx_dmabuf, tx_dmalen, DMA_TO_DEVICE); - dev->trans_start = jiffies; - dev_kfree_skb_irq(skb); - lp->current_tx_skb = NULL; - if (lp->pending_tx_skb != NULL) - smc911x_hardware_send_pkt(dev); - else { - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, - "%s: No pending Tx packets. DMA disabled\n", dev->name); - spin_lock_irqsave(&lp->lock, flags); - lp->txdma_active = 0; - if (!lp->tx_throttle) { - netif_wake_queue(dev); - } - spin_unlock_irqrestore(&lp->lock, flags); - } - - DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, - "%s: TX DMA irq completed\n", dev->name); -} -static void -smc911x_rx_dma_irq(int dma, void *data) -{ - struct net_device *dev = (struct net_device *)data; - unsigned long ioaddr = dev->base_addr; - struct smc911x_local *lp = netdev_priv(dev); - struct sk_buff *skb = lp->current_rx_skb; - unsigned long flags; - unsigned int pkts; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name); - /* Clear the DMA interrupt sources */ - SMC_DMA_ACK_IRQ(dev, dma); - dma_unmap_single(NULL, rx_dmabuf, rx_dmalen, DMA_FROM_DEVICE); - BUG_ON(skb == NULL); - lp->current_rx_skb = NULL; - PRINT_PKT(skb->data, skb->len); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - - spin_lock_irqsave(&lp->lock, flags); - pkts = (SMC_GET_RX_FIFO_INF(lp) & RX_FIFO_INF_RXSUSED_) >> 16; - if (pkts != 0) { - smc911x_rcv(dev); - }else { - lp->rxdma_active = 0; - } - spin_unlock_irqrestore(&lp->lock, flags); - DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, - "%s: RX DMA irq completed. DMA RX FIFO PKTS %d\n", - dev->name, pkts); -} -#endif /* SMC_USE_DMA */ - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void smc911x_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - smc911x_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -/* Our watchdog timed out. Called by the networking layer */ -static void smc911x_timeout(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int status, mask; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - spin_lock_irqsave(&lp->lock, flags); - status = SMC_GET_INT(lp); - mask = SMC_GET_INT_EN(lp); - spin_unlock_irqrestore(&lp->lock, flags); - DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x\n", - dev->name, status, mask); - - /* Dump the current TX FIFO contents and restart */ - mask = SMC_GET_TX_CFG(lp); - SMC_SET_TX_CFG(lp, mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_); - /* - * Reconfiguring the PHY doesn't seem like a bad idea here, but - * smc911x_phy_configure() calls msleep() which calls schedule_timeout() - * which calls schedule(). Hence we use a work queue. - */ - if (lp->phy_type != 0) - schedule_work(&lp->phy_configure); - - /* We can accept TX packets again */ - dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(dev); -} - -/* - * This routine will, depending on the values passed to it, - * either make it accept multicast packets, go into - * promiscuous mode (for TCPDUMP and cousins) or accept - * a select set of multicast packets - */ -static void smc911x_set_multicast_list(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int multicast_table[2]; - unsigned int mcr, update_multicast = 0; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CR(lp, mcr); - spin_unlock_irqrestore(&lp->lock, flags); - - if (dev->flags & IFF_PROMISC) { - - DBG(SMC_DEBUG_MISC, "%s: RCR_PRMS\n", dev->name); - mcr |= MAC_CR_PRMS_; - } - /* - * Here, I am setting this to accept all multicast packets. - * I don't need to zero the multicast table, because the flag is - * checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { - DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name); - mcr |= MAC_CR_MCPAS_; - } - - /* - * This sets the internal hardware table to filter out unwanted - * multicast packets before they take up memory. - * - * The SMC chip uses a hash table where the high 6 bits of the CRC of - * address are the offset into the table. If that bit is 1, then the - * multicast packet is accepted. Otherwise, it's dropped silently. - * - * To use the 6 bits as an offset into the table, the high 1 bit is - * the number of the 32 bit register, while the low 5 bits are the bit - * within that register. - */ - else if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - /* Set the Hash perfec mode */ - mcr |= MAC_CR_HPFILT_; - - /* start with a table of all zeros: reject all */ - memset(multicast_table, 0, sizeof(multicast_table)); - - netdev_for_each_mc_addr(ha, dev) { - u32 position; - - /* upper 6 bits are used as hash index */ - position = ether_crc(ETH_ALEN, ha->addr)>>26; - - multicast_table[position>>5] |= 1 << (position&0x1f); - } - - /* be sure I get rid of flags I might have set */ - mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - /* now, the table can be loaded into the chipset */ - update_multicast = 1; - } else { - DBG(SMC_DEBUG_MISC, "%s: ~(MAC_CR_PRMS_|MAC_CR_MCPAS_)\n", - dev->name); - mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - /* - * since I'm disabling all multicast entirely, I need to - * clear the multicast list - */ - memset(multicast_table, 0, sizeof(multicast_table)); - update_multicast = 1; - } - - spin_lock_irqsave(&lp->lock, flags); - SMC_SET_MAC_CR(lp, mcr); - if (update_multicast) { - DBG(SMC_DEBUG_MISC, - "%s: update mcast hash table 0x%08x 0x%08x\n", - dev->name, multicast_table[0], multicast_table[1]); - SMC_SET_HASHL(lp, multicast_table[0]); - SMC_SET_HASHH(lp, multicast_table[1]); - } - spin_unlock_irqrestore(&lp->lock, flags); -} - - -/* - * Open and Initialize the board - * - * Set up everything, reset the card, etc.. - */ -static int -smc911x_open(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - /* - * Check that the address is valid. If its not, refuse - * to bring the device up. The user must specify an - * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx - */ - if (!is_valid_ether_addr(dev->dev_addr)) { - PRINTK("%s: no valid ethernet hw addr\n", __func__); - return -EINVAL; - } - - /* reset the hardware */ - smc911x_reset(dev); - - /* Configure the PHY, initialize the link state */ - smc911x_phy_configure(&lp->phy_configure); - - /* Turn on Tx + Rx */ - smc911x_enable(dev); - - netif_start_queue(dev); - - return 0; -} - -/* - * smc911x_close - * - * this makes the board clean up everything that it can - * and not talk to the outside world. Caused by - * an 'ifconfig ethX down' - */ -static int smc911x_close(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - netif_stop_queue(dev); - netif_carrier_off(dev); - - /* clear everything */ - smc911x_shutdown(dev); - - if (lp->phy_type != 0) { - /* We need to ensure that no calls to - * smc911x_phy_configure are pending. - */ - cancel_work_sync(&lp->phy_configure); - smc911x_phy_powerdown(dev, lp->mii.phy_id); - } - - if (lp->pending_tx_skb) { - dev_kfree_skb(lp->pending_tx_skb); - lp->pending_tx_skb = NULL; - } - - return 0; -} - -/* - * Ethtool support - */ -static int -smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret, status; - unsigned long flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - cmd->maxtxpkt = 1; - cmd->maxrxpkt = 1; - - if (lp->phy_type != 0) { - spin_lock_irqsave(&lp->lock, flags); - ret = mii_ethtool_gset(&lp->mii, cmd); - spin_unlock_irqrestore(&lp->lock, flags); - } else { - cmd->supported = SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_TP | SUPPORTED_AUI; - - if (lp->ctl_rspeed == 10) - ethtool_cmd_speed_set(cmd, SPEED_10); - else if (lp->ctl_rspeed == 100) - ethtool_cmd_speed_set(cmd, SPEED_100); - - cmd->autoneg = AUTONEG_DISABLE; - if (lp->mii.phy_id==1) - cmd->transceiver = XCVR_INTERNAL; - else - cmd->transceiver = XCVR_EXTERNAL; - cmd->port = 0; - SMC_GET_PHY_SPECIAL(lp, lp->mii.phy_id, status); - cmd->duplex = - (status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ? - DUPLEX_FULL : DUPLEX_HALF; - ret = 0; - } - - return ret; -} - -static int -smc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - unsigned long flags; - - if (lp->phy_type != 0) { - spin_lock_irqsave(&lp->lock, flags); - ret = mii_ethtool_sset(&lp->mii, cmd); - spin_unlock_irqrestore(&lp->lock, flags); - } else { - if (cmd->autoneg != AUTONEG_DISABLE || - cmd->speed != SPEED_10 || - (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) || - (cmd->port != PORT_TP && cmd->port != PORT_AUI)) - return -EINVAL; - - lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL; - - ret = 0; - } - - return ret; -} - -static void -smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strncpy(info->driver, CARDNAME, sizeof(info->driver)); - strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info)); -} - -static int smc911x_ethtool_nwayreset(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret = -EINVAL; - unsigned long flags; - - if (lp->phy_type != 0) { - spin_lock_irqsave(&lp->lock, flags); - ret = mii_nway_restart(&lp->mii); - spin_unlock_irqrestore(&lp->lock, flags); - } - - return ret; -} - -static u32 smc911x_ethtool_getmsglevel(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - return lp->msg_enable; -} - -static void smc911x_ethtool_setmsglevel(struct net_device *dev, u32 level) -{ - struct smc911x_local *lp = netdev_priv(dev); - lp->msg_enable = level; -} - -static int smc911x_ethtool_getregslen(struct net_device *dev) -{ - /* System regs + MAC regs + PHY regs */ - return (((E2P_CMD - ID_REV)/4 + 1) + - (WUCSR - MAC_CR)+1 + 32) * sizeof(u32); -} - -static void smc911x_ethtool_getregs(struct net_device *dev, - struct ethtool_regs* regs, void *buf) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned long flags; - u32 reg,i,j=0; - u32 *data = (u32*)buf; - - regs->version = lp->version; - for(i=ID_REV;i<=E2P_CMD;i+=4) { - data[j++] = SMC_inl(lp, i); - } - for(i=MAC_CR;i<=WUCSR;i++) { - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MAC_CSR(lp, i, reg); - spin_unlock_irqrestore(&lp->lock, flags); - data[j++] = reg; - } - for(i=0;i<=31;i++) { - spin_lock_irqsave(&lp->lock, flags); - SMC_GET_MII(lp, i, lp->mii.phy_id, reg); - spin_unlock_irqrestore(&lp->lock, flags); - data[j++] = reg & 0xFFFF; - } -} - -static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - unsigned int timeout; - int e2p_cmd; - - e2p_cmd = SMC_GET_E2P_CMD(lp); - for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) { - if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) { - PRINTK("%s: %s timeout waiting for EEPROM to respond\n", - dev->name, __func__); - return -EFAULT; - } - mdelay(1); - e2p_cmd = SMC_GET_E2P_CMD(lp); - } - if (timeout == 0) { - PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n", - dev->name, __func__); - return -ETIMEDOUT; - } - return 0; -} - -static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev, - int cmd, int addr) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - - if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) - return ret; - SMC_SET_E2P_CMD(lp, E2P_CMD_EPC_BUSY_ | - ((cmd) & (0x7<<28)) | - ((addr) & 0xFF)); - return 0; -} - -static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev, - u8 *data) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - - if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) - return ret; - *data = SMC_GET_E2P_DATA(lp); - return 0; -} - -static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev, - u8 data) -{ - struct smc911x_local *lp = netdev_priv(dev); - int ret; - - if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0) - return ret; - SMC_SET_E2P_DATA(lp, data); - return 0; -} - -static int smc911x_ethtool_geteeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - u8 eebuf[SMC911X_EEPROM_LEN]; - int i, ret; - - for(i=0;i<SMC911X_EEPROM_LEN;i++) { - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ_, i ))!=0) - return ret; - if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0) - return ret; - } - memcpy(data, eebuf+eeprom->offset, eeprom->len); - return 0; -} - -static int smc911x_ethtool_seteeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - int i, ret; - - /* Enable erase */ - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN_, 0 ))!=0) - return ret; - for(i=eeprom->offset;i<(eeprom->offset+eeprom->len);i++) { - /* erase byte */ - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE_, i ))!=0) - return ret; - /* write byte */ - if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0) - return ret; - if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0) - return ret; - } - return 0; -} - -static int smc911x_ethtool_geteeprom_len(struct net_device *dev) -{ - return SMC911X_EEPROM_LEN; -} - -static const struct ethtool_ops smc911x_ethtool_ops = { - .get_settings = smc911x_ethtool_getsettings, - .set_settings = smc911x_ethtool_setsettings, - .get_drvinfo = smc911x_ethtool_getdrvinfo, - .get_msglevel = smc911x_ethtool_getmsglevel, - .set_msglevel = smc911x_ethtool_setmsglevel, - .nway_reset = smc911x_ethtool_nwayreset, - .get_link = ethtool_op_get_link, - .get_regs_len = smc911x_ethtool_getregslen, - .get_regs = smc911x_ethtool_getregs, - .get_eeprom_len = smc911x_ethtool_geteeprom_len, - .get_eeprom = smc911x_ethtool_geteeprom, - .set_eeprom = smc911x_ethtool_seteeprom, -}; - -/* - * smc911x_findirq - * - * This routine has a simple purpose -- make the SMC chip generate an - * interrupt, so an auto-detect routine can detect it, and find the IRQ, - */ -static int __devinit smc911x_findirq(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int timeout = 20; - unsigned long cookie; - - DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); - - cookie = probe_irq_on(); - - /* - * Force a SW interrupt - */ - - SMC_SET_INT_EN(lp, INT_EN_SW_INT_EN_); - - /* - * Wait until positive that the interrupt has been generated - */ - do { - int int_status; - udelay(10); - int_status = SMC_GET_INT_EN(lp); - if (int_status & INT_EN_SW_INT_EN_) - break; /* got the interrupt */ - } while (--timeout); - - /* - * there is really nothing that I can do here if timeout fails, - * as autoirq_report will return a 0 anyway, which is what I - * want in this case. Plus, the clean up is needed in both - * cases. - */ - - /* and disable all interrupts again */ - SMC_SET_INT_EN(lp, 0); - - /* and return what I found */ - return probe_irq_off(cookie); -} - -static const struct net_device_ops smc911x_netdev_ops = { - .ndo_open = smc911x_open, - .ndo_stop = smc911x_close, - .ndo_start_xmit = smc911x_hard_start_xmit, - .ndo_tx_timeout = smc911x_timeout, - .ndo_set_rx_mode = smc911x_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = smc911x_poll_controller, -#endif -}; - -/* - * Function: smc911x_probe(unsigned long ioaddr) - * - * Purpose: - * Tests to see if a given ioaddr points to an SMC911x chip. - * Returns a 0 on success - * - * Algorithm: - * (1) see if the endian word is OK - * (1) see if I recognize the chip ID in the appropriate register - * - * Here I do typical initialization tasks. - * - * o Initialize the structure if needed - * o print out my vanity message if not done so already - * o print out what type of hardware is detected - * o print out the ethernet address - * o find the IRQ - * o set up my private data - * o configure the dev structure with my subroutines - * o actually GRAB the irq. - * o GRAB the region - */ -static int __devinit smc911x_probe(struct net_device *dev) -{ - struct smc911x_local *lp = netdev_priv(dev); - int i, retval; - unsigned int val, chip_id, revision; - const char *version_string; - unsigned long irq_flags; - - DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__); - - /* First, see if the endian word is recognized */ - val = SMC_GET_BYTE_TEST(lp); - DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val); - if (val != 0x87654321) { - printk(KERN_ERR "Invalid chip endian 0x%08x\n",val); - retval = -ENODEV; - goto err_out; - } - - /* - * check if the revision register is something that I - * recognize. These might need to be added to later, - * as future revisions could be added. - */ - chip_id = SMC_GET_PN(lp); - DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id); - for(i=0;chip_ids[i].id != 0; i++) { - if (chip_ids[i].id == chip_id) break; - } - if (!chip_ids[i].id) { - printk(KERN_ERR "Unknown chip ID %04x\n", chip_id); - retval = -ENODEV; - goto err_out; - } - version_string = chip_ids[i].name; - - revision = SMC_GET_REV(lp); - DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision); - - /* At this point I'll assume that the chip is an SMC911x. */ - DBG(SMC_DEBUG_MISC, "%s: Found a %s\n", CARDNAME, chip_ids[i].name); - - /* Validate the TX FIFO size requested */ - if ((tx_fifo_kb < 2) || (tx_fifo_kb > 14)) { - printk(KERN_ERR "Invalid TX FIFO size requested %d\n", tx_fifo_kb); - retval = -EINVAL; - goto err_out; - } - - /* fill in some of the fields */ - lp->version = chip_ids[i].id; - lp->revision = revision; - lp->tx_fifo_kb = tx_fifo_kb; - /* Reverse calculate the RX FIFO size from the TX */ - lp->tx_fifo_size=(lp->tx_fifo_kb<<10) - 512; - lp->rx_fifo_size= ((0x4000 - 512 - lp->tx_fifo_size) / 16) * 15; - - /* Set the automatic flow control values */ - switch(lp->tx_fifo_kb) { - /* - * AFC_HI is about ((Rx Data Fifo Size)*2/3)/64 - * AFC_LO is AFC_HI/2 - * BACK_DUR is about 5uS*(AFC_LO) rounded down - */ - case 2:/* 13440 Rx Data Fifo Size */ - lp->afc_cfg=0x008C46AF;break; - case 3:/* 12480 Rx Data Fifo Size */ - lp->afc_cfg=0x0082419F;break; - case 4:/* 11520 Rx Data Fifo Size */ - lp->afc_cfg=0x00783C9F;break; - case 5:/* 10560 Rx Data Fifo Size */ - lp->afc_cfg=0x006E374F;break; - case 6:/* 9600 Rx Data Fifo Size */ - lp->afc_cfg=0x0064328F;break; - case 7:/* 8640 Rx Data Fifo Size */ - lp->afc_cfg=0x005A2D7F;break; - case 8:/* 7680 Rx Data Fifo Size */ - lp->afc_cfg=0x0050287F;break; - case 9:/* 6720 Rx Data Fifo Size */ - lp->afc_cfg=0x0046236F;break; - case 10:/* 5760 Rx Data Fifo Size */ - lp->afc_cfg=0x003C1E6F;break; - case 11:/* 4800 Rx Data Fifo Size */ - lp->afc_cfg=0x0032195F;break; - /* - * AFC_HI is ~1520 bytes less than RX Data Fifo Size - * AFC_LO is AFC_HI/2 - * BACK_DUR is about 5uS*(AFC_LO) rounded down - */ - case 12:/* 3840 Rx Data Fifo Size */ - lp->afc_cfg=0x0024124F;break; - case 13:/* 2880 Rx Data Fifo Size */ - lp->afc_cfg=0x0015073F;break; - case 14:/* 1920 Rx Data Fifo Size */ - lp->afc_cfg=0x0006032F;break; - default: - PRINTK("%s: ERROR -- no AFC_CFG setting found", - dev->name); - break; - } - - DBG(SMC_DEBUG_MISC | SMC_DEBUG_TX | SMC_DEBUG_RX, - "%s: tx_fifo %d rx_fifo %d afc_cfg 0x%08x\n", CARDNAME, - lp->tx_fifo_size, lp->rx_fifo_size, lp->afc_cfg); - - spin_lock_init(&lp->lock); - - /* Get the MAC address */ - SMC_GET_MAC_ADDR(lp, dev->dev_addr); - - /* now, reset the chip, and put it into a known state */ - smc911x_reset(dev); - - /* - * If dev->irq is 0, then the device has to be banged on to see - * what the IRQ is. - * - * Specifying an IRQ is done with the assumption that the user knows - * what (s)he is doing. No checking is done!!!! - */ - if (dev->irq < 1) { - int trials; - - trials = 3; - while (trials--) { - dev->irq = smc911x_findirq(dev); - if (dev->irq) - break; - /* kick the card and try again */ - smc911x_reset(dev); - } - } - if (dev->irq == 0) { - printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", - dev->name); - retval = -ENODEV; - goto err_out; - } - dev->irq = irq_canonicalize(dev->irq); - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - dev->netdev_ops = &smc911x_netdev_ops; - dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->ethtool_ops = &smc911x_ethtool_ops; - - INIT_WORK(&lp->phy_configure, smc911x_phy_configure); - lp->mii.phy_id_mask = 0x1f; - lp->mii.reg_num_mask = 0x1f; - lp->mii.force_media = 0; - lp->mii.full_duplex = 0; - lp->mii.dev = dev; - lp->mii.mdio_read = smc911x_phy_read; - lp->mii.mdio_write = smc911x_phy_write; - - /* - * Locate the phy, if any. - */ - smc911x_phy_detect(dev); - - /* Set default parameters */ - lp->msg_enable = NETIF_MSG_LINK; - lp->ctl_rfduplx = 1; - lp->ctl_rspeed = 100; - -#ifdef SMC_DYNAMIC_BUS_CONFIG - irq_flags = lp->cfg.irq_flags; -#else - irq_flags = IRQF_SHARED | SMC_IRQ_SENSE; -#endif - - /* Grab the IRQ */ - retval = request_irq(dev->irq, smc911x_interrupt, - irq_flags, dev->name, dev); - if (retval) - goto err_out; - -#ifdef SMC_USE_DMA - lp->rxdma = SMC_DMA_REQUEST(dev, smc911x_rx_dma_irq); - lp->txdma = SMC_DMA_REQUEST(dev, smc911x_tx_dma_irq); - lp->rxdma_active = 0; - lp->txdma_active = 0; - dev->dma = lp->rxdma; -#endif - - retval = register_netdev(dev); - if (retval == 0) { - /* now, print out the card info, in a short format.. */ - printk("%s: %s (rev %d) at %#lx IRQ %d", - dev->name, version_string, lp->revision, - dev->base_addr, dev->irq); - -#ifdef SMC_USE_DMA - if (lp->rxdma != -1) - printk(" RXDMA %d ", lp->rxdma); - - if (lp->txdma != -1) - printk("TXDMA %d", lp->txdma); -#endif - printk("\n"); - if (!is_valid_ether_addr(dev->dev_addr)) { - printk("%s: Invalid ethernet MAC address. Please " - "set using ifconfig\n", dev->name); - } else { - /* Print the Ethernet address */ - printk("%s: Ethernet addr: %pM\n", - dev->name, dev->dev_addr); - } - - if (lp->phy_type == 0) { - PRINTK("%s: No PHY found\n", dev->name); - } else if ((lp->phy_type & ~0xff) == LAN911X_INTERNAL_PHY_ID) { - PRINTK("%s: LAN911x Internal PHY\n", dev->name); - } else { - PRINTK("%s: External PHY 0x%08x\n", dev->name, lp->phy_type); - } - } - -err_out: -#ifdef SMC_USE_DMA - if (retval) { - if (lp->rxdma != -1) { - SMC_DMA_FREE(dev, lp->rxdma); - } - if (lp->txdma != -1) { - SMC_DMA_FREE(dev, lp->txdma); - } - } -#endif - return retval; -} - -/* - * smc911x_init(void) - * - * Output: - * 0 --> there is a device - * anything else, error - */ -static int __devinit smc911x_drv_probe(struct platform_device *pdev) -{ - struct net_device *ndev; - struct resource *res; - struct smc911x_local *lp; - unsigned int *addr; - int ret; - - DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto out; - } - - /* - * Request the regions. - */ - if (!request_mem_region(res->start, SMC911X_IO_EXTENT, CARDNAME)) { - ret = -EBUSY; - goto out; - } - - ndev = alloc_etherdev(sizeof(struct smc911x_local)); - if (!ndev) { - ret = -ENOMEM; - goto release_1; - } - SET_NETDEV_DEV(ndev, &pdev->dev); - - ndev->dma = (unsigned char)-1; - ndev->irq = platform_get_irq(pdev, 0); - lp = netdev_priv(ndev); - lp->netdev = ndev; -#ifdef SMC_DYNAMIC_BUS_CONFIG - { - struct smc911x_platdata *pd = pdev->dev.platform_data; - if (!pd) { - ret = -EINVAL; - goto release_both; - } - memcpy(&lp->cfg, pd, sizeof(lp->cfg)); - } -#endif - - addr = ioremap(res->start, SMC911X_IO_EXTENT); - if (!addr) { - ret = -ENOMEM; - goto release_both; - } - - platform_set_drvdata(pdev, ndev); - lp->base = addr; - ndev->base_addr = res->start; - ret = smc911x_probe(ndev); - if (ret != 0) { - platform_set_drvdata(pdev, NULL); - iounmap(addr); -release_both: - free_netdev(ndev); -release_1: - release_mem_region(res->start, SMC911X_IO_EXTENT); -out: - printk("%s: not found (%d).\n", CARDNAME, ret); - } -#ifdef SMC_USE_DMA - else { - lp->physaddr = res->start; - lp->dev = &pdev->dev; - } -#endif - - return ret; -} - -static int __devexit smc911x_drv_remove(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smc911x_local *lp = netdev_priv(ndev); - struct resource *res; - - DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); - platform_set_drvdata(pdev, NULL); - - unregister_netdev(ndev); - - free_irq(ndev->irq, ndev); - -#ifdef SMC_USE_DMA - { - if (lp->rxdma != -1) { - SMC_DMA_FREE(dev, lp->rxdma); - } - if (lp->txdma != -1) { - SMC_DMA_FREE(dev, lp->txdma); - } - } -#endif - iounmap(lp->base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, SMC911X_IO_EXTENT); - - free_netdev(ndev); - return 0; -} - -static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state) -{ - struct net_device *ndev = platform_get_drvdata(dev); - struct smc911x_local *lp = netdev_priv(ndev); - - DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); - if (ndev) { - if (netif_running(ndev)) { - netif_device_detach(ndev); - smc911x_shutdown(ndev); -#if POWER_DOWN - /* Set D2 - Energy detect only setting */ - SMC_SET_PMT_CTRL(lp, 2<<12); -#endif - } - } - return 0; -} - -static int smc911x_drv_resume(struct platform_device *dev) -{ - struct net_device *ndev = platform_get_drvdata(dev); - - DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__); - if (ndev) { - struct smc911x_local *lp = netdev_priv(ndev); - - if (netif_running(ndev)) { - smc911x_reset(ndev); - if (lp->phy_type != 0) - smc911x_phy_configure(&lp->phy_configure); - smc911x_enable(ndev); - netif_device_attach(ndev); - } - } - return 0; -} - -static struct platform_driver smc911x_driver = { - .probe = smc911x_drv_probe, - .remove = __devexit_p(smc911x_drv_remove), - .suspend = smc911x_drv_suspend, - .resume = smc911x_drv_resume, - .driver = { - .name = CARDNAME, - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(smc911x_driver); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.h b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.h deleted file mode 100644 index 3269292e..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc911x.h +++ /dev/null @@ -1,924 +0,0 @@ -/*------------------------------------------------------------------------ - . smc911x.h - macros for SMSC's LAN911{5,6,7,8} single-chip Ethernet device. - . - . Copyright (C) 2005 Sensoria Corp. - . Derived from the unified SMC91x driver by Nicolas Pitre - . - . This program is free software; you can redistribute it and/or modify - . it under the terms of the GNU General Public License as published by - . the Free Software Foundation; either version 2 of the License, or - . (at your option) any later version. - . - . This program is distributed in the hope that it will be useful, - . but WITHOUT ANY WARRANTY; without even the implied warranty of - . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - . GNU General Public License for more details. - . - . You should have received a copy of the GNU General Public License - . along with this program; if not, write to the Free Software - . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - . - . Information contained in this file was obtained from the LAN9118 - . manual from SMC. To get a copy, if you really want one, you can find - . information under www.smsc.com. - . - . Authors - . Dustin McIntire <dustin@sensoria.com> - . - ---------------------------------------------------------------------------*/ -#ifndef _SMC911X_H_ -#define _SMC911X_H_ - -#include <linux/smc911x.h> -/* - * Use the DMA feature on PXA chips - */ -#ifdef CONFIG_ARCH_PXA - #define SMC_USE_PXA_DMA 1 - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING -#elif defined(CONFIG_SH_MAGIC_PANEL_R2) - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW -#elif defined(CONFIG_ARCH_OMAP3) - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW - #define SMC_MEM_RESERVED 1 -#elif defined(CONFIG_ARCH_OMAP2) - #define SMC_USE_16BIT 0 - #define SMC_USE_32BIT 1 - #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW - #define SMC_MEM_RESERVED 1 -#else -/* - * Default configuration - */ - -#define SMC_DYNAMIC_BUS_CONFIG -#endif - -#ifdef SMC_USE_PXA_DMA -#define SMC_USE_DMA -#endif - -/* store this information for the driver.. */ -struct smc911x_local { - /* - * If I have to wait until the DMA is finished and ready to reload a - * packet, I will store the skbuff here. Then, the DMA will send it - * out and free it. - */ - struct sk_buff *pending_tx_skb; - - /* version/revision of the SMC911x chip */ - u16 version; - u16 revision; - - /* FIFO sizes */ - int tx_fifo_kb; - int tx_fifo_size; - int rx_fifo_size; - int afc_cfg; - - /* Contains the current active receive/phy mode */ - int ctl_rfduplx; - int ctl_rspeed; - - u32 msg_enable; - u32 phy_type; - struct mii_if_info mii; - - /* work queue */ - struct work_struct phy_configure; - - int tx_throttle; - spinlock_t lock; - - struct net_device *netdev; - -#ifdef SMC_USE_DMA - /* DMA needs the physical address of the chip */ - u_long physaddr; - int rxdma; - int txdma; - int rxdma_active; - int txdma_active; - struct sk_buff *current_rx_skb; - struct sk_buff *current_tx_skb; - struct device *dev; -#endif - void __iomem *base; -#ifdef SMC_DYNAMIC_BUS_CONFIG - struct smc911x_platdata cfg; -#endif -}; - -/* - * Define the bus width specific IO macros - */ - -#ifdef SMC_DYNAMIC_BUS_CONFIG -static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) - return readl(ioaddr); - - if (lp->cfg.flags & SMC911X_USE_16BIT) - return readw(ioaddr) | (readw(ioaddr + 2) << 16); - - BUG(); -} - -static inline void SMC_outl(unsigned int value, struct smc911x_local *lp, - int reg) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) { - writel(value, ioaddr); - return; - } - - if (lp->cfg.flags & SMC911X_USE_16BIT) { - writew(value & 0xffff, ioaddr); - writew(value >> 16, ioaddr + 2); - return; - } - - BUG(); -} - -static inline void SMC_insl(struct smc911x_local *lp, int reg, - void *addr, unsigned int count) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) { - readsl(ioaddr, addr, count); - return; - } - - if (lp->cfg.flags & SMC911X_USE_16BIT) { - readsw(ioaddr, addr, count * 2); - return; - } - - BUG(); -} - -static inline void SMC_outsl(struct smc911x_local *lp, int reg, - void *addr, unsigned int count) -{ - void __iomem *ioaddr = lp->base + reg; - - if (lp->cfg.flags & SMC911X_USE_32BIT) { - writesl(ioaddr, addr, count); - return; - } - - if (lp->cfg.flags & SMC911X_USE_16BIT) { - writesw(ioaddr, addr, count * 2); - return; - } - - BUG(); -} -#else -#if SMC_USE_16BIT -#define SMC_inl(lp, r) ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16)) -#define SMC_outl(v, lp, r) \ - do{ \ - writew(v & 0xFFFF, (lp)->base + (r)); \ - writew(v >> 16, (lp)->base + (r) + 2); \ - } while (0) -#define SMC_insl(lp, r, p, l) readsw((short*)((lp)->base + (r)), p, l*2) -#define SMC_outsl(lp, r, p, l) writesw((short*)((lp)->base + (r)), p, l*2) - -#elif SMC_USE_32BIT -#define SMC_inl(lp, r) readl((lp)->base + (r)) -#define SMC_outl(v, lp, r) writel(v, (lp)->base + (r)) -#define SMC_insl(lp, r, p, l) readsl((int*)((lp)->base + (r)), p, l) -#define SMC_outsl(lp, r, p, l) writesl((int*)((lp)->base + (r)), p, l) - -#endif /* SMC_USE_16BIT */ -#endif /* SMC_DYNAMIC_BUS_CONFIG */ - - -#ifdef SMC_USE_PXA_DMA - -#include <mach/dma.h> - -/* - * Define the request and free functions - * These are unfortunately architecture specific as no generic allocation - * mechanism exits - */ -#define SMC_DMA_REQUEST(dev, handler) \ - pxa_request_dma(dev->name, DMA_PRIO_LOW, handler, dev) - -#define SMC_DMA_FREE(dev, dma) \ - pxa_free_dma(dma) - -#define SMC_DMA_ACK_IRQ(dev, dma) \ -{ \ - if (DCSR(dma) & DCSR_BUSERR) { \ - printk("%s: DMA %d bus error!\n", dev->name, dma); \ - } \ - DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; \ -} - -/* - * Use a DMA for RX and TX packets. - */ -#include <linux/dma-mapping.h> - -static dma_addr_t rx_dmabuf, tx_dmabuf; -static int rx_dmalen, tx_dmalen; - -#ifdef SMC_insl -#undef SMC_insl -#define SMC_insl(lp, r, p, l) \ - smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l) - -static inline void -smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr, - int reg, int dma, u_char *buf, int len) -{ - /* 64 bit alignment is required for memory to memory DMA */ - if ((long)buf & 4) { - *((u32 *)buf) = SMC_inl(lp, reg); - buf += 4; - len--; - } - - len *= 4; - rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE); - rx_dmalen = len; - DCSR(dma) = DCSR_NODESC; - DTADR(dma) = rx_dmabuf; - DSADR(dma) = physaddr + reg; - DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | - DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen)); - DCSR(dma) = DCSR_NODESC | DCSR_RUN; -} -#endif - -#ifdef SMC_outsl -#undef SMC_outsl -#define SMC_outsl(lp, r, p, l) \ - smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l) - -static inline void -smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr, - int reg, int dma, u_char *buf, int len) -{ - /* 64 bit alignment is required for memory to memory DMA */ - if ((long)buf & 4) { - SMC_outl(*((u32 *)buf), lp, reg); - buf += 4; - len--; - } - - len *= 4; - tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE); - tx_dmalen = len; - DCSR(dma) = DCSR_NODESC; - DSADR(dma) = tx_dmabuf; - DTADR(dma) = physaddr + reg; - DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 | - DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen)); - DCSR(dma) = DCSR_NODESC | DCSR_RUN; -} -#endif -#endif /* SMC_USE_PXA_DMA */ - - -/* Chip Parameters and Register Definitions */ - -#define SMC911X_TX_FIFO_LOW_THRESHOLD (1536*2) - -#define SMC911X_IO_EXTENT 0x100 - -#define SMC911X_EEPROM_LEN 7 - -/* Below are the register offsets and bit definitions - * of the Lan911x memory space - */ -#define RX_DATA_FIFO (0x00) - -#define TX_DATA_FIFO (0x20) -#define TX_CMD_A_INT_ON_COMP_ (0x80000000) -#define TX_CMD_A_INT_BUF_END_ALGN_ (0x03000000) -#define TX_CMD_A_INT_4_BYTE_ALGN_ (0x00000000) -#define TX_CMD_A_INT_16_BYTE_ALGN_ (0x01000000) -#define TX_CMD_A_INT_32_BYTE_ALGN_ (0x02000000) -#define TX_CMD_A_INT_DATA_OFFSET_ (0x001F0000) -#define TX_CMD_A_INT_FIRST_SEG_ (0x00002000) -#define TX_CMD_A_INT_LAST_SEG_ (0x00001000) -#define TX_CMD_A_BUF_SIZE_ (0x000007FF) -#define TX_CMD_B_PKT_TAG_ (0xFFFF0000) -#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000) -#define TX_CMD_B_DISABLE_PADDING_ (0x00001000) -#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF) - -#define RX_STATUS_FIFO (0x40) -#define RX_STS_PKT_LEN_ (0x3FFF0000) -#define RX_STS_ES_ (0x00008000) -#define RX_STS_BCST_ (0x00002000) -#define RX_STS_LEN_ERR_ (0x00001000) -#define RX_STS_RUNT_ERR_ (0x00000800) -#define RX_STS_MCAST_ (0x00000400) -#define RX_STS_TOO_LONG_ (0x00000080) -#define RX_STS_COLL_ (0x00000040) -#define RX_STS_ETH_TYPE_ (0x00000020) -#define RX_STS_WDOG_TMT_ (0x00000010) -#define RX_STS_MII_ERR_ (0x00000008) -#define RX_STS_DRIBBLING_ (0x00000004) -#define RX_STS_CRC_ERR_ (0x00000002) -#define RX_STATUS_FIFO_PEEK (0x44) -#define TX_STATUS_FIFO (0x48) -#define TX_STS_TAG_ (0xFFFF0000) -#define TX_STS_ES_ (0x00008000) -#define TX_STS_LOC_ (0x00000800) -#define TX_STS_NO_CARR_ (0x00000400) -#define TX_STS_LATE_COLL_ (0x00000200) -#define TX_STS_MANY_COLL_ (0x00000100) -#define TX_STS_COLL_CNT_ (0x00000078) -#define TX_STS_MANY_DEFER_ (0x00000004) -#define TX_STS_UNDERRUN_ (0x00000002) -#define TX_STS_DEFERRED_ (0x00000001) -#define TX_STATUS_FIFO_PEEK (0x4C) -#define ID_REV (0x50) -#define ID_REV_CHIP_ID_ (0xFFFF0000) /* RO */ -#define ID_REV_REV_ID_ (0x0000FFFF) /* RO */ - -#define INT_CFG (0x54) -#define INT_CFG_INT_DEAS_ (0xFF000000) /* R/W */ -#define INT_CFG_INT_DEAS_CLR_ (0x00004000) -#define INT_CFG_INT_DEAS_STS_ (0x00002000) -#define INT_CFG_IRQ_INT_ (0x00001000) /* RO */ -#define INT_CFG_IRQ_EN_ (0x00000100) /* R/W */ -#define INT_CFG_IRQ_POL_ (0x00000010) /* R/W Not Affected by SW Reset */ -#define INT_CFG_IRQ_TYPE_ (0x00000001) /* R/W Not Affected by SW Reset */ - -#define INT_STS (0x58) -#define INT_STS_SW_INT_ (0x80000000) /* R/WC */ -#define INT_STS_TXSTOP_INT_ (0x02000000) /* R/WC */ -#define INT_STS_RXSTOP_INT_ (0x01000000) /* R/WC */ -#define INT_STS_RXDFH_INT_ (0x00800000) /* R/WC */ -#define INT_STS_RXDF_INT_ (0x00400000) /* R/WC */ -#define INT_STS_TX_IOC_ (0x00200000) /* R/WC */ -#define INT_STS_RXD_INT_ (0x00100000) /* R/WC */ -#define INT_STS_GPT_INT_ (0x00080000) /* R/WC */ -#define INT_STS_PHY_INT_ (0x00040000) /* RO */ -#define INT_STS_PME_INT_ (0x00020000) /* R/WC */ -#define INT_STS_TXSO_ (0x00010000) /* R/WC */ -#define INT_STS_RWT_ (0x00008000) /* R/WC */ -#define INT_STS_RXE_ (0x00004000) /* R/WC */ -#define INT_STS_TXE_ (0x00002000) /* R/WC */ -//#define INT_STS_ERX_ (0x00001000) /* R/WC */ -#define INT_STS_TDFU_ (0x00000800) /* R/WC */ -#define INT_STS_TDFO_ (0x00000400) /* R/WC */ -#define INT_STS_TDFA_ (0x00000200) /* R/WC */ -#define INT_STS_TSFF_ (0x00000100) /* R/WC */ -#define INT_STS_TSFL_ (0x00000080) /* R/WC */ -//#define INT_STS_RXDF_ (0x00000040) /* R/WC */ -#define INT_STS_RDFO_ (0x00000040) /* R/WC */ -#define INT_STS_RDFL_ (0x00000020) /* R/WC */ -#define INT_STS_RSFF_ (0x00000010) /* R/WC */ -#define INT_STS_RSFL_ (0x00000008) /* R/WC */ -#define INT_STS_GPIO2_INT_ (0x00000004) /* R/WC */ -#define INT_STS_GPIO1_INT_ (0x00000002) /* R/WC */ -#define INT_STS_GPIO0_INT_ (0x00000001) /* R/WC */ - -#define INT_EN (0x5C) -#define INT_EN_SW_INT_EN_ (0x80000000) /* R/W */ -#define INT_EN_TXSTOP_INT_EN_ (0x02000000) /* R/W */ -#define INT_EN_RXSTOP_INT_EN_ (0x01000000) /* R/W */ -#define INT_EN_RXDFH_INT_EN_ (0x00800000) /* R/W */ -//#define INT_EN_RXDF_INT_EN_ (0x00400000) /* R/W */ -#define INT_EN_TIOC_INT_EN_ (0x00200000) /* R/W */ -#define INT_EN_RXD_INT_EN_ (0x00100000) /* R/W */ -#define INT_EN_GPT_INT_EN_ (0x00080000) /* R/W */ -#define INT_EN_PHY_INT_EN_ (0x00040000) /* R/W */ -#define INT_EN_PME_INT_EN_ (0x00020000) /* R/W */ -#define INT_EN_TXSO_EN_ (0x00010000) /* R/W */ -#define INT_EN_RWT_EN_ (0x00008000) /* R/W */ -#define INT_EN_RXE_EN_ (0x00004000) /* R/W */ -#define INT_EN_TXE_EN_ (0x00002000) /* R/W */ -//#define INT_EN_ERX_EN_ (0x00001000) /* R/W */ -#define INT_EN_TDFU_EN_ (0x00000800) /* R/W */ -#define INT_EN_TDFO_EN_ (0x00000400) /* R/W */ -#define INT_EN_TDFA_EN_ (0x00000200) /* R/W */ -#define INT_EN_TSFF_EN_ (0x00000100) /* R/W */ -#define INT_EN_TSFL_EN_ (0x00000080) /* R/W */ -//#define INT_EN_RXDF_EN_ (0x00000040) /* R/W */ -#define INT_EN_RDFO_EN_ (0x00000040) /* R/W */ -#define INT_EN_RDFL_EN_ (0x00000020) /* R/W */ -#define INT_EN_RSFF_EN_ (0x00000010) /* R/W */ -#define INT_EN_RSFL_EN_ (0x00000008) /* R/W */ -#define INT_EN_GPIO2_INT_ (0x00000004) /* R/W */ -#define INT_EN_GPIO1_INT_ (0x00000002) /* R/W */ -#define INT_EN_GPIO0_INT_ (0x00000001) /* R/W */ - -#define BYTE_TEST (0x64) -#define FIFO_INT (0x68) -#define FIFO_INT_TX_AVAIL_LEVEL_ (0xFF000000) /* R/W */ -#define FIFO_INT_TX_STS_LEVEL_ (0x00FF0000) /* R/W */ -#define FIFO_INT_RX_AVAIL_LEVEL_ (0x0000FF00) /* R/W */ -#define FIFO_INT_RX_STS_LEVEL_ (0x000000FF) /* R/W */ - -#define RX_CFG (0x6C) -#define RX_CFG_RX_END_ALGN_ (0xC0000000) /* R/W */ -#define RX_CFG_RX_END_ALGN4_ (0x00000000) /* R/W */ -#define RX_CFG_RX_END_ALGN16_ (0x40000000) /* R/W */ -#define RX_CFG_RX_END_ALGN32_ (0x80000000) /* R/W */ -#define RX_CFG_RX_DMA_CNT_ (0x0FFF0000) /* R/W */ -#define RX_CFG_RX_DUMP_ (0x00008000) /* R/W */ -#define RX_CFG_RXDOFF_ (0x00001F00) /* R/W */ -//#define RX_CFG_RXBAD_ (0x00000001) /* R/W */ - -#define TX_CFG (0x70) -//#define TX_CFG_TX_DMA_LVL_ (0xE0000000) /* R/W */ -//#define TX_CFG_TX_DMA_CNT_ (0x0FFF0000) /* R/W Self Clearing */ -#define TX_CFG_TXS_DUMP_ (0x00008000) /* Self Clearing */ -#define TX_CFG_TXD_DUMP_ (0x00004000) /* Self Clearing */ -#define TX_CFG_TXSAO_ (0x00000004) /* R/W */ -#define TX_CFG_TX_ON_ (0x00000002) /* R/W */ -#define TX_CFG_STOP_TX_ (0x00000001) /* Self Clearing */ - -#define HW_CFG (0x74) -#define HW_CFG_TTM_ (0x00200000) /* R/W */ -#define HW_CFG_SF_ (0x00100000) /* R/W */ -#define HW_CFG_TX_FIF_SZ_ (0x000F0000) /* R/W */ -#define HW_CFG_TR_ (0x00003000) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_ (0x00000060) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_INT_PHY_ (0x00000000) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ (0x00000020) /* R/W */ -#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ (0x00000040) /* R/W */ -#define HW_CFG_SMI_SEL_ (0x00000010) /* R/W */ -#define HW_CFG_EXT_PHY_DET_ (0x00000008) /* RO */ -#define HW_CFG_EXT_PHY_EN_ (0x00000004) /* R/W */ -#define HW_CFG_32_16_BIT_MODE_ (0x00000004) /* RO */ -#define HW_CFG_SRST_TO_ (0x00000002) /* RO */ -#define HW_CFG_SRST_ (0x00000001) /* Self Clearing */ - -#define RX_DP_CTRL (0x78) -#define RX_DP_CTRL_RX_FFWD_ (0x80000000) /* R/W */ -#define RX_DP_CTRL_FFWD_BUSY_ (0x80000000) /* RO */ - -#define RX_FIFO_INF (0x7C) -#define RX_FIFO_INF_RXSUSED_ (0x00FF0000) /* RO */ -#define RX_FIFO_INF_RXDUSED_ (0x0000FFFF) /* RO */ - -#define TX_FIFO_INF (0x80) -#define TX_FIFO_INF_TSUSED_ (0x00FF0000) /* RO */ -#define TX_FIFO_INF_TDFREE_ (0x0000FFFF) /* RO */ - -#define PMT_CTRL (0x84) -#define PMT_CTRL_PM_MODE_ (0x00003000) /* Self Clearing */ -#define PMT_CTRL_PHY_RST_ (0x00000400) /* Self Clearing */ -#define PMT_CTRL_WOL_EN_ (0x00000200) /* R/W */ -#define PMT_CTRL_ED_EN_ (0x00000100) /* R/W */ -#define PMT_CTRL_PME_TYPE_ (0x00000040) /* R/W Not Affected by SW Reset */ -#define PMT_CTRL_WUPS_ (0x00000030) /* R/WC */ -#define PMT_CTRL_WUPS_NOWAKE_ (0x00000000) /* R/WC */ -#define PMT_CTRL_WUPS_ED_ (0x00000010) /* R/WC */ -#define PMT_CTRL_WUPS_WOL_ (0x00000020) /* R/WC */ -#define PMT_CTRL_WUPS_MULTI_ (0x00000030) /* R/WC */ -#define PMT_CTRL_PME_IND_ (0x00000008) /* R/W */ -#define PMT_CTRL_PME_POL_ (0x00000004) /* R/W */ -#define PMT_CTRL_PME_EN_ (0x00000002) /* R/W Not Affected by SW Reset */ -#define PMT_CTRL_READY_ (0x00000001) /* RO */ - -#define GPIO_CFG (0x88) -#define GPIO_CFG_LED3_EN_ (0x40000000) /* R/W */ -#define GPIO_CFG_LED2_EN_ (0x20000000) /* R/W */ -#define GPIO_CFG_LED1_EN_ (0x10000000) /* R/W */ -#define GPIO_CFG_GPIO2_INT_POL_ (0x04000000) /* R/W */ -#define GPIO_CFG_GPIO1_INT_POL_ (0x02000000) /* R/W */ -#define GPIO_CFG_GPIO0_INT_POL_ (0x01000000) /* R/W */ -#define GPIO_CFG_EEPR_EN_ (0x00700000) /* R/W */ -#define GPIO_CFG_GPIOBUF2_ (0x00040000) /* R/W */ -#define GPIO_CFG_GPIOBUF1_ (0x00020000) /* R/W */ -#define GPIO_CFG_GPIOBUF0_ (0x00010000) /* R/W */ -#define GPIO_CFG_GPIODIR2_ (0x00000400) /* R/W */ -#define GPIO_CFG_GPIODIR1_ (0x00000200) /* R/W */ -#define GPIO_CFG_GPIODIR0_ (0x00000100) /* R/W */ -#define GPIO_CFG_GPIOD4_ (0x00000010) /* R/W */ -#define GPIO_CFG_GPIOD3_ (0x00000008) /* R/W */ -#define GPIO_CFG_GPIOD2_ (0x00000004) /* R/W */ -#define GPIO_CFG_GPIOD1_ (0x00000002) /* R/W */ -#define GPIO_CFG_GPIOD0_ (0x00000001) /* R/W */ - -#define GPT_CFG (0x8C) -#define GPT_CFG_TIMER_EN_ (0x20000000) /* R/W */ -#define GPT_CFG_GPT_LOAD_ (0x0000FFFF) /* R/W */ - -#define GPT_CNT (0x90) -#define GPT_CNT_GPT_CNT_ (0x0000FFFF) /* RO */ - -#define ENDIAN (0x98) -#define FREE_RUN (0x9C) -#define RX_DROP (0xA0) -#define MAC_CSR_CMD (0xA4) -#define MAC_CSR_CMD_CSR_BUSY_ (0x80000000) /* Self Clearing */ -#define MAC_CSR_CMD_R_NOT_W_ (0x40000000) /* R/W */ -#define MAC_CSR_CMD_CSR_ADDR_ (0x000000FF) /* R/W */ - -#define MAC_CSR_DATA (0xA8) -#define AFC_CFG (0xAC) -#define AFC_CFG_AFC_HI_ (0x00FF0000) /* R/W */ -#define AFC_CFG_AFC_LO_ (0x0000FF00) /* R/W */ -#define AFC_CFG_BACK_DUR_ (0x000000F0) /* R/W */ -#define AFC_CFG_FCMULT_ (0x00000008) /* R/W */ -#define AFC_CFG_FCBRD_ (0x00000004) /* R/W */ -#define AFC_CFG_FCADD_ (0x00000002) /* R/W */ -#define AFC_CFG_FCANY_ (0x00000001) /* R/W */ - -#define E2P_CMD (0xB0) -#define E2P_CMD_EPC_BUSY_ (0x80000000) /* Self Clearing */ -#define E2P_CMD_EPC_CMD_ (0x70000000) /* R/W */ -#define E2P_CMD_EPC_CMD_READ_ (0x00000000) /* R/W */ -#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) /* R/W */ -#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) /* R/W */ -#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) /* R/W */ -#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) /* R/W */ -#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) /* R/W */ -#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) /* R/W */ -#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) /* R/W */ -#define E2P_CMD_EPC_TIMEOUT_ (0x00000200) /* RO */ -#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100) /* RO */ -#define E2P_CMD_EPC_ADDR_ (0x000000FF) /* R/W */ - -#define E2P_DATA (0xB4) -#define E2P_DATA_EEPROM_DATA_ (0x000000FF) /* R/W */ -/* end of LAN register offsets and bit definitions */ - -/* - **************************************************************************** - **************************************************************************** - * MAC Control and Status Register (Indirect Address) - * Offset (through the MAC_CSR CMD and DATA port) - **************************************************************************** - **************************************************************************** - * - */ -#define MAC_CR (0x01) /* R/W */ - -/* MAC_CR - MAC Control Register */ -#define MAC_CR_RXALL_ (0x80000000) -// TODO: delete this bit? It is not described in the data sheet. -#define MAC_CR_HBDIS_ (0x10000000) -#define MAC_CR_RCVOWN_ (0x00800000) -#define MAC_CR_LOOPBK_ (0x00200000) -#define MAC_CR_FDPX_ (0x00100000) -#define MAC_CR_MCPAS_ (0x00080000) -#define MAC_CR_PRMS_ (0x00040000) -#define MAC_CR_INVFILT_ (0x00020000) -#define MAC_CR_PASSBAD_ (0x00010000) -#define MAC_CR_HFILT_ (0x00008000) -#define MAC_CR_HPFILT_ (0x00002000) -#define MAC_CR_LCOLL_ (0x00001000) -#define MAC_CR_BCAST_ (0x00000800) -#define MAC_CR_DISRTY_ (0x00000400) -#define MAC_CR_PADSTR_ (0x00000100) -#define MAC_CR_BOLMT_MASK_ (0x000000C0) -#define MAC_CR_DFCHK_ (0x00000020) -#define MAC_CR_TXEN_ (0x00000008) -#define MAC_CR_RXEN_ (0x00000004) - -#define ADDRH (0x02) /* R/W mask 0x0000FFFFUL */ -#define ADDRL (0x03) /* R/W mask 0xFFFFFFFFUL */ -#define HASHH (0x04) /* R/W */ -#define HASHL (0x05) /* R/W */ - -#define MII_ACC (0x06) /* R/W */ -#define MII_ACC_PHY_ADDR_ (0x0000F800) -#define MII_ACC_MIIRINDA_ (0x000007C0) -#define MII_ACC_MII_WRITE_ (0x00000002) -#define MII_ACC_MII_BUSY_ (0x00000001) - -#define MII_DATA (0x07) /* R/W mask 0x0000FFFFUL */ - -#define FLOW (0x08) /* R/W */ -#define FLOW_FCPT_ (0xFFFF0000) -#define FLOW_FCPASS_ (0x00000004) -#define FLOW_FCEN_ (0x00000002) -#define FLOW_FCBSY_ (0x00000001) - -#define VLAN1 (0x09) /* R/W mask 0x0000FFFFUL */ -#define VLAN1_VTI1_ (0x0000ffff) - -#define VLAN2 (0x0A) /* R/W mask 0x0000FFFFUL */ -#define VLAN2_VTI2_ (0x0000ffff) - -#define WUFF (0x0B) /* WO */ - -#define WUCSR (0x0C) /* R/W */ -#define WUCSR_GUE_ (0x00000200) -#define WUCSR_WUFR_ (0x00000040) -#define WUCSR_MPR_ (0x00000020) -#define WUCSR_WAKE_EN_ (0x00000004) -#define WUCSR_MPEN_ (0x00000002) - -/* - **************************************************************************** - * Chip Specific MII Defines - **************************************************************************** - * - * Phy register offsets and bit definitions - * - */ - -#define PHY_MODE_CTRL_STS ((u32)17) /* Mode Control/Status Register */ -//#define MODE_CTRL_STS_FASTRIP_ ((u16)0x4000) -#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000) -//#define MODE_CTRL_STS_LOWSQEN_ ((u16)0x0800) -//#define MODE_CTRL_STS_MDPREBP_ ((u16)0x0400) -//#define MODE_CTRL_STS_FARLOOPBACK_ ((u16)0x0200) -//#define MODE_CTRL_STS_FASTEST_ ((u16)0x0100) -//#define MODE_CTRL_STS_REFCLKEN_ ((u16)0x0010) -//#define MODE_CTRL_STS_PHYADBP_ ((u16)0x0008) -//#define MODE_CTRL_STS_FORCE_G_LINK_ ((u16)0x0004) -#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002) - -#define PHY_INT_SRC ((u32)29) -#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080) -#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020) -#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010) -#define PHY_INT_SRC_ANEG_LP_ACK_ ((u16)0x0008) -#define PHY_INT_SRC_PAR_DET_FAULT_ ((u16)0x0004) -#define PHY_INT_SRC_ANEG_PGRX_ ((u16)0x0002) - -#define PHY_INT_MASK ((u32)30) -#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080) -#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020) -#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) -#define PHY_INT_MASK_ANEG_LP_ACK_ ((u16)0x0008) -#define PHY_INT_MASK_PAR_DET_FAULT_ ((u16)0x0004) -#define PHY_INT_MASK_ANEG_PGRX_ ((u16)0x0002) - -#define PHY_SPECIAL ((u32)31) -#define PHY_SPECIAL_ANEG_DONE_ ((u16)0x1000) -#define PHY_SPECIAL_RES_ ((u16)0x0040) -#define PHY_SPECIAL_RES_MASK_ ((u16)0x0FE1) -#define PHY_SPECIAL_SPD_ ((u16)0x001C) -#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004) -#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014) -#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008) -#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018) - -#define LAN911X_INTERNAL_PHY_ID (0x0007C000) - -/* Chip ID values */ -#define CHIP_9115 0x0115 -#define CHIP_9116 0x0116 -#define CHIP_9117 0x0117 -#define CHIP_9118 0x0118 -#define CHIP_9211 0x9211 -#define CHIP_9215 0x115A -#define CHIP_9217 0x117A -#define CHIP_9218 0x118A - -struct chip_id { - u16 id; - char *name; -}; - -static const struct chip_id chip_ids[] = { - { CHIP_9115, "LAN9115" }, - { CHIP_9116, "LAN9116" }, - { CHIP_9117, "LAN9117" }, - { CHIP_9118, "LAN9118" }, - { CHIP_9211, "LAN9211" }, - { CHIP_9215, "LAN9215" }, - { CHIP_9217, "LAN9217" }, - { CHIP_9218, "LAN9218" }, - { 0, NULL }, -}; - -#define IS_REV_A(x) ((x & 0xFFFF)==0) - -/* - * Macros to abstract register access according to the data bus - * capabilities. Please use those and not the in/out primitives. - */ -/* FIFO read/write macros */ -#define SMC_PUSH_DATA(lp, p, l) SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 ) -#define SMC_PULL_DATA(lp, p, l) SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 ) -#define SMC_SET_TX_FIFO(lp, x) SMC_outl( x, lp, TX_DATA_FIFO ) -#define SMC_GET_RX_FIFO(lp) SMC_inl( lp, RX_DATA_FIFO ) - - -/* I/O mapped register read/write macros */ -#define SMC_GET_TX_STS_FIFO(lp) SMC_inl( lp, TX_STATUS_FIFO ) -#define SMC_GET_RX_STS_FIFO(lp) SMC_inl( lp, RX_STATUS_FIFO ) -#define SMC_GET_RX_STS_FIFO_PEEK(lp) SMC_inl( lp, RX_STATUS_FIFO_PEEK ) -#define SMC_GET_PN(lp) (SMC_inl( lp, ID_REV ) >> 16) -#define SMC_GET_REV(lp) (SMC_inl( lp, ID_REV ) & 0xFFFF) -#define SMC_GET_IRQ_CFG(lp) SMC_inl( lp, INT_CFG ) -#define SMC_SET_IRQ_CFG(lp, x) SMC_outl( x, lp, INT_CFG ) -#define SMC_GET_INT(lp) SMC_inl( lp, INT_STS ) -#define SMC_ACK_INT(lp, x) SMC_outl( x, lp, INT_STS ) -#define SMC_GET_INT_EN(lp) SMC_inl( lp, INT_EN ) -#define SMC_SET_INT_EN(lp, x) SMC_outl( x, lp, INT_EN ) -#define SMC_GET_BYTE_TEST(lp) SMC_inl( lp, BYTE_TEST ) -#define SMC_SET_BYTE_TEST(lp, x) SMC_outl( x, lp, BYTE_TEST ) -#define SMC_GET_FIFO_INT(lp) SMC_inl( lp, FIFO_INT ) -#define SMC_SET_FIFO_INT(lp, x) SMC_outl( x, lp, FIFO_INT ) -#define SMC_SET_FIFO_TDA(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24); \ - SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 ); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_SET_FIFO_TSL(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16); \ - SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16)); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_SET_FIFO_RSA(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8); \ - SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8)); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_SET_FIFO_RSL(lp, x) \ - do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF; \ - SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF)); \ - local_irq_restore(__flags); \ - } while (0) -#define SMC_GET_RX_CFG(lp) SMC_inl( lp, RX_CFG ) -#define SMC_SET_RX_CFG(lp, x) SMC_outl( x, lp, RX_CFG ) -#define SMC_GET_TX_CFG(lp) SMC_inl( lp, TX_CFG ) -#define SMC_SET_TX_CFG(lp, x) SMC_outl( x, lp, TX_CFG ) -#define SMC_GET_HW_CFG(lp) SMC_inl( lp, HW_CFG ) -#define SMC_SET_HW_CFG(lp, x) SMC_outl( x, lp, HW_CFG ) -#define SMC_GET_RX_DP_CTRL(lp) SMC_inl( lp, RX_DP_CTRL ) -#define SMC_SET_RX_DP_CTRL(lp, x) SMC_outl( x, lp, RX_DP_CTRL ) -#define SMC_GET_PMT_CTRL(lp) SMC_inl( lp, PMT_CTRL ) -#define SMC_SET_PMT_CTRL(lp, x) SMC_outl( x, lp, PMT_CTRL ) -#define SMC_GET_GPIO_CFG(lp) SMC_inl( lp, GPIO_CFG ) -#define SMC_SET_GPIO_CFG(lp, x) SMC_outl( x, lp, GPIO_CFG ) -#define SMC_GET_RX_FIFO_INF(lp) SMC_inl( lp, RX_FIFO_INF ) -#define SMC_SET_RX_FIFO_INF(lp, x) SMC_outl( x, lp, RX_FIFO_INF ) -#define SMC_GET_TX_FIFO_INF(lp) SMC_inl( lp, TX_FIFO_INF ) -#define SMC_SET_TX_FIFO_INF(lp, x) SMC_outl( x, lp, TX_FIFO_INF ) -#define SMC_GET_GPT_CFG(lp) SMC_inl( lp, GPT_CFG ) -#define SMC_SET_GPT_CFG(lp, x) SMC_outl( x, lp, GPT_CFG ) -#define SMC_GET_RX_DROP(lp) SMC_inl( lp, RX_DROP ) -#define SMC_SET_RX_DROP(lp, x) SMC_outl( x, lp, RX_DROP ) -#define SMC_GET_MAC_CMD(lp) SMC_inl( lp, MAC_CSR_CMD ) -#define SMC_SET_MAC_CMD(lp, x) SMC_outl( x, lp, MAC_CSR_CMD ) -#define SMC_GET_MAC_DATA(lp) SMC_inl( lp, MAC_CSR_DATA ) -#define SMC_SET_MAC_DATA(lp, x) SMC_outl( x, lp, MAC_CSR_DATA ) -#define SMC_GET_AFC_CFG(lp) SMC_inl( lp, AFC_CFG ) -#define SMC_SET_AFC_CFG(lp, x) SMC_outl( x, lp, AFC_CFG ) -#define SMC_GET_E2P_CMD(lp) SMC_inl( lp, E2P_CMD ) -#define SMC_SET_E2P_CMD(lp, x) SMC_outl( x, lp, E2P_CMD ) -#define SMC_GET_E2P_DATA(lp) SMC_inl( lp, E2P_DATA ) -#define SMC_SET_E2P_DATA(lp, x) SMC_outl( x, lp, E2P_DATA ) - -/* MAC register read/write macros */ -#define SMC_GET_MAC_CSR(lp,a,v) \ - do { \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ | \ - MAC_CSR_CMD_R_NOT_W_ | (a) ); \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - v = SMC_GET_MAC_DATA((lp)); \ - } while (0) -#define SMC_SET_MAC_CSR(lp,a,v) \ - do { \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_DATA((lp), v); \ - SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) ); \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - } while (0) -#define SMC_GET_MAC_CR(lp, x) SMC_GET_MAC_CSR( (lp), MAC_CR, x ) -#define SMC_SET_MAC_CR(lp, x) SMC_SET_MAC_CSR( (lp), MAC_CR, x ) -#define SMC_GET_ADDRH(lp, x) SMC_GET_MAC_CSR( (lp), ADDRH, x ) -#define SMC_SET_ADDRH(lp, x) SMC_SET_MAC_CSR( (lp), ADDRH, x ) -#define SMC_GET_ADDRL(lp, x) SMC_GET_MAC_CSR( (lp), ADDRL, x ) -#define SMC_SET_ADDRL(lp, x) SMC_SET_MAC_CSR( (lp), ADDRL, x ) -#define SMC_GET_HASHH(lp, x) SMC_GET_MAC_CSR( (lp), HASHH, x ) -#define SMC_SET_HASHH(lp, x) SMC_SET_MAC_CSR( (lp), HASHH, x ) -#define SMC_GET_HASHL(lp, x) SMC_GET_MAC_CSR( (lp), HASHL, x ) -#define SMC_SET_HASHL(lp, x) SMC_SET_MAC_CSR( (lp), HASHL, x ) -#define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x ) -#define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x ) -#define SMC_GET_MII_DATA(lp, x) SMC_GET_MAC_CSR( (lp), MII_DATA, x ) -#define SMC_SET_MII_DATA(lp, x) SMC_SET_MAC_CSR( (lp), MII_DATA, x ) -#define SMC_GET_FLOW(lp, x) SMC_GET_MAC_CSR( (lp), FLOW, x ) -#define SMC_SET_FLOW(lp, x) SMC_SET_MAC_CSR( (lp), FLOW, x ) -#define SMC_GET_VLAN1(lp, x) SMC_GET_MAC_CSR( (lp), VLAN1, x ) -#define SMC_SET_VLAN1(lp, x) SMC_SET_MAC_CSR( (lp), VLAN1, x ) -#define SMC_GET_VLAN2(lp, x) SMC_GET_MAC_CSR( (lp), VLAN2, x ) -#define SMC_SET_VLAN2(lp, x) SMC_SET_MAC_CSR( (lp), VLAN2, x ) -#define SMC_SET_WUFF(lp, x) SMC_SET_MAC_CSR( (lp), WUFF, x ) -#define SMC_GET_WUCSR(lp, x) SMC_GET_MAC_CSR( (lp), WUCSR, x ) -#define SMC_SET_WUCSR(lp, x) SMC_SET_MAC_CSR( (lp), WUCSR, x ) - -/* PHY register read/write macros */ -#define SMC_GET_MII(lp,a,phy,v) \ - do { \ - u32 __v; \ - do { \ - SMC_GET_MII_ACC((lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \ - MII_ACC_MII_BUSY_); \ - do { \ - SMC_GET_MII_ACC( (lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_GET_MII_DATA((lp), v); \ - } while (0) -#define SMC_SET_MII(lp,a,phy,v) \ - do { \ - u32 __v; \ - do { \ - SMC_GET_MII_ACC((lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - SMC_SET_MII_DATA((lp), v); \ - SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \ - MII_ACC_MII_BUSY_ | \ - MII_ACC_MII_WRITE_ ); \ - do { \ - SMC_GET_MII_ACC((lp), __v); \ - } while ( __v & MII_ACC_MII_BUSY_ ); \ - } while (0) -#define SMC_GET_PHY_BMCR(lp,phy,x) SMC_GET_MII( (lp), MII_BMCR, phy, x ) -#define SMC_SET_PHY_BMCR(lp,phy,x) SMC_SET_MII( (lp), MII_BMCR, phy, x ) -#define SMC_GET_PHY_BMSR(lp,phy,x) SMC_GET_MII( (lp), MII_BMSR, phy, x ) -#define SMC_GET_PHY_ID1(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID1, phy, x ) -#define SMC_GET_PHY_ID2(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID2, phy, x ) -#define SMC_GET_PHY_MII_ADV(lp,phy,x) SMC_GET_MII( (lp), MII_ADVERTISE, phy, x ) -#define SMC_SET_PHY_MII_ADV(lp,phy,x) SMC_SET_MII( (lp), MII_ADVERTISE, phy, x ) -#define SMC_GET_PHY_MII_LPA(lp,phy,x) SMC_GET_MII( (lp), MII_LPA, phy, x ) -#define SMC_SET_PHY_MII_LPA(lp,phy,x) SMC_SET_MII( (lp), MII_LPA, phy, x ) -#define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x ) -#define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x ) -#define SMC_GET_PHY_INT_SRC(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_SRC, phy, x ) -#define SMC_SET_PHY_INT_SRC(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_SRC, phy, x ) -#define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x ) -#define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x ) -#define SMC_GET_PHY_SPECIAL(lp,phy,x) SMC_GET_MII( (lp), PHY_SPECIAL, phy, x ) - - - -/* Misc read/write macros */ - -#ifndef SMC_GET_MAC_ADDR -#define SMC_GET_MAC_ADDR(lp, addr) \ - do { \ - unsigned int __v; \ - \ - SMC_GET_MAC_CSR((lp), ADDRL, __v); \ - addr[0] = __v; addr[1] = __v >> 8; \ - addr[2] = __v >> 16; addr[3] = __v >> 24; \ - SMC_GET_MAC_CSR((lp), ADDRH, __v); \ - addr[4] = __v; addr[5] = __v >> 8; \ - } while (0) -#endif - -#define SMC_SET_MAC_ADDR(lp, addr) \ - do { \ - SMC_SET_MAC_CSR((lp), ADDRL, \ - addr[0] | \ - (addr[1] << 8) | \ - (addr[2] << 16) | \ - (addr[3] << 24)); \ - SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\ - } while (0) - - -#define SMC_WRITE_EEPROM_CMD(lp, cmd, addr) \ - do { \ - while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a ); \ - while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \ - } while (0) - -#endif /* _SMC911X_H_ */ diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.c deleted file mode 100644 index 50823da9..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.c +++ /dev/null @@ -1,1589 +0,0 @@ -/*------------------------------------------------------------------------ - . smc9194.c - . This is a driver for SMC's 9000 series of Ethernet cards. - . - . Copyright (C) 1996 by Erik Stahlman - . This software may be used and distributed according to the terms - . of the GNU General Public License, incorporated herein by reference. - . - . "Features" of the SMC chip: - . 4608 byte packet memory. ( for the 91C92. Others have more ) - . EEPROM for configuration - . AUI/TP selection ( mine has 10Base2/10BaseT select ) - . - . Arguments: - . io = for the base address - . irq = for the IRQ - . ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 ) - . - . author: - . Erik Stahlman ( erik@vt.edu ) - . contributors: - . Arnaldo Carvalho de Melo <acme@conectiva.com.br> - . - . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) - . - . Sources: - . o SMC databook - . o skeleton.c by Donald Becker ( becker@scyld.com ) - . o ( a LOT of advice from Becker as well ) - . - . History: - . 12/07/95 Erik Stahlman written, got receive/xmit handled - . 01/03/96 Erik Stahlman worked out some bugs, actually usable!!! :-) - . 01/06/96 Erik Stahlman cleaned up some, better testing, etc - . 01/29/96 Erik Stahlman fixed autoirq, added multicast - . 02/01/96 Erik Stahlman 1. disabled all interrupts in smc_reset - . 2. got rid of post-decrementing bug -- UGH. - . 02/13/96 Erik Stahlman Tried to fix autoirq failure. Added more - . descriptive error messages. - . 02/15/96 Erik Stahlman Fixed typo that caused detection failure - . 02/23/96 Erik Stahlman Modified it to fit into kernel tree - . Added support to change hardware address - . Cleared stats on opens - . 02/26/96 Erik Stahlman Trial support for Kernel 1.2.13 - . Kludge for automatic IRQ detection - . 03/04/96 Erik Stahlman Fixed kernel 1.3.70 + - . Fixed bug reported by Gardner Buchanan in - . smc_enable, with outw instead of outb - . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert - . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory - . allocation - . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet - . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" - . 11/08/01 Matt Domsch Use common crc32 function - ----------------------------------------------------------------------------*/ - -static const char version[] = - "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n"; - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/crc32.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/bitops.h> - -#include <asm/io.h> - -#include "smc9194.h" - -#define DRV_NAME "smc9194" - -/*------------------------------------------------------------------------ - . - . Configuration options, for the experienced user to change. - . - -------------------------------------------------------------------------*/ - -/* - . Do you want to use 32 bit xfers? This should work on all chips, as - . the chipset is designed to accommodate them. -*/ -#ifdef __sh__ -#undef USE_32_BIT -#else -#define USE_32_BIT 1 -#endif - -#if defined(__H8300H__) || defined(__H8300S__) -#define NO_AUTOPROBE -#undef insl -#undef outsl -#define insl(a,b,l) io_insl_noswap(a,b,l) -#define outsl(a,b,l) io_outsl_noswap(a,b,l) -#endif - -/* - .the SMC9194 can be at any of the following port addresses. To change, - .for a slightly different card, you can add it to the array. Keep in - .mind that the array must end in zero. -*/ - -struct devlist { - unsigned int port; - unsigned int irq; -}; - -#if defined(CONFIG_H8S_EDOSK2674) -static struct devlist smc_devlist[] __initdata = { - {.port = 0xf80000, .irq = 16}, - {.port = 0, .irq = 0 }, -}; -#else -static struct devlist smc_devlist[] __initdata = { - {.port = 0x200, .irq = 0}, - {.port = 0x220, .irq = 0}, - {.port = 0x240, .irq = 0}, - {.port = 0x260, .irq = 0}, - {.port = 0x280, .irq = 0}, - {.port = 0x2A0, .irq = 0}, - {.port = 0x2C0, .irq = 0}, - {.port = 0x2E0, .irq = 0}, - {.port = 0x300, .irq = 0}, - {.port = 0x320, .irq = 0}, - {.port = 0x340, .irq = 0}, - {.port = 0x360, .irq = 0}, - {.port = 0x380, .irq = 0}, - {.port = 0x3A0, .irq = 0}, - {.port = 0x3C0, .irq = 0}, - {.port = 0x3E0, .irq = 0}, - {.port = 0, .irq = 0}, -}; -#endif -/* - . Wait time for memory to be free. This probably shouldn't be - . tuned that much, as waiting for this means nothing else happens - . in the system -*/ -#define MEMORY_WAIT_TIME 16 - -/* - . DEBUGGING LEVELS - . - . 0 for normal operation - . 1 for slightly more details - . >2 for various levels of increasingly useless information - . 2 for interrupt tracking, status flags - . 3 for packet dumps, etc. -*/ -#define SMC_DEBUG 0 - -#if (SMC_DEBUG > 2 ) -#define PRINTK3(x) printk x -#else -#define PRINTK3(x) -#endif - -#if SMC_DEBUG > 1 -#define PRINTK2(x) printk x -#else -#define PRINTK2(x) -#endif - -#ifdef SMC_DEBUG -#define PRINTK(x) printk x -#else -#define PRINTK(x) -#endif - - -/*------------------------------------------------------------------------ - . - . The internal workings of the driver. If you are changing anything - . here with the SMC stuff, you should have the datasheet and known - . what you are doing. - . - -------------------------------------------------------------------------*/ -#define CARDNAME "SMC9194" - - -/* store this information for the driver.. */ -struct smc_local { - /* - If I have to wait until memory is available to send - a packet, I will store the skbuff here, until I get the - desired memory. Then, I'll send it out and free it. - */ - struct sk_buff * saved_skb; - - /* - . This keeps track of how many packets that I have - . sent out. When an TX_EMPTY interrupt comes, I know - . that all of these have been sent. - */ - int packets_waiting; -}; - - -/*----------------------------------------------------------------- - . - . The driver can be entered at any of the following entry points. - . - .------------------------------------------------------------------ */ - -/* - . This is called by register_netdev(). It is responsible for - . checking the portlist for the SMC9000 series chipset. If it finds - . one, then it will initialize the device, find the hardware information, - . and sets up the appropriate device parameters. - . NOTE: Interrupts are *OFF* when this procedure is called. - . - . NB:This shouldn't be static since it is referred to externally. -*/ -struct net_device *smc_init(int unit); - -/* - . The kernel calls this function when someone wants to use the device, - . typically 'ifconfig ethX up'. -*/ -static int smc_open(struct net_device *dev); - -/* - . Our watchdog timed out. Called by the networking layer -*/ -static void smc_timeout(struct net_device *dev); - -/* - . This is called by the kernel in response to 'ifconfig ethX down'. It - . is responsible for cleaning up everything that the open routine - . does, and maybe putting the card into a powerdown state. -*/ -static int smc_close(struct net_device *dev); - -/* - . Finally, a call to set promiscuous mode ( for TCPDUMP and related - . programs ) and multicast modes. -*/ -static void smc_set_multicast_list(struct net_device *dev); - - -/*--------------------------------------------------------------- - . - . Interrupt level calls.. - . - ----------------------------------------------------------------*/ - -/* - . Handles the actual interrupt -*/ -static irqreturn_t smc_interrupt(int irq, void *); -/* - . This is a separate procedure to handle the receipt of a packet, to - . leave the interrupt code looking slightly cleaner -*/ -static inline void smc_rcv( struct net_device *dev ); -/* - . This handles a TX interrupt, which is only called when an error - . relating to a packet is sent. -*/ -static inline void smc_tx( struct net_device * dev ); - -/* - ------------------------------------------------------------ - . - . Internal routines - . - ------------------------------------------------------------ -*/ - -/* - . Test if a given location contains a chip, trying to cause as - . little damage as possible if it's not a SMC chip. -*/ -static int smc_probe(struct net_device *dev, int ioaddr); - -/* - . A rather simple routine to print out a packet for debugging purposes. -*/ -#if SMC_DEBUG > 2 -static void print_packet( byte *, int ); -#endif - -#define tx_done(dev) 1 - -/* this is called to actually send the packet to the chip */ -static void smc_hardware_send_packet( struct net_device * dev ); - -/* Since I am not sure if I will have enough room in the chip's ram - . to store the packet, I call this routine, which either sends it - . now, or generates an interrupt when the card is ready for the - . packet */ -static netdev_tx_t smc_wait_to_send_packet( struct sk_buff * skb, - struct net_device *dev ); - -/* this does a soft reset on the device */ -static void smc_reset( int ioaddr ); - -/* Enable Interrupts, Receive, and Transmit */ -static void smc_enable( int ioaddr ); - -/* this puts the device in an inactive state */ -static void smc_shutdown( int ioaddr ); - -/* This routine will find the IRQ of the driver if one is not - . specified in the input to the device. */ -static int smc_findirq( int ioaddr ); - -/* - . Function: smc_reset( int ioaddr ) - . Purpose: - . This sets the SMC91xx chip to its normal state, hopefully from whatever - . mess that any other DOS driver has put it in. - . - . Maybe I should reset more registers to defaults in here? SOFTRESET should - . do that for me. - . - . Method: - . 1. send a SOFT RESET - . 2. wait for it to finish - . 3. enable autorelease mode - . 4. reset the memory management unit - . 5. clear all interrupts - . -*/ -static void smc_reset( int ioaddr ) -{ - /* This resets the registers mostly to defaults, but doesn't - affect EEPROM. That seems unnecessary */ - SMC_SELECT_BANK( 0 ); - outw( RCR_SOFTRESET, ioaddr + RCR ); - - /* this should pause enough for the chip to be happy */ - SMC_DELAY( ); - - /* Set the transmit and receive configuration registers to - default values */ - outw( RCR_CLEAR, ioaddr + RCR ); - outw( TCR_CLEAR, ioaddr + TCR ); - - /* set the control register to automatically - release successfully transmitted packets, to make the best - use out of our limited memory */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); - - /* Reset the MMU */ - SMC_SELECT_BANK( 2 ); - outw( MC_RESET, ioaddr + MMU_CMD ); - - /* Note: It doesn't seem that waiting for the MMU busy is needed here, - but this is a place where future chipsets _COULD_ break. Be wary - of issuing another MMU command right after this */ - - outb( 0, ioaddr + INT_MASK ); -} - -/* - . Function: smc_enable - . Purpose: let the chip talk to the outside work - . Method: - . 1. Enable the transmitter - . 2. Enable the receiver - . 3. Enable interrupts -*/ -static void smc_enable( int ioaddr ) -{ - SMC_SELECT_BANK( 0 ); - /* see the header file for options in TCR/RCR NORMAL*/ - outw( TCR_NORMAL, ioaddr + TCR ); - outw( RCR_NORMAL, ioaddr + RCR ); - - /* now, enable interrupts */ - SMC_SELECT_BANK( 2 ); - outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); -} - -/* - . Function: smc_shutdown - . Purpose: closes down the SMC91xxx chip. - . Method: - . 1. zero the interrupt mask - . 2. clear the enable receive flag - . 3. clear the enable xmit flags - . - . TODO: - . (1) maybe utilize power down mode. - . Why not yet? Because while the chip will go into power down mode, - . the manual says that it will wake up in response to any I/O requests - . in the register space. Empirical results do not show this working. -*/ -static void smc_shutdown( int ioaddr ) -{ - /* no more interrupts for me */ - SMC_SELECT_BANK( 2 ); - outb( 0, ioaddr + INT_MASK ); - - /* and tell the card to stay away from that nasty outside world */ - SMC_SELECT_BANK( 0 ); - outb( RCR_CLEAR, ioaddr + RCR ); - outb( TCR_CLEAR, ioaddr + TCR ); -#if 0 - /* finally, shut the chip down */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL ); -#endif -} - - -/* - . Function: smc_setmulticast( int ioaddr, struct net_device *dev ) - . Purpose: - . This sets the internal hardware table to filter out unwanted multicast - . packets before they take up memory. - . - . The SMC chip uses a hash table where the high 6 bits of the CRC of - . address are the offset into the table. If that bit is 1, then the - . multicast packet is accepted. Otherwise, it's dropped silently. - . - . To use the 6 bits as an offset into the table, the high 3 bits are the - . number of the 8 bit register, while the low 3 bits are the bit within - . that register. - . - . This routine is based very heavily on the one provided by Peter Cammaert. -*/ - - -static void smc_setmulticast(int ioaddr, struct net_device *dev) -{ - int i; - unsigned char multicast_table[ 8 ]; - struct netdev_hw_addr *ha; - /* table for flipping the order of 3 bits */ - unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; - - /* start with a table of all zeros: reject all */ - memset( multicast_table, 0, sizeof( multicast_table ) ); - - netdev_for_each_mc_addr(ha, dev) { - int position; - - /* only use the low order bits */ - position = ether_crc_le(6, ha->addr) & 0x3f; - - /* do some messy swapping to put the bit in the right spot */ - multicast_table[invert3[position&7]] |= - (1<<invert3[(position>>3)&7]); - - } - /* now, the table can be loaded into the chipset */ - SMC_SELECT_BANK( 3 ); - - for ( i = 0; i < 8 ; i++ ) { - outb( multicast_table[i], ioaddr + MULTICAST1 + i ); - } -} - -/* - . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) - . Purpose: - . Attempt to allocate memory for a packet, if chip-memory is not - . available, then tell the card to generate an interrupt when it - . is available. - . - . Algorithm: - . - . o if the saved_skb is not currently null, then drop this packet - . on the floor. This should never happen, because of TBUSY. - . o if the saved_skb is null, then replace it with the current packet, - . o See if I can sending it now. - . o (NO): Enable interrupts and let the interrupt handler deal with it. - . o (YES):Send it now. -*/ -static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - word length; - unsigned short numPages; - word time_out; - - netif_stop_queue(dev); - /* Well, I want to send the packet.. but I don't know - if I can send it right now... */ - - if ( lp->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - dev->stats.tx_aborted_errors++; - printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); - return NETDEV_TX_BUSY; - } - lp->saved_skb = skb; - - length = skb->len; - - if (length < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) { - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - length = ETH_ZLEN; - } - - /* - ** The MMU wants the number of pages to be the number of 256 bytes - ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) - ** - ** Pkt size for allocating is data length +6 (for additional status words, - ** length and ctl!) If odd size last byte is included in this header. - */ - numPages = ((length & 0xfffe) + 6) / 256; - - if (numPages > 7 ) { - printk(CARDNAME": Far too big packet error.\n"); - /* freeing the packet is a good thing here... but should - . any packets of this size get down here? */ - dev_kfree_skb (skb); - lp->saved_skb = NULL; - /* this IS an error, but, i don't want the skb saved */ - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - /* either way, a packet is waiting now */ - lp->packets_waiting++; - - /* now, try to allocate the memory */ - SMC_SELECT_BANK( 2 ); - outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); - /* - . Performance Hack - . - . wait a short amount of time.. if I can send a packet now, I send - . it now. Otherwise, I enable an interrupt and wait for one to be - . available. - . - . I could have handled this a slightly different way, by checking to - . see if any memory was available in the FREE MEMORY register. However, - . either way, I need to generate an allocation, and the allocation works - . no matter what, so I saw no point in checking free memory. - */ - time_out = MEMORY_WAIT_TIME; - do { - word status; - - status = inb( ioaddr + INTERRUPT ); - if ( status & IM_ALLOC_INT ) { - /* acknowledge the interrupt */ - outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); - break; - } - } while ( -- time_out ); - - if ( !time_out ) { - /* oh well, wait until the chip finds memory later */ - SMC_ENABLE_INT( IM_ALLOC_INT ); - PRINTK2((CARDNAME": memory allocation deferred.\n")); - /* it's deferred, but I'll handle it later */ - return NETDEV_TX_OK; - } - /* or YES! I can send the packet now.. */ - smc_hardware_send_packet(dev); - netif_wake_queue(dev); - return NETDEV_TX_OK; -} - -/* - . Function: smc_hardware_send_packet(struct net_device * ) - . Purpose: - . This sends the actual packet to the SMC9xxx chip. - . - . Algorithm: - . First, see if a saved_skb is available. - . ( this should NOT be called if there is no 'saved_skb' - . Now, find the packet number that the chip allocated - . Point the data pointers at it in memory - . Set the length word in the chip's memory - . Dump the packet to chip memory - . Check if a last byte is needed ( odd length packet ) - . if so, set the control flag right - . Tell the card to send it - . Enable the transmit interrupt, so I know if it failed - . Free the kernel data if I actually sent it. -*/ -static void smc_hardware_send_packet( struct net_device * dev ) -{ - struct smc_local *lp = netdev_priv(dev); - byte packet_no; - struct sk_buff * skb = lp->saved_skb; - word length; - unsigned int ioaddr; - byte * buf; - - ioaddr = dev->base_addr; - - if ( !skb ) { - PRINTK((CARDNAME": In XMIT with no packet to send\n")); - return; - } - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buf = skb->data; - - /* If I get here, I _know_ there is a packet slot waiting for me */ - packet_no = inb( ioaddr + PNR_ARR + 1 ); - if ( packet_no & 0x80 ) { - /* or isn't there? BAD CHIP! */ - printk(KERN_DEBUG CARDNAME": Memory allocation failed.\n"); - dev_kfree_skb_any(skb); - lp->saved_skb = NULL; - netif_wake_queue(dev); - return; - } - - /* we have a packet address, so tell the card to use it */ - outb( packet_no, ioaddr + PNR_ARR ); - - /* point to the beginning of the packet */ - outw( PTR_AUTOINC , ioaddr + POINTER ); - - PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length )); -#if SMC_DEBUG > 2 - print_packet( buf, length ); -#endif - - /* send the packet length ( +6 for status, length and ctl byte ) - and the status word ( set to zeros ) */ -#ifdef USE_32_BIT - outl( (length +6 ) << 16 , ioaddr + DATA_1 ); -#else - outw( 0, ioaddr + DATA_1 ); - /* send the packet length ( +6 for status words, length, and ctl*/ - outb( (length+6) & 0xFF,ioaddr + DATA_1 ); - outb( (length+6) >> 8 , ioaddr + DATA_1 ); -#endif - - /* send the actual data - . I _think_ it's faster to send the longs first, and then - . mop up by sending the last word. It depends heavily - . on alignment, at least on the 486. Maybe it would be - . a good idea to check which is optimal? But that could take - . almost as much time as is saved? - */ -#ifdef USE_32_BIT - if ( length & 0x2 ) { - outsl(ioaddr + DATA_1, buf, length >> 2 ); -#if !defined(__H8300H__) && !defined(__H8300S__) - outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); -#else - ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); -#endif - } - else - outsl(ioaddr + DATA_1, buf, length >> 2 ); -#else - outsw(ioaddr + DATA_1 , buf, (length ) >> 1); -#endif - /* Send the last byte, if there is one. */ - - if ( (length & 1) == 0 ) { - outw( 0, ioaddr + DATA_1 ); - } else { - outb( buf[length -1 ], ioaddr + DATA_1 ); - outb( 0x20, ioaddr + DATA_1); - } - - /* enable the interrupts */ - SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); - - /* and let the chipset deal with it */ - outw( MC_ENQUEUE , ioaddr + MMU_CMD ); - - PRINTK2((CARDNAME": Sent packet of length %d\n", length)); - - lp->saved_skb = NULL; - dev_kfree_skb_any (skb); - - dev->trans_start = jiffies; - - /* we can send another packet */ - netif_wake_queue(dev); -} - -/*------------------------------------------------------------------------- - | - | smc_init(int unit) - | Input parameters: - | dev->base_addr == 0, try to find all possible locations - | dev->base_addr == 1, return failure code - | dev->base_addr == 2, always allocate space, and return success - | dev->base_addr == <anything else> this is the address to check - | - | Output: - | pointer to net_device or ERR_PTR(error) - | - --------------------------------------------------------------------------- -*/ -static int io; -static int irq; -static int ifport; - -struct net_device * __init smc_init(int unit) -{ - struct net_device *dev = alloc_etherdev(sizeof(struct smc_local)); - struct devlist *smcdev = smc_devlist; - int err = 0; - - if (!dev) - return ERR_PTR(-ENODEV); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - io = dev->base_addr; - irq = dev->irq; - } - - if (io > 0x1ff) { /* Check a single specified location. */ - err = smc_probe(dev, io); - } else if (io != 0) { /* Don't probe at all. */ - err = -ENXIO; - } else { - for (;smcdev->port; smcdev++) { - if (smc_probe(dev, smcdev->port) == 0) - break; - } - if (!smcdev->port) - err = -ENODEV; - } - if (err) - goto out; - err = register_netdev(dev); - if (err) - goto out1; - return dev; -out1: - free_irq(dev->irq, dev); - release_region(dev->base_addr, SMC_IO_EXTENT); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -/*---------------------------------------------------------------------- - . smc_findirq - . - . This routine has a simple purpose -- make the SMC chip generate an - . interrupt, so an auto-detect routine can detect it, and find the IRQ, - ------------------------------------------------------------------------ -*/ -static int __init smc_findirq(int ioaddr) -{ -#ifndef NO_AUTOPROBE - int timeout = 20; - unsigned long cookie; - - - cookie = probe_irq_on(); - - /* - * What I try to do here is trigger an ALLOC_INT. This is done - * by allocating a small chunk of memory, which will give an interrupt - * when done. - */ - - - SMC_SELECT_BANK(2); - /* enable ALLOCation interrupts ONLY */ - outb( IM_ALLOC_INT, ioaddr + INT_MASK ); - - /* - . Allocate 512 bytes of memory. Note that the chip was just - . reset so all the memory is available - */ - outw( MC_ALLOC | 1, ioaddr + MMU_CMD ); - - /* - . Wait until positive that the interrupt has been generated - */ - while ( timeout ) { - byte int_status; - - int_status = inb( ioaddr + INTERRUPT ); - - if ( int_status & IM_ALLOC_INT ) - break; /* got the interrupt */ - timeout--; - } - /* there is really nothing that I can do here if timeout fails, - as probe_irq_off will return a 0 anyway, which is what I - want in this case. Plus, the clean up is needed in both - cases. */ - - /* DELAY HERE! - On a fast machine, the status might change before the interrupt - is given to the processor. This means that the interrupt was - never detected, and probe_irq_off fails to report anything. - This should fix probe_irq_* problems. - */ - SMC_DELAY(); - SMC_DELAY(); - - /* and disable all interrupts again */ - outb( 0, ioaddr + INT_MASK ); - - /* and return what I found */ - return probe_irq_off(cookie); -#else /* NO_AUTOPROBE */ - struct devlist *smcdev; - for (smcdev = smc_devlist; smcdev->port; smcdev++) { - if (smcdev->port == ioaddr) - return smcdev->irq; - } - return 0; -#endif -} - -static const struct net_device_ops smc_netdev_ops = { - .ndo_open = smc_open, - .ndo_stop = smc_close, - .ndo_start_xmit = smc_wait_to_send_packet, - .ndo_tx_timeout = smc_timeout, - .ndo_set_rx_mode = smc_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/*---------------------------------------------------------------------- - . Function: smc_probe( int ioaddr ) - . - . Purpose: - . Tests to see if a given ioaddr points to an SMC9xxx chip. - . Returns a 0 on success - . - . Algorithm: - . (1) see if the high byte of BANK_SELECT is 0x33 - . (2) compare the ioaddr with the base register's address - . (3) see if I recognize the chip ID in the appropriate register - . - .--------------------------------------------------------------------- - */ - -/*--------------------------------------------------------------- - . Here I do typical initialization tasks. - . - . o Initialize the structure if needed - . o print out my vanity message if not done so already - . o print out what type of hardware is detected - . o print out the ethernet address - . o find the IRQ - . o set up my private data - . o configure the dev structure with my subroutines - . o actually GRAB the irq. - . o GRAB the region - .----------------------------------------------------------------- -*/ -static int __init smc_probe(struct net_device *dev, int ioaddr) -{ - int i, memory, retval; - static unsigned version_printed; - unsigned int bank; - - const char *version_string; - const char *if_string; - - /* registers */ - word revision_register; - word base_address_register; - word configuration_register; - word memory_info_register; - word memory_cfg_register; - - /* Grab the region so that no one else tries to probe our ioports. */ - if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) - return -EBUSY; - - dev->irq = irq; - dev->if_port = ifport; - - /* First, see if the high byte is 0x33 */ - bank = inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00) != 0x3300 ) { - retval = -ENODEV; - goto err_out; - } - /* The above MIGHT indicate a device, but I need to write to further - test this. */ - outw( 0x0, ioaddr + BANK_SELECT ); - bank = inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00 ) != 0x3300 ) { - retval = -ENODEV; - goto err_out; - } -#if !defined(CONFIG_H8S_EDOSK2674) - /* well, we've already written once, so hopefully another time won't - hurt. This time, I need to switch the bank register to bank 1, - so I can access the base address register */ - SMC_SELECT_BANK(1); - base_address_register = inw( ioaddr + BASE ); - if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { - printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). " - "Probably not a SMC chip\n", - ioaddr, base_address_register >> 3 & 0x3E0 ); - /* well, the base address register didn't match. Must not have - been a SMC chip after all. */ - retval = -ENODEV; - goto err_out; - } -#else - (void)base_address_register; /* Warning suppression */ -#endif - - - /* check if the revision register is something that I recognize. - These might need to be added to later, as future revisions - could be added. */ - SMC_SELECT_BANK(3); - revision_register = inw( ioaddr + REVISION ); - if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { - /* I don't recognize this chip, so... */ - printk(CARDNAME ": IO %x: Unrecognized revision register:" - " %x, Contact author.\n", ioaddr, revision_register); - - retval = -ENODEV; - goto err_out; - } - - /* at this point I'll assume that the chip is an SMC9xxx. - It might be prudent to check a listing of MAC addresses - against the hardware address, or do some other tests. */ - - if (version_printed++ == 0) - printk("%s", version); - - /* fill in some of the fields */ - dev->base_addr = ioaddr; - - /* - . Get the MAC address ( bank 1, regs 4 - 9 ) - */ - SMC_SELECT_BANK( 1 ); - for ( i = 0; i < 6; i += 2 ) { - word address; - - address = inw( ioaddr + ADDR0 + i ); - dev->dev_addr[ i + 1] = address >> 8; - dev->dev_addr[ i ] = address & 0xFF; - } - - /* get the memory information */ - - SMC_SELECT_BANK( 0 ); - memory_info_register = inw( ioaddr + MIR ); - memory_cfg_register = inw( ioaddr + MCR ); - memory = ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ - memory *= 256 * ( memory_info_register & 0xFF ); - - /* - Now, I want to find out more about the chip. This is sort of - redundant, but it's cleaner to have it in both, rather than having - one VERY long probe procedure. - */ - SMC_SELECT_BANK(3); - revision_register = inw( ioaddr + REVISION ); - version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; - if ( !version_string ) { - /* I shouldn't get here because this call was done before.... */ - retval = -ENODEV; - goto err_out; - } - - /* is it using AUI or 10BaseT ? */ - if ( dev->if_port == 0 ) { - SMC_SELECT_BANK(1); - configuration_register = inw( ioaddr + CONFIG ); - if ( configuration_register & CFG_AUI_SELECT ) - dev->if_port = 2; - else - dev->if_port = 1; - } - if_string = interfaces[ dev->if_port - 1 ]; - - /* now, reset the chip, and put it into a known state */ - smc_reset( ioaddr ); - - /* - . If dev->irq is 0, then the device has to be banged on to see - . what the IRQ is. - . - . This banging doesn't always detect the IRQ, for unknown reasons. - . a workaround is to reset the chip and try again. - . - . Interestingly, the DOS packet driver *SETS* the IRQ on the card to - . be what is requested on the command line. I don't do that, mostly - . because the card that I have uses a non-standard method of accessing - . the IRQs, and because this _should_ work in most configurations. - . - . Specifying an IRQ is done with the assumption that the user knows - . what (s)he is doing. No checking is done!!!! - . - */ - if ( dev->irq < 2 ) { - int trials; - - trials = 3; - while ( trials-- ) { - dev->irq = smc_findirq( ioaddr ); - if ( dev->irq ) - break; - /* kick the card and try again */ - smc_reset( ioaddr ); - } - } - if (dev->irq == 0 ) { - printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n"); - retval = -ENODEV; - goto err_out; - } - - /* now, print out the card info, in a short format.. */ - - printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, - version_string, revision_register & 0xF, ioaddr, dev->irq, - if_string, memory ); - /* - . Print the Ethernet address - */ - printk("ADDR: %pM\n", dev->dev_addr); - - /* Grab the IRQ */ - retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev); - if (retval) { - printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME, - dev->irq, retval); - goto err_out; - } - - dev->netdev_ops = &smc_netdev_ops; - dev->watchdog_timeo = HZ/20; - - return 0; - -err_out: - release_region(ioaddr, SMC_IO_EXTENT); - return retval; -} - -#if SMC_DEBUG > 2 -static void print_packet( byte * buf, int length ) -{ -#if 0 - int i; - int remainder; - int lines; - - printk("Packet of length %d\n", length); - lines = length / 16; - remainder = length % 16; - - for ( i = 0; i < lines ; i ++ ) { - int cur; - - for ( cur = 0; cur < 8; cur ++ ) { - byte a, b; - - a = *(buf ++ ); - b = *(buf ++ ); - printk("%02x%02x ", a, b ); - } - printk("\n"); - } - for ( i = 0; i < remainder/2 ; i++ ) { - byte a, b; - - a = *(buf ++ ); - b = *(buf ++ ); - printk("%02x%02x ", a, b ); - } - printk("\n"); -#endif -} -#endif - - -/* - * Open and Initialize the board - * - * Set up everything, reset the card, etc .. - * - */ -static int smc_open(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - - int i; /* used to set hw ethernet address */ - - /* clear out all the junk that was put here before... */ - memset(netdev_priv(dev), 0, sizeof(struct smc_local)); - - /* reset the hardware */ - - smc_reset( ioaddr ); - smc_enable( ioaddr ); - - /* Select which interface to use */ - - SMC_SELECT_BANK( 1 ); - if ( dev->if_port == 1 ) { - outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - else if ( dev->if_port == 2 ) { - outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - - /* - According to Becker, I have to set the hardware address - at this point, because the (l)user can set it with an - ioctl. Easily done... - */ - SMC_SELECT_BANK( 1 ); - for ( i = 0; i < 6; i += 2 ) { - word address; - - address = dev->dev_addr[ i + 1 ] << 8 ; - address |= dev->dev_addr[ i ]; - outw( address, ioaddr + ADDR0 + i ); - } - - netif_start_queue(dev); - return 0; -} - -/*-------------------------------------------------------- - . Called by the kernel to send a packet out into the void - . of the net. This routine is largely based on - . skeleton.c, from Becker. - .-------------------------------------------------------- -*/ - -static void smc_timeout(struct net_device *dev) -{ - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n", - tx_done(dev) ? "IRQ conflict" : - "network cable problem"); - /* "kick" the adaptor */ - smc_reset( dev->base_addr ); - smc_enable( dev->base_addr ); - dev->trans_start = jiffies; /* prevent tx timeout */ - /* clear anything saved */ - ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL; - netif_wake_queue(dev); -} - -/*------------------------------------------------------------- - . - . smc_rcv - receive a packet from the card - . - . There is ( at least ) a packet waiting to be read from - . chip-memory. - . - . o Read the status - . o If an error, record it - . o otherwise, read in the packet - -------------------------------------------------------------- -*/ -static void smc_rcv(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - int packet_number; - word status; - word packet_length; - - /* assume bank 2 */ - - packet_number = inw( ioaddr + FIFO_PORTS ); - - if ( packet_number & FP_RXEMPTY ) { - /* we got called , but nothing was on the FIFO */ - PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n")); - /* don't need to restore anything */ - return; - } - - /* start reading from the start of the packet */ - outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); - - /* First two words are status and packet_length */ - status = inw( ioaddr + DATA_1 ); - packet_length = inw( ioaddr + DATA_1 ); - - packet_length &= 0x07ff; /* mask off top bits */ - - PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length )); - /* - . the packet length contains 3 extra words : - . status, length, and an extra word with an odd byte . - */ - packet_length -= 6; - - if ( !(status & RS_ERRORS ) ){ - /* do stuff to make a new packet */ - struct sk_buff * skb; - byte * data; - - /* read one extra byte */ - if ( status & RS_ODDFRAME ) - packet_length++; - - /* set multicast stats */ - if ( status & RS_MULTICAST ) - dev->stats.multicast++; - - skb = netdev_alloc_skb(dev, packet_length + 5); - - if ( skb == NULL ) { - printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); - dev->stats.rx_dropped++; - goto done; - } - - /* - ! This should work without alignment, but it could be - ! in the worse case - */ - - skb_reserve( skb, 2 ); /* 16 bit alignment */ - - data = skb_put( skb, packet_length); - -#ifdef USE_32_BIT - /* QUESTION: Like in the TX routine, do I want - to send the DWORDs or the bytes first, or some - mixture. A mixture might improve already slow PIO - performance */ - PRINTK3((" Reading %d dwords (and %d bytes)\n", - packet_length >> 2, packet_length & 3 )); - insl(ioaddr + DATA_1 , data, packet_length >> 2 ); - /* read the left over bytes */ - insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC), - packet_length & 0x3 ); -#else - PRINTK3((" Reading %d words and %d byte(s)\n", - (packet_length >> 1 ), packet_length & 1 )); - insw(ioaddr + DATA_1 , data, packet_length >> 1); - if ( packet_length & 1 ) { - data += packet_length & ~1; - *(data++) = inb( ioaddr + DATA_1 ); - } -#endif -#if SMC_DEBUG > 2 - print_packet( data, packet_length ); -#endif - - skb->protocol = eth_type_trans(skb, dev ); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += packet_length; - } else { - /* error ... */ - dev->stats.rx_errors++; - - if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++; - if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) - dev->stats.rx_length_errors++; - if ( status & RS_BADCRC) dev->stats.rx_crc_errors++; - } - -done: - /* error or good, tell the card to get rid of this packet */ - outw( MC_RELEASE, ioaddr + MMU_CMD ); -} - - -/************************************************************************* - . smc_tx - . - . Purpose: Handle a transmit error message. This will only be called - . when an error, because of the AUTO_RELEASE mode. - . - . Algorithm: - . Save pointer and packet no - . Get the packet no from the top of the queue - . check if it's valid ( if not, is this an error??? ) - . read the status word - . record the error - . ( resend? Not really, since we don't want old packets around ) - . Restore saved values - ************************************************************************/ -static void smc_tx( struct net_device * dev ) -{ - int ioaddr = dev->base_addr; - struct smc_local *lp = netdev_priv(dev); - byte saved_packet; - byte packet_no; - word tx_status; - - - /* assume bank 2 */ - - saved_packet = inb( ioaddr + PNR_ARR ); - packet_no = inw( ioaddr + FIFO_PORTS ); - packet_no &= 0x7F; - - /* select this as the packet to read from */ - outb( packet_no, ioaddr + PNR_ARR ); - - /* read the first word from this packet */ - outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER ); - - tx_status = inw( ioaddr + DATA_1 ); - PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status)); - - dev->stats.tx_errors++; - if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++; - if ( tx_status & TS_LATCOL ) { - printk(KERN_DEBUG CARDNAME - ": Late collision occurred on last xmit.\n"); - dev->stats.tx_window_errors++; - } -#if 0 - if ( tx_status & TS_16COL ) { ... } -#endif - - if ( tx_status & TS_SUCCESS ) { - printk(CARDNAME": Successful packet caused interrupt\n"); - } - /* re-enable transmit */ - SMC_SELECT_BANK( 0 ); - outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR ); - - /* kill the packet */ - SMC_SELECT_BANK( 2 ); - outw( MC_FREEPKT, ioaddr + MMU_CMD ); - - /* one less packet waiting for me */ - lp->packets_waiting--; - - outb( saved_packet, ioaddr + PNR_ARR ); -} - -/*-------------------------------------------------------------------- - . - . This is the main routine of the driver, to handle the device when - . it needs some attention. - . - . So: - . first, save state of the chipset - . branch off into routines to handle each case, and acknowledge - . each to the interrupt register - . and finally restore state. - . - ---------------------------------------------------------------------*/ - -static irqreturn_t smc_interrupt(int irq, void * dev_id) -{ - struct net_device *dev = dev_id; - int ioaddr = dev->base_addr; - struct smc_local *lp = netdev_priv(dev); - - byte status; - word card_stats; - byte mask; - int timeout; - /* state registers */ - word saved_bank; - word saved_pointer; - int handled = 0; - - - PRINTK3((CARDNAME": SMC interrupt started\n")); - - saved_bank = inw( ioaddr + BANK_SELECT ); - - SMC_SELECT_BANK(2); - saved_pointer = inw( ioaddr + POINTER ); - - mask = inb( ioaddr + INT_MASK ); - /* clear all interrupts */ - outb( 0, ioaddr + INT_MASK ); - - - /* set a timeout value, so I don't stay here forever */ - timeout = 4; - - PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask)); - do { - /* read the status flag, and mask it */ - status = inb( ioaddr + INTERRUPT ) & mask; - if (!status ) - break; - - handled = 1; - - PRINTK3((KERN_WARNING CARDNAME - ": Handling interrupt status %x\n", status)); - - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - PRINTK2((KERN_WARNING CARDNAME - ": Receive Interrupt\n")); - smc_rcv(dev); - } else if (status & IM_TX_INT ) { - PRINTK2((KERN_WARNING CARDNAME - ": TX ERROR handled\n")); - smc_tx(dev); - outb(IM_TX_INT, ioaddr + INTERRUPT ); - } else if (status & IM_TX_EMPTY_INT ) { - /* update stats */ - SMC_SELECT_BANK( 0 ); - card_stats = inw( ioaddr + COUNTER ); - /* single collisions */ - dev->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - /* multiple collisions */ - dev->stats.collisions += card_stats & 0xF; - - /* these are for when linux supports these statistics */ - - SMC_SELECT_BANK( 2 ); - PRINTK2((KERN_WARNING CARDNAME - ": TX_BUFFER_EMPTY handled\n")); - outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); - mask &= ~IM_TX_EMPTY_INT; - dev->stats.tx_packets += lp->packets_waiting; - lp->packets_waiting = 0; - - } else if (status & IM_ALLOC_INT ) { - PRINTK2((KERN_DEBUG CARDNAME - ": Allocation interrupt\n")); - /* clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - - smc_hardware_send_packet( dev ); - - /* enable xmit interrupts based on this */ - mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - - PRINTK2((CARDNAME": Handoff done successfully.\n")); - } else if (status & IM_RX_OVRN_INT ) { - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); - } else if (status & IM_EPH_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n")); - } else if (status & IM_ERCV_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n")); - outb( IM_ERCV_INT, ioaddr + INTERRUPT ); - } - } while ( timeout -- ); - - - /* restore state register */ - SMC_SELECT_BANK( 2 ); - outb( mask, ioaddr + INT_MASK ); - - PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask)); - outw( saved_pointer, ioaddr + POINTER ); - - SMC_SELECT_BANK( saved_bank ); - - PRINTK3((CARDNAME ": Interrupt done\n")); - return IRQ_RETVAL(handled); -} - - -/*---------------------------------------------------- - . smc_close - . - . this makes the board clean up everything that it can - . and not talk to the outside world. Caused by - . an 'ifconfig ethX down' - . - -----------------------------------------------------*/ -static int smc_close(struct net_device *dev) -{ - netif_stop_queue(dev); - /* clear everything */ - smc_shutdown( dev->base_addr ); - - /* Update the statistics here. */ - return 0; -} - -/*----------------------------------------------------------- - . smc_set_multicast_list - . - . This routine will, depending on the values passed to it, - . either make it accept multicast packets, go into - . promiscuous mode ( for TCPDUMP and cousins ) or accept - . a select set of multicast packets -*/ -static void smc_set_multicast_list(struct net_device *dev) -{ - short ioaddr = dev->base_addr; - - SMC_SELECT_BANK(0); - if ( dev->flags & IFF_PROMISC ) - outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR ); - -/* BUG? I never disable promiscuous mode if multicasting was turned on. - Now, I turn off promiscuous mode, but I don't do anything to multicasting - when promiscuous mode is turned on. -*/ - - /* Here, I am setting this to accept all multicast packets. - I don't need to zero the multicast table, because the flag is - checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI) - outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR ); - - /* We just get all multicast packets even if we only want them - . from one source. This will be changed at some future - . point. */ - else if (!netdev_mc_empty(dev)) { - /* support hardware multicasting */ - - /* be sure I get rid of flags I might have set */ - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); - /* NOTE: this has to set the bank, so make sure it is the - last thing called. The bank is set to zero at the top */ - smc_setmulticast(ioaddr, dev); - } - else { - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); - - /* - since I'm disabling all multicast entirely, I need to - clear the multicast list - */ - SMC_SELECT_BANK( 3 ); - outw( 0, ioaddr + MULTICAST1 ); - outw( 0, ioaddr + MULTICAST2 ); - outw( 0, ioaddr + MULTICAST3 ); - outw( 0, ioaddr + MULTICAST4 ); - } -} - -#ifdef MODULE - -static struct net_device *devSMC9194; -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -module_param(irq, int, 0); -module_param(ifport, int, 0); -MODULE_PARM_DESC(io, "SMC 99194 I/O base address"); -MODULE_PARM_DESC(irq, "SMC 99194 IRQ number"); -MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)"); - -int __init init_module(void) -{ - if (io == 0) - printk(KERN_WARNING - CARDNAME": You shouldn't use auto-probing with insmod!\n" ); - - /* copy the parameters from insmod into the device structure */ - devSMC9194 = smc_init(-1); - if (IS_ERR(devSMC9194)) - return PTR_ERR(devSMC9194); - return 0; -} - -void __exit cleanup_module(void) -{ - unregister_netdev(devSMC9194); - free_irq(devSMC9194->irq, devSMC9194); - release_region(devSMC9194->base_addr, SMC_IO_EXTENT); - free_netdev(devSMC9194); -} - -#endif /* MODULE */ diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.h b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.h deleted file mode 100644 index cf69d0a5..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc9194.h +++ /dev/null @@ -1,241 +0,0 @@ -/*------------------------------------------------------------------------ - . smc9194.h - . Copyright (C) 1996 by Erik Stahlman - . - . This software may be used and distributed according to the terms - . of the GNU General Public License, incorporated herein by reference. - . - . This file contains register information and access macros for - . the SMC91xxx chipset. - . - . Information contained in this file was obtained from the SMC91C94 - . manual from SMC. To get a copy, if you really want one, you can find - . information under www.smc.com in the components division. - . ( this thanks to advice from Donald Becker ). - . - . Authors - . Erik Stahlman ( erik@vt.edu ) - . - . History - . 01/06/96 Erik Stahlman moved definitions here from main .c file - . 01/19/96 Erik Stahlman polished this up some, and added better - . error handling - . - ---------------------------------------------------------------------------*/ -#ifndef _SMC9194_H_ -#define _SMC9194_H_ - -/* I want some simple types */ - -typedef unsigned char byte; -typedef unsigned short word; -typedef unsigned long int dword; - - -/* Because of bank switching, the SMC91xxx uses only 16 I/O ports */ - -#define SMC_IO_EXTENT 16 - - -/*--------------------------------------------------------------- - . - . A description of the SMC registers is probably in order here, - . although for details, the SMC datasheet is invaluable. - . - . Basically, the chip has 4 banks of registers ( 0 to 3 ), which - . are accessed by writing a number into the BANK_SELECT register - . ( I also use a SMC_SELECT_BANK macro for this ). - . - . The banks are configured so that for most purposes, bank 2 is all - . that is needed for simple run time tasks. - -----------------------------------------------------------------------*/ - -/* - . Bank Select Register: - . - . yyyy yyyy 0000 00xx - . xx = bank number - . yyyy yyyy = 0x33, for identification purposes. -*/ -#define BANK_SELECT 14 - -/* BANK 0 */ - -#define TCR 0 /* transmit control register */ -#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ -#define TCR_FDUPLX 0x0800 /* receive packets sent out */ -#define TCR_STP_SQET 0x1000 /* stop transmitting if Signal quality error */ -#define TCR_MON_CNS 0x0400 /* monitors the carrier status */ -#define TCR_PAD_ENABLE 0x0080 /* pads short packets to 64 bytes */ - -#define TCR_CLEAR 0 /* do NOTHING */ -/* the normal settings for the TCR register : */ -/* QUESTION: do I want to enable padding of short packets ? */ -#define TCR_NORMAL TCR_ENABLE - - -#define EPH_STATUS 2 -#define ES_LINK_OK 0x4000 /* is the link integrity ok ? */ - -#define RCR 4 -#define RCR_SOFTRESET 0x8000 /* resets the chip */ -#define RCR_STRIP_CRC 0x200 /* strips CRC */ -#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */ -#define RCR_ALMUL 0x4 /* receive all multicast packets */ -#define RCR_PROMISC 0x2 /* enable promiscuous mode */ - -/* the normal settings for the RCR register : */ -#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE) -#define RCR_CLEAR 0x0 /* set it to a base state */ - -#define COUNTER 6 -#define MIR 8 -#define MCR 10 -/* 12 is reserved */ - -/* BANK 1 */ -#define CONFIG 0 -#define CFG_AUI_SELECT 0x100 -#define BASE 2 -#define ADDR0 4 -#define ADDR1 6 -#define ADDR2 8 -#define GENERAL 10 -#define CONTROL 12 -#define CTL_POWERDOWN 0x2000 -#define CTL_LE_ENABLE 0x80 -#define CTL_CR_ENABLE 0x40 -#define CTL_TE_ENABLE 0x0020 -#define CTL_AUTO_RELEASE 0x0800 -#define CTL_EPROM_ACCESS 0x0003 /* high if Eprom is being read */ - -/* BANK 2 */ -#define MMU_CMD 0 -#define MC_BUSY 1 /* only readable bit in the register */ -#define MC_NOP 0 -#define MC_ALLOC 0x20 /* or with number of 256 byte packets */ -#define MC_RESET 0x40 -#define MC_REMOVE 0x60 /* remove the current rx packet */ -#define MC_RELEASE 0x80 /* remove and release the current rx packet */ -#define MC_FREEPKT 0xA0 /* Release packet in PNR register */ -#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */ - -#define PNR_ARR 2 -#define FIFO_PORTS 4 - -#define FP_RXEMPTY 0x8000 -#define FP_TXEMPTY 0x80 - -#define POINTER 6 -#define PTR_READ 0x2000 -#define PTR_RCV 0x8000 -#define PTR_AUTOINC 0x4000 -#define PTR_AUTO_INC 0x0040 - -#define DATA_1 8 -#define DATA_2 10 -#define INTERRUPT 12 - -#define INT_MASK 13 -#define IM_RCV_INT 0x1 -#define IM_TX_INT 0x2 -#define IM_TX_EMPTY_INT 0x4 -#define IM_ALLOC_INT 0x8 -#define IM_RX_OVRN_INT 0x10 -#define IM_EPH_INT 0x20 -#define IM_ERCV_INT 0x40 /* not on SMC9192 */ - -/* BANK 3 */ -#define MULTICAST1 0 -#define MULTICAST2 2 -#define MULTICAST3 4 -#define MULTICAST4 6 -#define MGMT 8 -#define REVISION 10 /* ( hi: chip id low: rev # ) */ - - -/* this is NOT on SMC9192 */ -#define ERCV 12 - -#define CHIP_9190 3 -#define CHIP_9194 4 -#define CHIP_9195 5 -#define CHIP_91100 7 - -static const char * chip_ids[ 15 ] = { - NULL, NULL, NULL, - /* 3 */ "SMC91C90/91C92", - /* 4 */ "SMC91C94", - /* 5 */ "SMC91C95", - NULL, - /* 7 */ "SMC91C100", - /* 8 */ "SMC91C100FD", - NULL, NULL, NULL, - NULL, NULL, NULL}; - -/* - . Transmit status bits -*/ -#define TS_SUCCESS 0x0001 -#define TS_LOSTCAR 0x0400 -#define TS_LATCOL 0x0200 -#define TS_16COL 0x0010 - -/* - . Receive status bits -*/ -#define RS_ALGNERR 0x8000 -#define RS_BADCRC 0x2000 -#define RS_ODDFRAME 0x1000 -#define RS_TOOLONG 0x0800 -#define RS_TOOSHORT 0x0400 -#define RS_MULTICAST 0x0001 -#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) - -static const char * interfaces[ 2 ] = { "TP", "AUI" }; - -/*------------------------------------------------------------------------- - . I define some macros to make it easier to do somewhat common - . or slightly complicated, repeated tasks. - --------------------------------------------------------------------------*/ - -/* select a register bank, 0 to 3 */ - -#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT ); } - -/* define a small delay for the reset */ -#define SMC_DELAY() { inw( ioaddr + RCR );\ - inw( ioaddr + RCR );\ - inw( ioaddr + RCR ); } - -/* this enables an interrupt in the interrupt mask register */ -#define SMC_ENABLE_INT(x) {\ - unsigned char mask;\ - SMC_SELECT_BANK(2);\ - mask = inb( ioaddr + INT_MASK );\ - mask |= (x);\ - outb( mask, ioaddr + INT_MASK ); \ -} - -/* this disables an interrupt from the interrupt mask register */ - -#define SMC_DISABLE_INT(x) {\ - unsigned char mask;\ - SMC_SELECT_BANK(2);\ - mask = inb( ioaddr + INT_MASK );\ - mask &= ~(x);\ - outb( mask, ioaddr + INT_MASK ); \ -} - -/*---------------------------------------------------------------------- - . Define the interrupts that I want to receive from the card - . - . I want: - . IM_EPH_INT, for nasty errors - . IM_RCV_INT, for happy received packets - . IM_RX_OVRN_INT, because I have to kick the receiver - --------------------------------------------------------------------------*/ -#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) - -#endif /* _SMC_9194_H_ */ - diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91c92_cs.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91c92_cs.c deleted file mode 100644 index 04393b5f..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91c92_cs.c +++ /dev/null @@ -1,2069 +0,0 @@ -/*====================================================================== - - A PCMCIA ethernet driver for SMC91c92-based cards. - - This driver supports Megahertz PCMCIA ethernet cards; and - Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem - multifunction cards. - - Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - - smc91c92_cs.c 1.122 2002/10/25 06:26:39 - - This driver contains code written by Donald Becker - (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au), - David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman - (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of - Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've - incorporated some parts of his driver here. I (Dave) wrote most - of the PCMCIA glue code, and the Ositech support code. Kelly - Stephens (kstephen@holli.com) added support for the Motorola - Mariner, with help from Allen Brost. - - This software may be used and distributed according to the terms of - the GNU General Public License, incorporated herein by reference. - -======================================================================*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/crc32.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/ioport.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/jiffies.h> -#include <linux/firmware.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ciscode.h> -#include <pcmcia/ds.h> -#include <pcmcia/ss.h> - -#include <asm/io.h> -#include <asm/uaccess.h> - -/*====================================================================*/ - -static const char *if_names[] = { "auto", "10baseT", "10base2"}; - -/* Firmware name */ -#define FIRMWARE_NAME "ositech/Xilinx7OD.bin" - -/* Module parameters */ - -MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FIRMWARE_NAME); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -/* - Transceiver/media type. - 0 = auto - 1 = 10baseT (and autoselect if #define AUTOSELECT), - 2 = AUI/10base2, -*/ -INT_MODULE_PARM(if_port, 0); - - -#define DRV_NAME "smc91c92_cs" -#define DRV_VERSION "1.123" - -/*====================================================================*/ - -/* Operational parameter that usually are not changed. */ - -/* Time in jiffies before concluding Tx hung */ -#define TX_TIMEOUT ((400*HZ)/1000) - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -#define INTR_WORK 4 - -/* Times to check the check the chip before concluding that it doesn't - currently have room for another Tx packet. */ -#define MEMORY_WAIT_TIME 8 - -struct smc_private { - struct pcmcia_device *p_dev; - spinlock_t lock; - u_short manfid; - u_short cardid; - - struct sk_buff *saved_skb; - int packets_waiting; - void __iomem *base; - u_short cfg; - struct timer_list media; - int watchdog, tx_err; - u_short media_status; - u_short fast_poll; - u_short link_status; - struct mii_if_info mii_if; - int duplex; - int rx_ovrn; -}; - -/* Special definitions for Megahertz multifunction cards */ -#define MEGAHERTZ_ISR 0x0380 - -/* Special function registers for Motorola Mariner */ -#define MOT_LAN 0x0000 -#define MOT_UART 0x0020 -#define MOT_EEPROM 0x20 - -#define MOT_NORMAL \ -(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA) - -/* Special function registers for Ositech cards */ -#define OSITECH_AUI_CTL 0x0c -#define OSITECH_PWRDOWN 0x0d -#define OSITECH_RESET 0x0e -#define OSITECH_ISR 0x0f -#define OSITECH_AUI_PWR 0x0c -#define OSITECH_RESET_ISR 0x0e - -#define OSI_AUI_PWR 0x40 -#define OSI_LAN_PWRDOWN 0x02 -#define OSI_MODEM_PWRDOWN 0x01 -#define OSI_LAN_RESET 0x02 -#define OSI_MODEM_RESET 0x01 - -/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */ -#define BANK_SELECT 14 /* Window select register. */ -#define SMC_SELECT_BANK(x) { outw(x, ioaddr + BANK_SELECT); } - -/* Bank 0 registers. */ -#define TCR 0 /* transmit control register */ -#define TCR_CLEAR 0 /* do NOTHING */ -#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ -#define TCR_PAD_EN 0x0080 /* pads short packets to 64 bytes */ -#define TCR_MONCSN 0x0400 /* Monitor Carrier. */ -#define TCR_FDUPLX 0x0800 /* Full duplex mode. */ -#define TCR_NORMAL TCR_ENABLE | TCR_PAD_EN - -#define EPH 2 /* Ethernet Protocol Handler report. */ -#define EPH_TX_SUC 0x0001 -#define EPH_SNGLCOL 0x0002 -#define EPH_MULCOL 0x0004 -#define EPH_LTX_MULT 0x0008 -#define EPH_16COL 0x0010 -#define EPH_SQET 0x0020 -#define EPH_LTX_BRD 0x0040 -#define EPH_TX_DEFR 0x0080 -#define EPH_LAT_COL 0x0200 -#define EPH_LOST_CAR 0x0400 -#define EPH_EXC_DEF 0x0800 -#define EPH_CTR_ROL 0x1000 -#define EPH_RX_OVRN 0x2000 -#define EPH_LINK_OK 0x4000 -#define EPH_TX_UNRN 0x8000 -#define MEMINFO 8 /* Memory Information Register */ -#define MEMCFG 10 /* Memory Configuration Register */ - -/* Bank 1 registers. */ -#define CONFIG 0 -#define CFG_MII_SELECT 0x8000 /* 91C100 only */ -#define CFG_NO_WAIT 0x1000 -#define CFG_FULL_STEP 0x0400 -#define CFG_SET_SQLCH 0x0200 -#define CFG_AUI_SELECT 0x0100 -#define CFG_16BIT 0x0080 -#define CFG_DIS_LINK 0x0040 -#define CFG_STATIC 0x0030 -#define CFG_IRQ_SEL_1 0x0004 -#define CFG_IRQ_SEL_0 0x0002 -#define BASE_ADDR 2 -#define ADDR0 4 -#define GENERAL 10 -#define CONTROL 12 -#define CTL_STORE 0x0001 -#define CTL_RELOAD 0x0002 -#define CTL_EE_SELECT 0x0004 -#define CTL_TE_ENABLE 0x0020 -#define CTL_CR_ENABLE 0x0040 -#define CTL_LE_ENABLE 0x0080 -#define CTL_AUTO_RELEASE 0x0800 -#define CTL_POWERDOWN 0x2000 - -/* Bank 2 registers. */ -#define MMU_CMD 0 -#define MC_ALLOC 0x20 /* or with number of 256 byte packets */ -#define MC_RESET 0x40 -#define MC_RELEASE 0x80 /* remove and release the current rx packet */ -#define MC_FREEPKT 0xA0 /* Release packet in PNR register */ -#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */ -#define PNR_ARR 2 -#define FIFO_PORTS 4 -#define FP_RXEMPTY 0x8000 -#define POINTER 6 -#define PTR_AUTO_INC 0x0040 -#define PTR_READ 0x2000 -#define PTR_AUTOINC 0x4000 -#define PTR_RCV 0x8000 -#define DATA_1 8 -#define INTERRUPT 12 -#define IM_RCV_INT 0x1 -#define IM_TX_INT 0x2 -#define IM_TX_EMPTY_INT 0x4 -#define IM_ALLOC_INT 0x8 -#define IM_RX_OVRN_INT 0x10 -#define IM_EPH_INT 0x20 - -#define RCR 4 -enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002, - RxEnable = 0x0100, RxStripCRC = 0x0200}; -#define RCR_SOFTRESET 0x8000 /* resets the chip */ -#define RCR_STRIP_CRC 0x200 /* strips CRC */ -#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */ -#define RCR_ALMUL 0x4 /* receive all multicast packets */ -#define RCR_PROMISC 0x2 /* enable promiscuous mode */ - -/* the normal settings for the RCR register : */ -#define RCR_NORMAL (RCR_STRIP_CRC | RCR_ENABLE) -#define RCR_CLEAR 0x0 /* set it to a base state */ -#define COUNTER 6 - -/* BANK 3 -- not the same values as in smc9194! */ -#define MULTICAST0 0 -#define MULTICAST2 2 -#define MULTICAST4 4 -#define MULTICAST6 6 -#define MGMT 8 -#define REVISION 0x0a - -/* Transmit status bits. */ -#define TS_SUCCESS 0x0001 -#define TS_16COL 0x0010 -#define TS_LATCOL 0x0200 -#define TS_LOSTCAR 0x0400 - -/* Receive status bits. */ -#define RS_ALGNERR 0x8000 -#define RS_BADCRC 0x2000 -#define RS_ODDFRAME 0x1000 -#define RS_TOOLONG 0x0800 -#define RS_TOOSHORT 0x0400 -#define RS_MULTICAST 0x0001 -#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) - -#define set_bits(v, p) outw(inw(p)|(v), (p)) -#define mask_bits(v, p) outw(inw(p)&(v), (p)) - -/*====================================================================*/ - -static void smc91c92_detach(struct pcmcia_device *p_dev); -static int smc91c92_config(struct pcmcia_device *link); -static void smc91c92_release(struct pcmcia_device *link); - -static int smc_open(struct net_device *dev); -static int smc_close(struct net_device *dev); -static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void smc_tx_timeout(struct net_device *dev); -static netdev_tx_t smc_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t smc_interrupt(int irq, void *dev_id); -static void smc_rx(struct net_device *dev); -static void set_rx_mode(struct net_device *dev); -static int s9k_config(struct net_device *dev, struct ifmap *map); -static void smc_set_xcvr(struct net_device *dev, int if_port); -static void smc_reset(struct net_device *dev); -static void media_check(u_long arg); -static void mdio_sync(unsigned int addr); -static int mdio_read(struct net_device *dev, int phy_id, int loc); -static void mdio_write(struct net_device *dev, int phy_id, int loc, int value); -static int smc_link_ok(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - -static const struct net_device_ops smc_netdev_ops = { - .ndo_open = smc_open, - .ndo_stop = smc_close, - .ndo_start_xmit = smc_start_xmit, - .ndo_tx_timeout = smc_tx_timeout, - .ndo_set_config = s9k_config, - .ndo_set_rx_mode = set_rx_mode, - .ndo_do_ioctl = smc_ioctl, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int smc91c92_probe(struct pcmcia_device *link) -{ - struct smc_private *smc; - struct net_device *dev; - - dev_dbg(&link->dev, "smc91c92_attach()\n"); - - /* Create new ethernet device */ - dev = alloc_etherdev(sizeof(struct smc_private)); - if (!dev) - return -ENOMEM; - smc = netdev_priv(dev); - smc->p_dev = link; - link->priv = dev; - - spin_lock_init(&smc->lock); - - /* The SMC91c92-specific entries in the device structure. */ - dev->netdev_ops = &smc_netdev_ops; - SET_ETHTOOL_OPS(dev, ðtool_ops); - dev->watchdog_timeo = TX_TIMEOUT; - - smc->mii_if.dev = dev; - smc->mii_if.mdio_read = mdio_read; - smc->mii_if.mdio_write = mdio_write; - smc->mii_if.phy_id_mask = 0x1f; - smc->mii_if.reg_num_mask = 0x1f; - - return smc91c92_config(link); -} /* smc91c92_attach */ - -static void smc91c92_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - dev_dbg(&link->dev, "smc91c92_detach\n"); - - unregister_netdev(dev); - - smc91c92_release(link); - - free_netdev(dev); -} /* smc91c92_detach */ - -/*====================================================================*/ - -static int cvt_ascii_address(struct net_device *dev, char *s) -{ - int i, j, da, c; - - if (strlen(s) != 12) - return -1; - for (i = 0; i < 6; i++) { - da = 0; - for (j = 0; j < 2; j++) { - c = *s++; - da <<= 4; - da += ((c >= '0') && (c <= '9')) ? - (c - '0') : ((c & 0x0f) + 9); - } - dev->dev_addr[i] = da; - } - return 0; -} - -/*==================================================================== - - Configuration stuff for Megahertz cards - - mhz_3288_power() is used to power up a 3288's ethernet chip. - mhz_mfc_config() handles socket setup for multifunction (1144 - and 3288) cards. mhz_setup() gets a card's hardware ethernet - address. - -======================================================================*/ - -static int mhz_3288_power(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - u_char tmp; - - /* Read the ISR twice... */ - readb(smc->base+MEGAHERTZ_ISR); - udelay(5); - readb(smc->base+MEGAHERTZ_ISR); - - /* Pause 200ms... */ - mdelay(200); - - /* Now read and write the COR... */ - tmp = readb(smc->base + link->config_base + CISREG_COR); - udelay(5); - writeb(tmp, smc->base + link->config_base + CISREG_COR); - - return 0; -} - -static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - int k; - p_dev->io_lines = 16; - p_dev->resource[1]->start = p_dev->resource[0]->start; - p_dev->resource[1]->end = 8; - p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - for (k = 0; k < 0x400; k += 0x10) { - if (k & 0x80) - continue; - p_dev->resource[0]->start = k ^ 0x300; - if (!pcmcia_request_io(p_dev)) - return 0; - } - return -ENODEV; -} - -static int mhz_mfc_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - unsigned int offset; - int i; - - link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ | - CONF_AUTO_SET_IO; - - /* The Megahertz combo cards have modem-like CIS entries, so - we have to explicitly try a bunch of port combinations. */ - if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL)) - return -ENODEV; - - dev->base_addr = link->resource[0]->start; - - /* Allocate a memory window, for accessing the ISR */ - link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - link->resource[2]->start = link->resource[2]->end = 0; - i = pcmcia_request_window(link, link->resource[2], 0); - if (i != 0) - return -ENODEV; - - smc->base = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0; - i = pcmcia_map_mem_page(link, link->resource[2], offset); - if ((i == 0) && - (smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - - return 0; -} - -static int pcmcia_get_versmac(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev = priv; - cisparse_t parse; - u8 *buf; - - if (pcmcia_parse_tuple(tuple, &parse)) - return -EINVAL; - - buf = parse.version_1.str + parse.version_1.ofs[3]; - - if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0)) - return 0; - - return -EINVAL; -}; - -static int mhz_setup(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - size_t len; - u8 *buf; - int rc; - - /* Read the station address from the CIS. It is stored as the last - (fourth) string in the Version 1 Version/ID tuple. */ - if ((link->prod_id[3]) && - (cvt_ascii_address(dev, link->prod_id[3]) == 0)) - return 0; - - /* Workarounds for broken cards start here. */ - /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev)) - return 0; - - /* Another possibility: for the EM3288, in a special tuple */ - rc = -1; - len = pcmcia_get_tuple(link, 0x81, &buf); - if (buf && len >= 13) { - buf[12] = '\0'; - if (cvt_ascii_address(dev, buf) == 0) - rc = 0; - } - kfree(buf); - - return rc; -}; - -/*====================================================================== - - Configuration stuff for the Motorola Mariner - - mot_config() writes directly to the Mariner configuration - registers because the CIS is just bogus. - -======================================================================*/ - -static void mot_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - unsigned int iouart = link->resource[1]->start; - - /* Set UART base address and force map with COR bit 1 */ - writeb(iouart & 0xff, smc->base + MOT_UART + CISREG_IOBASE_0); - writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1); - writeb(MOT_NORMAL, smc->base + MOT_UART + CISREG_COR); - - /* Set SMC base address and force map with COR bit 1 */ - writeb(ioaddr & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_0); - writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1); - writeb(MOT_NORMAL, smc->base + MOT_LAN + CISREG_COR); - - /* Wait for things to settle down */ - mdelay(100); -} - -static int mot_setup(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - unsigned int ioaddr = dev->base_addr; - int i, wait, loop; - u_int addr; - - /* Read Ethernet address from Serial EEPROM */ - - for (i = 0; i < 3; i++) { - SMC_SELECT_BANK(2); - outw(MOT_EEPROM + i, ioaddr + POINTER); - SMC_SELECT_BANK(1); - outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL); - - for (loop = wait = 0; loop < 200; loop++) { - udelay(10); - wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL)); - if (wait == 0) break; - } - - if (wait) - return -1; - - addr = inw(ioaddr + GENERAL); - dev->dev_addr[2*i] = addr & 0xff; - dev->dev_addr[2*i+1] = (addr >> 8) & 0xff; - } - - return 0; -} - -/*====================================================================*/ - -static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - return pcmcia_request_io(p_dev); -} - -static int smc_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int i; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - i = pcmcia_loop_config(link, smc_configcheck, NULL); - if (!i) - dev->base_addr = link->resource[0]->start; - - return i; -} - - -static int smc_setup(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - /* Check for a LAN function extension tuple */ - if (!pcmcia_get_mac_from_cis(link, dev)) - return 0; - - /* Try the third string in the Version 1 Version/ID tuple. */ - if (link->prod_id[2]) { - if (cvt_ascii_address(dev, link->prod_id[2]) == 0) - return 0; - } - return -1; -} - -/*====================================================================*/ - -static int osi_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; - int i, j; - - link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ; - link->resource[0]->end = 64; - link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[1]->end = 8; - - /* Enable Hard Decode, LAN, Modem */ - link->io_lines = 16; - link->config_index = 0x23; - - for (i = j = 0; j < 4; j++) { - link->resource[1]->start = com[j]; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) { - /* Fallback: turn off hard decode */ - link->config_index = 0x03; - link->resource[1]->end = 0; - i = pcmcia_request_io(link); - } - dev->base_addr = link->resource[0]->start + 0x10; - return i; -} - -static int osi_load_firmware(struct pcmcia_device *link) -{ - const struct firmware *fw; - int i, err; - - err = request_firmware(&fw, FIRMWARE_NAME, &link->dev); - if (err) { - pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME); - return err; - } - - /* Download the Seven of Diamonds firmware */ - for (i = 0; i < fw->size; i++) { - outb(fw->data[i], link->resource[0]->start + 2); - udelay(50); - } - release_firmware(fw); - return err; -} - -static int pcmcia_osi_mac(struct pcmcia_device *p_dev, - tuple_t *tuple, - void *priv) -{ - struct net_device *dev = priv; - int i; - - if (tuple->TupleDataLen < 8) - return -EINVAL; - if (tuple->TupleData[0] != 0x04) - return -EINVAL; - for (i = 0; i < 6; i++) - dev->dev_addr[i] = tuple->TupleData[i+2]; - return 0; -}; - - -static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) -{ - struct net_device *dev = link->priv; - int rc; - - /* Read the station address from tuple 0x90, subtuple 0x04 */ - if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev)) - return -1; - - if (((manfid == MANFID_OSITECH) && - (cardid == PRODID_OSITECH_SEVEN)) || - ((manfid == MANFID_PSION) && - (cardid == PRODID_PSION_NET100))) { - rc = osi_load_firmware(link); - if (rc) - return rc; - } else if (manfid == MANFID_OSITECH) { - /* Make sure both functions are powered up */ - set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR); - /* Now, turn on the interrupt for both card functions */ - set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR); - dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", - inw(link->resource[0]->start + OSITECH_AUI_PWR), - inw(link->resource[0]->start + OSITECH_RESET_ISR)); - } - return 0; -} - -static int smc91c92_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int smc91c92_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - int i; - - if ((smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - if (smc->manfid == MANFID_MOTOROLA) - mot_config(link); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - /* Power up the card and enable interrupts */ - set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); - set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); - } - if (((smc->manfid == MANFID_OSITECH) && - (smc->cardid == PRODID_OSITECH_SEVEN)) || - ((smc->manfid == MANFID_PSION) && - (smc->cardid == PRODID_PSION_NET100))) { - i = osi_load_firmware(link); - if (i) { - pr_err("smc91c92_cs: Failed to load firmware\n"); - return i; - } - } - if (link->open) { - smc_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -/*====================================================================== - - This verifies that the chip is some SMC91cXX variant, and returns - the revision code if successful. Otherwise, it returns -ENODEV. - -======================================================================*/ - -static int check_sig(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - unsigned int ioaddr = dev->base_addr; - int width; - u_short s; - - SMC_SELECT_BANK(1); - if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) { - /* Try powering up the chip */ - outw(0, ioaddr + CONTROL); - mdelay(55); - } - - /* Try setting bus width */ - width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO); - s = inb(ioaddr + CONFIG); - if (width) - s |= CFG_16BIT; - else - s &= ~CFG_16BIT; - outb(s, ioaddr + CONFIG); - - /* Check Base Address Register to make sure bus width is OK */ - s = inw(ioaddr + BASE_ADDR); - if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) && - ((s >> 8) != (s & 0xff))) { - SMC_SELECT_BANK(3); - s = inw(ioaddr + REVISION); - return s & 0xff; - } - - if (width) { - pr_info("using 8-bit IO window\n"); - - smc91c92_suspend(link); - pcmcia_fixup_iowidth(link); - smc91c92_resume(link); - return check_sig(link); - } - return -ENODEV; -} - -static int smc91c92_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - char *name; - int i, rev, j = 0; - unsigned int ioaddr; - u_long mir; - - dev_dbg(&link->dev, "smc91c92_config\n"); - - smc->manfid = link->manf_id; - smc->cardid = link->card_id; - - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - i = osi_config(link); - } else if ((smc->manfid == MANFID_MOTOROLA) || - ((smc->manfid == MANFID_MEGAHERTZ) && - ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) || - (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) { - i = mhz_mfc_config(link); - } else { - i = smc_config(link); - } - if (i) - goto config_failed; - - i = pcmcia_request_irq(link, smc_interrupt); - if (i) - goto config_failed; - i = pcmcia_enable_device(link); - if (i) - goto config_failed; - - if (smc->manfid == MANFID_MOTOROLA) - mot_config(link); - - dev->irq = link->irq; - - if ((if_port >= 0) && (if_port <= 2)) - dev->if_port = if_port; - else - dev_notice(&link->dev, "invalid if_port requested\n"); - - switch (smc->manfid) { - case MANFID_OSITECH: - case MANFID_PSION: - i = osi_setup(link, smc->manfid, smc->cardid); break; - case MANFID_SMC: - case MANFID_NEW_MEDIA: - i = smc_setup(link); break; - case 0x128: /* For broken Megahertz cards */ - case MANFID_MEGAHERTZ: - i = mhz_setup(link); break; - case MANFID_MOTOROLA: - default: /* get the hw address from EEPROM */ - i = mot_setup(link); break; - } - - if (i != 0) { - dev_notice(&link->dev, "Unable to find hardware address.\n"); - goto config_failed; - } - - smc->duplex = 0; - smc->rx_ovrn = 0; - - rev = check_sig(link); - name = "???"; - if (rev > 0) - switch (rev >> 4) { - case 3: name = "92"; break; - case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break; - case 5: name = "95"; break; - case 7: name = "100"; break; - case 8: name = "100-FD"; break; - case 9: name = "110"; break; - } - - ioaddr = dev->base_addr; - if (rev > 0) { - u_long mcr; - SMC_SELECT_BANK(0); - mir = inw(ioaddr + MEMINFO) & 0xff; - if (mir == 0xff) mir++; - /* Get scale factor for memory size */ - mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200; - mir *= 128 * (1<<((mcr >> 9) & 7)); - SMC_SELECT_BANK(1); - smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT; - smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC; - if (smc->manfid == MANFID_OSITECH) - smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0; - if ((rev >> 4) >= 7) - smc->cfg |= CFG_MII_SELECT; - } else - mir = 0; - - if (smc->cfg & CFG_MII_SELECT) { - SMC_SELECT_BANK(3); - - for (i = 0; i < 32; i++) { - j = mdio_read(dev, i, 1); - if ((j != 0) && (j != 0xffff)) break; - } - smc->mii_if.phy_id = (i < 32) ? i : -1; - - SMC_SELECT_BANK(0); - } - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - dev_err(&link->dev, "register_netdev() failed\n"); - goto config_undo; - } - - netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n", - name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr); - - if (rev > 0) { - if (mir & 0x3ff) - netdev_info(dev, " %lu byte", mir); - else - netdev_info(dev, " %lu kb", mir>>10); - pr_cont(" buffer, %s xcvr\n", - (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]); - } - - if (smc->cfg & CFG_MII_SELECT) { - if (smc->mii_if.phy_id != -1) { - netdev_dbg(dev, " MII transceiver at index %d, status %x\n", - smc->mii_if.phy_id, j); - } else { - netdev_notice(dev, " No MII transceivers found!\n"); - } - } - return 0; - -config_undo: - unregister_netdev(dev); -config_failed: - smc91c92_release(link); - free_netdev(dev); - return -ENODEV; -} /* smc91c92_config */ - -static void smc91c92_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "smc91c92_release\n"); - if (link->resource[2]->end) { - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - iounmap(smc->base); - } - pcmcia_disable_device(link); -} - -/*====================================================================== - - MII interface support for SMC91cXX based cards -======================================================================*/ - -#define MDIO_SHIFT_CLK 0x04 -#define MDIO_DATA_OUT 0x01 -#define MDIO_DIR_WRITE 0x08 -#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE) -#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) -#define MDIO_DATA_READ 0x02 - -static void mdio_sync(unsigned int addr) -{ - int bits; - for (bits = 0; bits < 32; bits++) { - outb(MDIO_DATA_WRITE1, addr); - outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr); - } -} - -static int mdio_read(struct net_device *dev, int phy_id, int loc) -{ - unsigned int addr = dev->base_addr + MGMT; - u_int cmd = (0x06<<10)|(phy_id<<5)|loc; - int i, retval = 0; - - mdio_sync(addr); - for (i = 13; i >= 0; i--) { - int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; - outb(dat, addr); - outb(dat | MDIO_SHIFT_CLK, addr); - } - for (i = 19; i > 0; i--) { - outb(0, addr); - retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0); - outb(MDIO_SHIFT_CLK, addr); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) -{ - unsigned int addr = dev->base_addr + MGMT; - u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; - int i; - - mdio_sync(addr); - for (i = 31; i >= 0; i--) { - int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; - outb(dat, addr); - outb(dat | MDIO_SHIFT_CLK, addr); - } - for (i = 1; i >= 0; i--) { - outb(0, addr); - outb(MDIO_SHIFT_CLK, addr); - } -} - -/*====================================================================== - - The driver core code, most of which should be common with a - non-PCMCIA implementation. - -======================================================================*/ - -#ifdef PCMCIA_DEBUG -static void smc_dump(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - u_short i, w, save; - save = inw(ioaddr + BANK_SELECT); - for (w = 0; w < 4; w++) { - SMC_SELECT_BANK(w); - netdev_printk(KERN_DEBUG, dev, "bank %d: ", w); - for (i = 0; i < 14; i += 2) - pr_cont(" %04x", inw(ioaddr + i)); - pr_cont("\n"); - } - outw(save, ioaddr + BANK_SELECT); -} -#endif - -static int smc_open(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - struct pcmcia_device *link = smc->p_dev; - - dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n", - dev->name, dev, inw(dev->base_addr + BANK_SELECT)); -#ifdef PCMCIA_DEBUG - smc_dump(dev); -#endif - - /* Check that the PCMCIA card is still here. */ - if (!pcmcia_dev_present(link)) - return -ENODEV; - /* Physical device present signature. */ - if (check_sig(link) < 0) { - netdev_info(dev, "Yikes! Bad chip signature!\n"); - return -ENODEV; - } - link->open++; - - netif_start_queue(dev); - smc->saved_skb = NULL; - smc->packets_waiting = 0; - - smc_reset(dev); - init_timer(&smc->media); - smc->media.function = media_check; - smc->media.data = (u_long) dev; - smc->media.expires = jiffies + HZ; - add_timer(&smc->media); - - return 0; -} /* smc_open */ - -/*====================================================================*/ - -static int smc_close(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - struct pcmcia_device *link = smc->p_dev; - unsigned int ioaddr = dev->base_addr; - - dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n", - dev->name, inw(ioaddr + BANK_SELECT)); - - netif_stop_queue(dev); - - /* Shut off all interrupts, and turn off the Tx and Rx sections. - Don't bother to check for chip present. */ - SMC_SELECT_BANK(2); /* Nominally paranoia, but do no assume... */ - outw(0, ioaddr + INTERRUPT); - SMC_SELECT_BANK(0); - mask_bits(0xff00, ioaddr + RCR); - mask_bits(0xff00, ioaddr + TCR); - - /* Put the chip into power-down mode. */ - SMC_SELECT_BANK(1); - outw(CTL_POWERDOWN, ioaddr + CONTROL ); - - link->open--; - del_timer_sync(&smc->media); - - return 0; -} /* smc_close */ - -/*====================================================================== - - Transfer a packet to the hardware and trigger the packet send. - This may be called at either from either the Tx queue code - or the interrupt handler. - -======================================================================*/ - -static void smc_hardware_send_packet(struct net_device * dev) -{ - struct smc_private *smc = netdev_priv(dev); - struct sk_buff *skb = smc->saved_skb; - unsigned int ioaddr = dev->base_addr; - u_char packet_no; - - if (!skb) { - netdev_err(dev, "In XMIT with no packet to send\n"); - return; - } - - /* There should be a packet slot waiting. */ - packet_no = inw(ioaddr + PNR_ARR) >> 8; - if (packet_no & 0x80) { - /* If not, there is a hardware problem! Likely an ejected card. */ - netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n", - packet_no); - dev_kfree_skb_irq(skb); - smc->saved_skb = NULL; - netif_start_queue(dev); - return; - } - - dev->stats.tx_bytes += skb->len; - /* The card should use the just-allocated buffer. */ - outw(packet_no, ioaddr + PNR_ARR); - /* point to the beginning of the packet */ - outw(PTR_AUTOINC , ioaddr + POINTER); - - /* Send the packet length (+6 for status, length and ctl byte) - and the status word (set to zeros). */ - { - u_char *buf = skb->data; - u_int length = skb->len; /* The chip will pad to ethernet min. */ - - netdev_dbg(dev, "Trying to xmit packet of length %d\n", length); - - /* send the packet length: +6 for status word, length, and ctl */ - outw(0, ioaddr + DATA_1); - outw(length + 6, ioaddr + DATA_1); - outsw(ioaddr + DATA_1, buf, length >> 1); - - /* The odd last byte, if there is one, goes in the control word. */ - outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1); - } - - /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */ - outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) | - (inw(ioaddr + INTERRUPT) & 0xff00), - ioaddr + INTERRUPT); - - /* The chip does the rest of the work. */ - outw(MC_ENQUEUE , ioaddr + MMU_CMD); - - smc->saved_skb = NULL; - dev_kfree_skb_irq(skb); - dev->trans_start = jiffies; - netif_start_queue(dev); -} - -/*====================================================================*/ - -static void smc_tx_timeout(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - - netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n", - inw(ioaddr)&0xff, inw(ioaddr + 2)); - dev->stats.tx_errors++; - smc_reset(dev); - dev->trans_start = jiffies; /* prevent tx timeout */ - smc->saved_skb = NULL; - netif_wake_queue(dev); -} - -static netdev_tx_t smc_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short num_pages; - short time_out, ir; - unsigned long flags; - - netif_stop_queue(dev); - - netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n", - skb->len, inw(ioaddr + 2)); - - if (smc->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - dev->stats.tx_aborted_errors++; - netdev_printk(KERN_DEBUG, dev, - "Internal error -- sent packet while busy\n"); - return NETDEV_TX_BUSY; - } - smc->saved_skb = skb; - - num_pages = skb->len >> 8; - - if (num_pages > 7) { - netdev_err(dev, "Far too big packet error: %d pages\n", num_pages); - dev_kfree_skb (skb); - smc->saved_skb = NULL; - dev->stats.tx_dropped++; - return NETDEV_TX_OK; /* Do not re-queue this packet. */ - } - /* A packet is now waiting. */ - smc->packets_waiting++; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(2); /* Paranoia, we should always be in window 2 */ - - /* need MC_RESET to keep the memory consistent. errata? */ - if (smc->rx_ovrn) { - outw(MC_RESET, ioaddr + MMU_CMD); - smc->rx_ovrn = 0; - } - - /* Allocate the memory; send the packet now if we win. */ - outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD); - for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) { - ir = inw(ioaddr+INTERRUPT); - if (ir & IM_ALLOC_INT) { - /* Acknowledge the interrupt, send the packet. */ - outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT); - smc_hardware_send_packet(dev); /* Send the packet now.. */ - spin_unlock_irqrestore(&smc->lock, flags); - return NETDEV_TX_OK; - } - } - - /* Otherwise defer until the Tx-space-allocated interrupt. */ - pr_debug("%s: memory allocation deferred.\n", dev->name); - outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); - spin_unlock_irqrestore(&smc->lock, flags); - - return NETDEV_TX_OK; -} - -/*====================================================================== - - Handle a Tx anomalous event. Entered while in Window 2. - -======================================================================*/ - -static void smc_tx_err(struct net_device * dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - int saved_packet = inw(ioaddr + PNR_ARR) & 0xff; - int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f; - int tx_status; - - /* select this as the packet to read from */ - outw(packet_no, ioaddr + PNR_ARR); - - /* read the first word from this packet */ - outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER); - - tx_status = inw(ioaddr + DATA_1); - - dev->stats.tx_errors++; - if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++; - if (tx_status & TS_LATCOL) dev->stats.tx_window_errors++; - if (tx_status & TS_16COL) { - dev->stats.tx_aborted_errors++; - smc->tx_err++; - } - - if (tx_status & TS_SUCCESS) { - netdev_notice(dev, "Successful packet caused error interrupt?\n"); - } - /* re-enable transmit */ - SMC_SELECT_BANK(0); - outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR); - SMC_SELECT_BANK(2); - - outw(MC_FREEPKT, ioaddr + MMU_CMD); /* Free the packet memory. */ - - /* one less packet waiting for me */ - smc->packets_waiting--; - - outw(saved_packet, ioaddr + PNR_ARR); -} - -/*====================================================================*/ - -static void smc_eph_irq(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short card_stats, ephs; - - SMC_SELECT_BANK(0); - ephs = inw(ioaddr + EPH); - pr_debug("%s: Ethernet protocol handler interrupt, status" - " %4.4x.\n", dev->name, ephs); - /* Could be a counter roll-over warning: update stats. */ - card_stats = inw(ioaddr + COUNTER); - /* single collisions */ - dev->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - /* multiple collisions */ - dev->stats.collisions += card_stats & 0xF; -#if 0 /* These are for when linux supports these statistics */ - card_stats >>= 4; /* deferred */ - card_stats >>= 4; /* excess deferred */ -#endif - /* If we had a transmit error we must re-enable the transmitter. */ - outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR); - - /* Clear a link error interrupt. */ - SMC_SELECT_BANK(1); - outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL); - outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, - ioaddr + CONTROL); - SMC_SELECT_BANK(2); -} - -/*====================================================================*/ - -static irqreturn_t smc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr; - u_short saved_bank, saved_pointer, mask, status; - unsigned int handled = 1; - char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ - - if (!netif_device_present(dev)) - return IRQ_NONE; - - ioaddr = dev->base_addr; - - pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name, - irq, ioaddr); - - spin_lock(&smc->lock); - smc->watchdog = 0; - saved_bank = inw(ioaddr + BANK_SELECT); - if ((saved_bank & 0xff00) != 0x3300) { - /* The device does not exist -- the card could be off-line, or - maybe it has been ejected. */ - pr_debug("%s: SMC91c92 interrupt %d for non-existent" - "/ejected device.\n", dev->name, irq); - handled = 0; - goto irq_done; - } - - SMC_SELECT_BANK(2); - saved_pointer = inw(ioaddr + POINTER); - mask = inw(ioaddr + INTERRUPT) >> 8; - /* clear all interrupts */ - outw(0, ioaddr + INTERRUPT); - - do { /* read the status flag, and mask it */ - status = inw(ioaddr + INTERRUPT) & 0xff; - pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name, - status, mask); - if ((status & mask) == 0) { - if (bogus_cnt == INTR_WORK) - handled = 0; - break; - } - if (status & IM_RCV_INT) { - /* Got a packet(s). */ - smc_rx(dev); - } - if (status & IM_TX_INT) { - smc_tx_err(dev); - outw(IM_TX_INT, ioaddr + INTERRUPT); - } - status &= mask; - if (status & IM_TX_EMPTY_INT) { - outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT); - mask &= ~IM_TX_EMPTY_INT; - dev->stats.tx_packets += smc->packets_waiting; - smc->packets_waiting = 0; - } - if (status & IM_ALLOC_INT) { - /* Clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - - smc_hardware_send_packet(dev); - - /* enable xmit interrupts based on this */ - mask |= (IM_TX_EMPTY_INT | IM_TX_INT); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - } - if (status & IM_RX_OVRN_INT) { - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - if (smc->duplex) - smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */ - outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT); - } - if (status & IM_EPH_INT) - smc_eph_irq(dev); - } while (--bogus_cnt); - - pr_debug(" Restoring saved registers mask %2.2x bank %4.4x" - " pointer %4.4x.\n", mask, saved_bank, saved_pointer); - - /* restore state register */ - outw((mask<<8), ioaddr + INTERRUPT); - outw(saved_pointer, ioaddr + POINTER); - SMC_SELECT_BANK(saved_bank); - - pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq); - -irq_done: - - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - /* Retrigger interrupt if needed */ - mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR); - set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR); - } - if (smc->manfid == MANFID_MOTOROLA) { - u_char cor; - cor = readb(smc->base + MOT_UART + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR); - writeb(cor, smc->base + MOT_UART + CISREG_COR); - cor = readb(smc->base + MOT_LAN + CISREG_COR); - writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR); - writeb(cor, smc->base + MOT_LAN + CISREG_COR); - } - - if ((smc->base != NULL) && /* Megahertz MFC's */ - (smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) { - - u_char tmp; - tmp = readb(smc->base+MEGAHERTZ_ISR); - tmp = readb(smc->base+MEGAHERTZ_ISR); - - /* Retrigger interrupt if needed */ - writeb(tmp, smc->base + MEGAHERTZ_ISR); - writeb(tmp, smc->base + MEGAHERTZ_ISR); - } - - spin_unlock(&smc->lock); - return IRQ_RETVAL(handled); -} - -/*====================================================================*/ - -static void smc_rx(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - int rx_status; - int packet_length; /* Caution: not frame length, rather words - to transfer from the chip. */ - - /* Assertion: we are in Window 2. */ - - if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) { - netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n"); - return; - } - - /* Reset the read pointer, and read the status and packet length. */ - outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER); - rx_status = inw(ioaddr + DATA_1); - packet_length = inw(ioaddr + DATA_1) & 0x07ff; - - pr_debug("%s: Receive status %4.4x length %d.\n", - dev->name, rx_status, packet_length); - - if (!(rx_status & RS_ERRORS)) { - /* do stuff to make a new packet */ - struct sk_buff *skb; - - /* Note: packet_length adds 5 or 6 extra bytes here! */ - skb = netdev_alloc_skb(dev, packet_length+2); - - if (skb == NULL) { - pr_debug("%s: Low memory, packet dropped.\n", dev->name); - dev->stats.rx_dropped++; - outw(MC_RELEASE, ioaddr + MMU_CMD); - return; - } - - packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6); - skb_reserve(skb, 2); - insw(ioaddr+DATA_1, skb_put(skb, packet_length), - (packet_length+1)>>1); - skb->protocol = eth_type_trans(skb, dev); - - netif_rx(skb); - dev->last_rx = jiffies; - dev->stats.rx_packets++; - dev->stats.rx_bytes += packet_length; - if (rx_status & RS_MULTICAST) - dev->stats.multicast++; - } else { - /* error ... */ - dev->stats.rx_errors++; - - if (rx_status & RS_ALGNERR) dev->stats.rx_frame_errors++; - if (rx_status & (RS_TOOSHORT | RS_TOOLONG)) - dev->stats.rx_length_errors++; - if (rx_status & RS_BADCRC) dev->stats.rx_crc_errors++; - } - /* Let the MMU free the memory of this packet. */ - outw(MC_RELEASE, ioaddr + MMU_CMD); -} - -/*====================================================================== - - Set the receive mode. - - This routine is used by both the protocol level to notify us of - promiscuous/multicast mode changes, and by the open/reset code to - initialize the Rx registers. We always set the multicast list and - leave the receiver running. - -======================================================================*/ - -static void set_rx_mode(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct smc_private *smc = netdev_priv(dev); - unsigned char multicast_table[8]; - unsigned long flags; - u_short rx_cfg_setting; - int i; - - memset(multicast_table, 0, sizeof(multicast_table)); - - if (dev->flags & IFF_PROMISC) { - rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti; - } else if (dev->flags & IFF_ALLMULTI) - rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti; - else { - if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, dev) { - u_int position = ether_crc(6, ha->addr); - multicast_table[position >> 29] |= 1 << ((position >> 26) & 7); - } - } - rx_cfg_setting = RxStripCRC | RxEnable; - } - - /* Load MC table and Rx setting into the chip without interrupts. */ - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - for (i = 0; i < 8; i++) - outb(multicast_table[i], ioaddr + MULTICAST0 + i); - SMC_SELECT_BANK(0); - outw(rx_cfg_setting, ioaddr + RCR); - SMC_SELECT_BANK(2); - spin_unlock_irqrestore(&smc->lock, flags); -} - -/*====================================================================== - - Senses when a card's config changes. Here, it's coax or TP. - -======================================================================*/ - -static int s9k_config(struct net_device *dev, struct ifmap *map) -{ - struct smc_private *smc = netdev_priv(dev); - if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - if (smc->cfg & CFG_MII_SELECT) - return -EOPNOTSUPP; - else if (map->port > 2) - return -EINVAL; - dev->if_port = map->port; - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - smc_reset(dev); - } - return 0; -} - -/*====================================================================== - - Reset the chip, reloading every register that might be corrupted. - -======================================================================*/ - -/* - Set transceiver type, perhaps to something other than what the user - specified in dev->if_port. -*/ -static void smc_set_xcvr(struct net_device *dev, int if_port) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short saved_bank; - - saved_bank = inw(ioaddr + BANK_SELECT); - SMC_SELECT_BANK(1); - if (if_port == 2) { - outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) - set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002); - } else { - outw(smc->cfg, ioaddr + CONFIG); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) - mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR); - smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001); - } - SMC_SELECT_BANK(saved_bank); -} - -static void smc_reset(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct smc_private *smc = netdev_priv(dev); - int i; - - pr_debug("%s: smc91c92 reset called.\n", dev->name); - - /* The first interaction must be a write to bring the chip out - of sleep mode. */ - SMC_SELECT_BANK(0); - /* Reset the chip. */ - outw(RCR_SOFTRESET, ioaddr + RCR); - udelay(10); - - /* Clear the transmit and receive configuration registers. */ - outw(RCR_CLEAR, ioaddr + RCR); - outw(TCR_CLEAR, ioaddr + TCR); - - /* Set the Window 1 control, configuration and station addr registers. - No point in writing the I/O base register ;-> */ - SMC_SELECT_BANK(1); - /* Automatically release successfully transmitted packets, - Accept link errors, counter and Tx error interrupts. */ - outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, - ioaddr + CONTROL); - smc_set_xcvr(dev, dev->if_port); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) - outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) | - (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00), - ioaddr - 0x10 + OSITECH_AUI_PWR); - - /* Fill in the physical address. The databook is wrong about the order! */ - for (i = 0; i < 6; i += 2) - outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i], - ioaddr + ADDR0 + i); - - /* Reset the MMU */ - SMC_SELECT_BANK(2); - outw(MC_RESET, ioaddr + MMU_CMD); - outw(0, ioaddr + INTERRUPT); - - /* Re-enable the chip. */ - SMC_SELECT_BANK(0); - outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) | - TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR); - set_rx_mode(dev); - - if (smc->cfg & CFG_MII_SELECT) { - SMC_SELECT_BANK(3); - - /* Reset MII */ - mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000); - - /* Advertise 100F, 100H, 10F, 10H */ - mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1); - - /* Restart MII autonegotiation */ - mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000); - mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200); - } - - /* Enable interrupts. */ - SMC_SELECT_BANK(2); - outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8, - ioaddr + INTERRUPT); -} - -/*====================================================================== - - Media selection timer routine - -======================================================================*/ - -static void media_check(u_long arg) -{ - struct net_device *dev = (struct net_device *) arg; - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u_short i, media, saved_bank; - u_short link; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - - saved_bank = inw(ioaddr + BANK_SELECT); - - if (!netif_device_present(dev)) - goto reschedule; - - SMC_SELECT_BANK(2); - - /* need MC_RESET to keep the memory consistent. errata? */ - if (smc->rx_ovrn) { - outw(MC_RESET, ioaddr + MMU_CMD); - smc->rx_ovrn = 0; - } - i = inw(ioaddr + INTERRUPT); - SMC_SELECT_BANK(0); - media = inw(ioaddr + EPH) & EPH_LINK_OK; - SMC_SELECT_BANK(1); - media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1; - - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - - /* Check for pending interrupt with watchdog flag set: with - this, we can limp along even if the interrupt is blocked */ - if (smc->watchdog++ && ((i>>8) & i)) { - if (!smc->fast_poll) - netdev_info(dev, "interrupt(s) dropped!\n"); - local_irq_save(flags); - smc_interrupt(dev->irq, dev); - local_irq_restore(flags); - smc->fast_poll = HZ; - } - if (smc->fast_poll) { - smc->fast_poll--; - smc->media.expires = jiffies + HZ/100; - add_timer(&smc->media); - return; - } - - spin_lock_irqsave(&smc->lock, flags); - - saved_bank = inw(ioaddr + BANK_SELECT); - - if (smc->cfg & CFG_MII_SELECT) { - if (smc->mii_if.phy_id < 0) - goto reschedule; - - SMC_SELECT_BANK(3); - link = mdio_read(dev, smc->mii_if.phy_id, 1); - if (!link || (link == 0xffff)) { - netdev_info(dev, "MII is missing!\n"); - smc->mii_if.phy_id = -1; - goto reschedule; - } - - link &= 0x0004; - if (link != smc->link_status) { - u_short p = mdio_read(dev, smc->mii_if.phy_id, 5); - netdev_info(dev, "%s link beat\n", link ? "found" : "lost"); - smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40)) - ? TCR_FDUPLX : 0); - if (link) { - netdev_info(dev, "autonegotiation complete: " - "%dbaseT-%cD selected\n", - (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H'); - } - SMC_SELECT_BANK(0); - outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR); - smc->link_status = link; - } - goto reschedule; - } - - /* Ignore collisions unless we've had no rx's recently */ - if (time_after(jiffies, dev->last_rx + HZ)) { - if (smc->tx_err || (smc->media_status & EPH_16COL)) - media |= EPH_16COL; - } - smc->tx_err = 0; - - if (media != smc->media_status) { - if ((media & smc->media_status & 1) && - ((smc->media_status ^ media) & EPH_LINK_OK)) - netdev_info(dev, "%s link beat\n", - smc->media_status & EPH_LINK_OK ? "lost" : "found"); - else if ((media & smc->media_status & 2) && - ((smc->media_status ^ media) & EPH_16COL)) - netdev_info(dev, "coax cable %s\n", - media & EPH_16COL ? "problem" : "ok"); - if (dev->if_port == 0) { - if (media & 1) { - if (media & EPH_LINK_OK) - netdev_info(dev, "flipped to 10baseT\n"); - else - smc_set_xcvr(dev, 2); - } else { - if (media & EPH_16COL) - smc_set_xcvr(dev, 1); - else - netdev_info(dev, "flipped to 10base2\n"); - } - } - smc->media_status = media; - } - -reschedule: - smc->media.expires = jiffies + HZ; - add_timer(&smc->media); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); -} - -static int smc_link_ok(struct net_device *dev) -{ - unsigned int ioaddr = dev->base_addr; - struct smc_private *smc = netdev_priv(dev); - - if (smc->cfg & CFG_MII_SELECT) { - return mii_link_ok(&smc->mii_if); - } else { - SMC_SELECT_BANK(0); - return inw(ioaddr + EPH) & EPH_LINK_OK; - } -} - -static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - u16 tmp; - unsigned int ioaddr = dev->base_addr; - - ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI | - SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full); - - SMC_SELECT_BANK(1); - tmp = inw(ioaddr + CONFIG); - ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP; - ecmd->transceiver = XCVR_INTERNAL; - ethtool_cmd_speed_set(ecmd, SPEED_10); - ecmd->phy_address = ioaddr + MGMT; - - SMC_SELECT_BANK(0); - tmp = inw(ioaddr + TCR); - ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF; - - return 0; -} - -static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - u16 tmp; - unsigned int ioaddr = dev->base_addr; - - if (ethtool_cmd_speed(ecmd) != SPEED_10) - return -EINVAL; - if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) - return -EINVAL; - if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI) - return -EINVAL; - if (ecmd->transceiver != XCVR_INTERNAL) - return -EINVAL; - - if (ecmd->port == PORT_AUI) - smc_set_xcvr(dev, 1); - else - smc_set_xcvr(dev, 0); - - SMC_SELECT_BANK(0); - tmp = inw(ioaddr + TCR); - if (ecmd->duplex == DUPLEX_FULL) - tmp |= TCR_FDUPLX; - else - tmp &= ~TCR_FDUPLX; - outw(tmp, ioaddr + TCR); - - return 0; -} - -static int check_if_running(struct net_device *dev) -{ - if (!netif_running(dev)) - return -EINVAL; - return 0; -} - -static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); -} - -static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - int ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - if (smc->cfg & CFG_MII_SELECT) - ret = mii_ethtool_gset(&smc->mii_if, ecmd); - else - ret = smc_netdev_get_ecmd(dev, ecmd); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - int ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - if (smc->cfg & CFG_MII_SELECT) - ret = mii_ethtool_sset(&smc->mii_if, ecmd); - else - ret = smc_netdev_set_ecmd(dev, ecmd); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static u32 smc_get_link(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - u32 ret; - unsigned long flags; - - spin_lock_irqsave(&smc->lock, flags); - SMC_SELECT_BANK(3); - ret = smc_link_ok(dev); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return ret; -} - -static int smc_nway_reset(struct net_device *dev) -{ - struct smc_private *smc = netdev_priv(dev); - if (smc->cfg & CFG_MII_SELECT) { - unsigned int ioaddr = dev->base_addr; - u16 saved_bank = inw(ioaddr + BANK_SELECT); - int res; - - SMC_SELECT_BANK(3); - res = mii_nway_restart(&smc->mii_if); - SMC_SELECT_BANK(saved_bank); - - return res; - } else - return -EOPNOTSUPP; -} - -static const struct ethtool_ops ethtool_ops = { - .begin = check_if_running, - .get_drvinfo = smc_get_drvinfo, - .get_settings = smc_get_settings, - .set_settings = smc_set_settings, - .get_link = smc_get_link, - .nway_reset = smc_nway_reset, -}; - -static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct smc_private *smc = netdev_priv(dev); - struct mii_ioctl_data *mii = if_mii(rq); - int rc = 0; - u16 saved_bank; - unsigned int ioaddr = dev->base_addr; - unsigned long flags; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irqsave(&smc->lock, flags); - saved_bank = inw(ioaddr + BANK_SELECT); - SMC_SELECT_BANK(3); - rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL); - SMC_SELECT_BANK(saved_bank); - spin_unlock_irqrestore(&smc->lock, flags); - return rc; -} - -static const struct pcmcia_device_id smc91c92_ids[] = { - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501), - PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9), - PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed), - PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020), - PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023), - PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc), - PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1), - PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5), - PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9), - PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953), - PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a), - PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314), - PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc), - PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9), - PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d), - /* These conflict with other cards! */ - /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */ - /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids); - -static struct pcmcia_driver smc91c92_cs_driver = { - .owner = THIS_MODULE, - .name = "smc91c92_cs", - .probe = smc91c92_probe, - .remove = smc91c92_detach, - .id_table = smc91c92_ids, - .suspend = smc91c92_suspend, - .resume = smc91c92_resume, -}; - -static int __init init_smc91c92_cs(void) -{ - return pcmcia_register_driver(&smc91c92_cs_driver); -} - -static void __exit exit_smc91c92_cs(void) -{ - pcmcia_unregister_driver(&smc91c92_cs_driver); -} - -module_init(init_smc91c92_cs); -module_exit(exit_smc91c92_cs); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.c deleted file mode 100644 index fee44935..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.c +++ /dev/null @@ -1,2419 +0,0 @@ -/* - * smc91x.c - * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. - * - * Copyright (C) 1996 by Erik Stahlman - * Copyright (C) 2001 Standard Microsystems Corporation - * Developed by Simple Network Magic Corporation - * Copyright (C) 2003 Monta Vista Software, Inc. - * Unified SMC91x driver by Nicolas Pitre - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Arguments: - * io = for the base address - * irq = for the IRQ - * nowait = 0 for normal wait states, 1 eliminates additional wait states - * - * original author: - * Erik Stahlman <erik@vt.edu> - * - * hardware multicast code: - * Peter Cammaert <pc@denkart.be> - * - * contributors: - * Daris A Nevil <dnevil@snmc.com> - * Nicolas Pitre <nico@fluxnic.net> - * Russell King <rmk@arm.linux.org.uk> - * - * History: - * 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet - * 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" - * 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 - * 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 - * 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 - * 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support - * 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, - * more bus abstraction, big cleanup, etc. - * 29/09/03 Russell King - add driver model support - * - ethtool support - * - convert to use generic MII interface - * - add link up/down notification - * - don't try to handle full negotiation in - * smc_phy_configure - * - clean up (and fix stack overrun) in PHY - * MII read/write functions - * 22/09/04 Nicolas Pitre big update (see commit log for details) - */ -static const char version[] = - "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@fluxnic.net>\n"; - -/* Debugging level */ -#ifndef SMC_DEBUG -#define SMC_DEBUG 0 -#endif - - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/crc32.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/workqueue.h> -#include <linux/of.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include <asm/io.h> - -#include "smc91x.h" - -#ifndef SMC_NOWAIT -# define SMC_NOWAIT 0 -#endif -static int nowait = SMC_NOWAIT; -module_param(nowait, int, 0400); -MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); - -/* - * Transmit timeout, default 5 seconds. - */ -static int watchdog = 1000; -module_param(watchdog, int, 0400); -MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:smc91x"); - -/* - * The internal workings of the driver. If you are changing anything - * here with the SMC stuff, you should have the datasheet and know - * what you are doing. - */ -#define CARDNAME "smc91x" - -/* - * Use power-down feature of the chip - */ -#define POWER_DOWN 1 - -/* - * Wait time for memory to be free. This probably shouldn't be - * tuned that much, as waiting for this means nothing else happens - * in the system - */ -#define MEMORY_WAIT_TIME 16 - -/* - * The maximum number of processing loops allowed for each call to the - * IRQ handler. - */ -#define MAX_IRQ_LOOPS 8 - -/* - * This selects whether TX packets are sent one by one to the SMC91x internal - * memory and throttled until transmission completes. This may prevent - * RX overruns a litle by keeping much of the memory free for RX packets - * but to the expense of reduced TX throughput and increased IRQ overhead. - * Note this is not a cure for a too slow data bus or too high IRQ latency. - */ -#define THROTTLE_TX_PKTS 0 - -/* - * The MII clock high/low times. 2x this number gives the MII clock period - * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!) - */ -#define MII_DELAY 1 - -#if SMC_DEBUG > 0 -#define DBG(n, args...) \ - do { \ - if (SMC_DEBUG >= (n)) \ - printk(args); \ - } while (0) - -#define PRINTK(args...) printk(args) -#else -#define DBG(n, args...) do { } while(0) -#define PRINTK(args...) printk(KERN_DEBUG args) -#endif - -#if SMC_DEBUG > 3 -static void PRINT_PKT(u_char *buf, int length) -{ - int i; - int remainder; - int lines; - - lines = length / 16; - remainder = length % 16; - - for (i = 0; i < lines ; i ++) { - int cur; - for (cur = 0; cur < 8; cur++) { - u_char a, b; - a = *buf++; - b = *buf++; - printk("%02x%02x ", a, b); - } - printk("\n"); - } - for (i = 0; i < remainder/2 ; i++) { - u_char a, b; - a = *buf++; - b = *buf++; - printk("%02x%02x ", a, b); - } - printk("\n"); -} -#else -#define PRINT_PKT(x...) do { } while(0) -#endif - - -/* this enables an interrupt in the interrupt mask register */ -#define SMC_ENABLE_INT(lp, x) do { \ - unsigned char mask; \ - unsigned long smc_enable_flags; \ - spin_lock_irqsave(&lp->lock, smc_enable_flags); \ - mask = SMC_GET_INT_MASK(lp); \ - mask |= (x); \ - SMC_SET_INT_MASK(lp, mask); \ - spin_unlock_irqrestore(&lp->lock, smc_enable_flags); \ -} while (0) - -/* this disables an interrupt from the interrupt mask register */ -#define SMC_DISABLE_INT(lp, x) do { \ - unsigned char mask; \ - unsigned long smc_disable_flags; \ - spin_lock_irqsave(&lp->lock, smc_disable_flags); \ - mask = SMC_GET_INT_MASK(lp); \ - mask &= ~(x); \ - SMC_SET_INT_MASK(lp, mask); \ - spin_unlock_irqrestore(&lp->lock, smc_disable_flags); \ -} while (0) - -/* - * Wait while MMU is busy. This is usually in the order of a few nanosecs - * if at all, but let's avoid deadlocking the system if the hardware - * decides to go south. - */ -#define SMC_WAIT_MMU_BUSY(lp) do { \ - if (unlikely(SMC_GET_MMU_CMD(lp) & MC_BUSY)) { \ - unsigned long timeout = jiffies + 2; \ - while (SMC_GET_MMU_CMD(lp) & MC_BUSY) { \ - if (time_after(jiffies, timeout)) { \ - printk("%s: timeout %s line %d\n", \ - dev->name, __FILE__, __LINE__); \ - break; \ - } \ - cpu_relax(); \ - } \ - } \ -} while (0) - - -/* - * this does a soft reset on the device - */ -static void smc_reset(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int ctl, cfg; - struct sk_buff *pending_skb; - - DBG(2, "%s: %s\n", dev->name, __func__); - - /* Disable all interrupts, block TX tasklet */ - spin_lock_irq(&lp->lock); - SMC_SELECT_BANK(lp, 2); - SMC_SET_INT_MASK(lp, 0); - pending_skb = lp->pending_tx_skb; - lp->pending_tx_skb = NULL; - spin_unlock_irq(&lp->lock); - - /* free any pending tx skb */ - if (pending_skb) { - dev_kfree_skb(pending_skb); - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - } - - /* - * This resets the registers mostly to defaults, but doesn't - * affect EEPROM. That seems unnecessary - */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_RCR(lp, RCR_SOFTRST); - - /* - * Setup the Configuration Register - * This is necessary because the CONFIG_REG is not affected - * by a soft reset - */ - SMC_SELECT_BANK(lp, 1); - - cfg = CONFIG_DEFAULT; - - /* - * Setup for fast accesses if requested. If the card/system - * can't handle it then there will be no recovery except for - * a hard reset or power cycle - */ - if (lp->cfg.flags & SMC91X_NOWAIT) - cfg |= CONFIG_NO_WAIT; - - /* - * Release from possible power-down state - * Configuration register is not affected by Soft Reset - */ - cfg |= CONFIG_EPH_POWER_EN; - - SMC_SET_CONFIG(lp, cfg); - - /* this should pause enough for the chip to be happy */ - /* - * elaborate? What does the chip _need_? --jgarzik - * - * This seems to be undocumented, but something the original - * driver(s) have always done. Suspect undocumented timing - * info/determined empirically. --rmk - */ - udelay(1); - - /* Disable transmit and receive functionality */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_RCR(lp, RCR_CLEAR); - SMC_SET_TCR(lp, TCR_CLEAR); - - SMC_SELECT_BANK(lp, 1); - ctl = SMC_GET_CTL(lp) | CTL_LE_ENABLE; - - /* - * Set the control register to automatically release successfully - * transmitted packets, to make the best use out of our limited - * memory - */ - if(!THROTTLE_TX_PKTS) - ctl |= CTL_AUTO_RELEASE; - else - ctl &= ~CTL_AUTO_RELEASE; - SMC_SET_CTL(lp, ctl); - - /* Reset the MMU */ - SMC_SELECT_BANK(lp, 2); - SMC_SET_MMU_CMD(lp, MC_RESET); - SMC_WAIT_MMU_BUSY(lp); -} - -/* - * Enable Interrupts, Receive, and Transmit - */ -static void smc_enable(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - int mask; - - DBG(2, "%s: %s\n", dev->name, __func__); - - /* see the header file for options in TCR/RCR DEFAULT */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_TCR(lp, lp->tcr_cur_mode); - SMC_SET_RCR(lp, lp->rcr_cur_mode); - - SMC_SELECT_BANK(lp, 1); - SMC_SET_MAC_ADDR(lp, dev->dev_addr); - - /* now, enable interrupts */ - mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; - if (lp->version >= (CHIP_91100 << 4)) - mask |= IM_MDINT; - SMC_SELECT_BANK(lp, 2); - SMC_SET_INT_MASK(lp, mask); - - /* - * From this point the register bank must _NOT_ be switched away - * to something else than bank 2 without proper locking against - * races with any tasklet or interrupt handlers until smc_shutdown() - * or smc_reset() is called. - */ -} - -/* - * this puts the device in an inactive state - */ -static void smc_shutdown(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - struct sk_buff *pending_skb; - - DBG(2, "%s: %s\n", CARDNAME, __func__); - - /* no more interrupts for me */ - spin_lock_irq(&lp->lock); - SMC_SELECT_BANK(lp, 2); - SMC_SET_INT_MASK(lp, 0); - pending_skb = lp->pending_tx_skb; - lp->pending_tx_skb = NULL; - spin_unlock_irq(&lp->lock); - if (pending_skb) - dev_kfree_skb(pending_skb); - - /* and tell the card to stay away from that nasty outside world */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_RCR(lp, RCR_CLEAR); - SMC_SET_TCR(lp, TCR_CLEAR); - -#ifdef POWER_DOWN - /* finally, shut the chip down */ - SMC_SELECT_BANK(lp, 1); - SMC_SET_CONFIG(lp, SMC_GET_CONFIG(lp) & ~CONFIG_EPH_POWER_EN); -#endif -} - -/* - * This is the procedure to handle the receipt of a packet. - */ -static inline void smc_rcv(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int packet_number, status, packet_len; - - DBG(3, "%s: %s\n", dev->name, __func__); - - packet_number = SMC_GET_RXFIFO(lp); - if (unlikely(packet_number & RXFIFO_REMPTY)) { - PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); - return; - } - - /* read from start of packet */ - SMC_SET_PTR(lp, PTR_READ | PTR_RCV | PTR_AUTOINC); - - /* First two words are status and packet length */ - SMC_GET_PKT_HDR(lp, status, packet_len); - packet_len &= 0x07ff; /* mask off top bits */ - DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", - dev->name, packet_number, status, - packet_len, packet_len); - - back: - if (unlikely(packet_len < 6 || status & RS_ERRORS)) { - if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) { - /* accept VLAN packets */ - status &= ~RS_TOOLONG; - goto back; - } - if (packet_len < 6) { - /* bloody hardware */ - printk(KERN_ERR "%s: fubar (rxlen %u status %x\n", - dev->name, packet_len, status); - status |= RS_TOOSHORT; - } - SMC_WAIT_MMU_BUSY(lp); - SMC_SET_MMU_CMD(lp, MC_RELEASE); - dev->stats.rx_errors++; - if (status & RS_ALGNERR) - dev->stats.rx_frame_errors++; - if (status & (RS_TOOSHORT | RS_TOOLONG)) - dev->stats.rx_length_errors++; - if (status & RS_BADCRC) - dev->stats.rx_crc_errors++; - } else { - struct sk_buff *skb; - unsigned char *data; - unsigned int data_len; - - /* set multicast stats */ - if (status & RS_MULTICAST) - dev->stats.multicast++; - - /* - * Actual payload is packet_len - 6 (or 5 if odd byte). - * We want skb_reserve(2) and the final ctrl word - * (2 bytes, possibly containing the payload odd byte). - * Furthermore, we add 2 bytes to allow rounding up to - * multiple of 4 bytes on 32 bit buses. - * Hence packet_len - 6 + 2 + 2 + 2. - */ - skb = netdev_alloc_skb(dev, packet_len); - if (unlikely(skb == NULL)) { - printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", - dev->name); - SMC_WAIT_MMU_BUSY(lp); - SMC_SET_MMU_CMD(lp, MC_RELEASE); - dev->stats.rx_dropped++; - return; - } - - /* Align IP header to 32 bits */ - skb_reserve(skb, 2); - - /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ - if (lp->version == 0x90) - status |= RS_ODDFRAME; - - /* - * If odd length: packet_len - 5, - * otherwise packet_len - 6. - * With the trailing ctrl byte it's packet_len - 4. - */ - data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6); - data = skb_put(skb, data_len); - SMC_PULL_DATA(lp, data, packet_len - 4); - - SMC_WAIT_MMU_BUSY(lp); - SMC_SET_MMU_CMD(lp, MC_RELEASE); - - PRINT_PKT(data, packet_len - 4); - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += data_len; - } -} - -#ifdef CONFIG_SMP -/* - * On SMP we have the following problem: - * - * A = smc_hardware_send_pkt() - * B = smc_hard_start_xmit() - * C = smc_interrupt() - * - * A and B can never be executed simultaneously. However, at least on UP, - * it is possible (and even desirable) for C to interrupt execution of - * A or B in order to have better RX reliability and avoid overruns. - * C, just like A and B, must have exclusive access to the chip and - * each of them must lock against any other concurrent access. - * Unfortunately this is not possible to have C suspend execution of A or - * B taking place on another CPU. On UP this is no an issue since A and B - * are run from softirq context and C from hard IRQ context, and there is - * no other CPU where concurrent access can happen. - * If ever there is a way to force at least B and C to always be executed - * on the same CPU then we could use read/write locks to protect against - * any other concurrent access and C would always interrupt B. But life - * isn't that easy in a SMP world... - */ -#define smc_special_trylock(lock, flags) \ -({ \ - int __ret; \ - local_irq_save(flags); \ - __ret = spin_trylock(lock); \ - if (!__ret) \ - local_irq_restore(flags); \ - __ret; \ -}) -#define smc_special_lock(lock, flags) spin_lock_irqsave(lock, flags) -#define smc_special_unlock(lock, flags) spin_unlock_irqrestore(lock, flags) -#else -#define smc_special_trylock(lock, flags) (flags == flags) -#define smc_special_lock(lock, flags) do { flags = 0; } while (0) -#define smc_special_unlock(lock, flags) do { flags = 0; } while (0) -#endif - -/* - * This is called to actually send a packet to the chip. - */ -static void smc_hardware_send_pkt(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - struct sk_buff *skb; - unsigned int packet_no, len; - unsigned char *buf; - unsigned long flags; - - DBG(3, "%s: %s\n", dev->name, __func__); - - if (!smc_special_trylock(&lp->lock, flags)) { - netif_stop_queue(dev); - tasklet_schedule(&lp->tx_task); - return; - } - - skb = lp->pending_tx_skb; - if (unlikely(!skb)) { - smc_special_unlock(&lp->lock, flags); - return; - } - lp->pending_tx_skb = NULL; - - packet_no = SMC_GET_AR(lp); - if (unlikely(packet_no & AR_FAILED)) { - printk("%s: Memory allocation failed.\n", dev->name); - dev->stats.tx_errors++; - dev->stats.tx_fifo_errors++; - smc_special_unlock(&lp->lock, flags); - goto done; - } - - /* point to the beginning of the packet */ - SMC_SET_PN(lp, packet_no); - SMC_SET_PTR(lp, PTR_AUTOINC); - - buf = skb->data; - len = skb->len; - DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n", - dev->name, packet_no, len, len, buf); - PRINT_PKT(buf, len); - - /* - * Send the packet length (+6 for status words, length, and ctl. - * The card will pad to 64 bytes with zeroes if packet is too small. - */ - SMC_PUT_PKT_HDR(lp, 0, len + 6); - - /* send the actual data */ - SMC_PUSH_DATA(lp, buf, len & ~1); - - /* Send final ctl word with the last byte if there is one */ - SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG(lp)); - - /* - * If THROTTLE_TX_PKTS is set, we stop the queue here. This will - * have the effect of having at most one packet queued for TX - * in the chip's memory at all time. - * - * If THROTTLE_TX_PKTS is not set then the queue is stopped only - * when memory allocation (MC_ALLOC) does not succeed right away. - */ - if (THROTTLE_TX_PKTS) - netif_stop_queue(dev); - - /* queue the packet for TX */ - SMC_SET_MMU_CMD(lp, MC_ENQUEUE); - smc_special_unlock(&lp->lock, flags); - - dev->trans_start = jiffies; - dev->stats.tx_packets++; - dev->stats.tx_bytes += len; - - SMC_ENABLE_INT(lp, IM_TX_INT | IM_TX_EMPTY_INT); - -done: if (!THROTTLE_TX_PKTS) - netif_wake_queue(dev); - - dev_kfree_skb(skb); -} - -/* - * Since I am not sure if I will have enough room in the chip's ram - * to store the packet, I call this routine which either sends it - * now, or set the card to generates an interrupt when ready - * for the packet. - */ -static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int numPages, poll_count, status; - unsigned long flags; - - DBG(3, "%s: %s\n", dev->name, __func__); - - BUG_ON(lp->pending_tx_skb != NULL); - - /* - * The MMU wants the number of pages to be the number of 256 bytes - * 'pages', minus 1 (since a packet can't ever have 0 pages :)) - * - * The 91C111 ignores the size bits, but earlier models don't. - * - * Pkt size for allocating is data length +6 (for additional status - * words, length and ctl) - * - * If odd size then last byte is included in ctl word. - */ - numPages = ((skb->len & ~1) + (6 - 1)) >> 8; - if (unlikely(numPages > 7)) { - printk("%s: Far too big packet error.\n", dev->name); - dev->stats.tx_errors++; - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - smc_special_lock(&lp->lock, flags); - - /* now, try to allocate the memory */ - SMC_SET_MMU_CMD(lp, MC_ALLOC | numPages); - - /* - * Poll the chip for a short amount of time in case the - * allocation succeeds quickly. - */ - poll_count = MEMORY_WAIT_TIME; - do { - status = SMC_GET_INT(lp); - if (status & IM_ALLOC_INT) { - SMC_ACK_INT(lp, IM_ALLOC_INT); - break; - } - } while (--poll_count); - - smc_special_unlock(&lp->lock, flags); - - lp->pending_tx_skb = skb; - if (!poll_count) { - /* oh well, wait until the chip finds memory later */ - netif_stop_queue(dev); - DBG(2, "%s: TX memory allocation deferred.\n", dev->name); - SMC_ENABLE_INT(lp, IM_ALLOC_INT); - } else { - /* - * Allocation succeeded: push packet to the chip's own memory - * immediately. - */ - smc_hardware_send_pkt((unsigned long)dev); - } - - return NETDEV_TX_OK; -} - -/* - * This handles a TX interrupt, which is only called when: - * - a TX error occurred, or - * - CTL_AUTO_RELEASE is not set and TX of a packet completed. - */ -static void smc_tx(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int saved_packet, packet_no, tx_status, pkt_len; - - DBG(3, "%s: %s\n", dev->name, __func__); - - /* If the TX FIFO is empty then nothing to do */ - packet_no = SMC_GET_TXFIFO(lp); - if (unlikely(packet_no & TXFIFO_TEMPTY)) { - PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); - return; - } - - /* select packet to read from */ - saved_packet = SMC_GET_PN(lp); - SMC_SET_PN(lp, packet_no); - - /* read the first word (status word) from this packet */ - SMC_SET_PTR(lp, PTR_AUTOINC | PTR_READ); - SMC_GET_PKT_HDR(lp, tx_status, pkt_len); - DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n", - dev->name, tx_status, packet_no); - - if (!(tx_status & ES_TX_SUC)) - dev->stats.tx_errors++; - - if (tx_status & ES_LOSTCARR) - dev->stats.tx_carrier_errors++; - - if (tx_status & (ES_LATCOL | ES_16COL)) { - PRINTK("%s: %s occurred on last xmit\n", dev->name, - (tx_status & ES_LATCOL) ? - "late collision" : "too many collisions"); - dev->stats.tx_window_errors++; - if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) { - printk(KERN_INFO "%s: unexpectedly large number of " - "bad collisions. Please check duplex " - "setting.\n", dev->name); - } - } - - /* kill the packet */ - SMC_WAIT_MMU_BUSY(lp); - SMC_SET_MMU_CMD(lp, MC_FREEPKT); - - /* Don't restore Packet Number Reg until busy bit is cleared */ - SMC_WAIT_MMU_BUSY(lp); - SMC_SET_PN(lp, saved_packet); - - /* re-enable transmit */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_TCR(lp, lp->tcr_cur_mode); - SMC_SELECT_BANK(lp, 2); -} - - -/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ - -static void smc_mii_out(struct net_device *dev, unsigned int val, int bits) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int mii_reg, mask; - - mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO); - mii_reg |= MII_MDOE; - - for (mask = 1 << (bits - 1); mask; mask >>= 1) { - if (val & mask) - mii_reg |= MII_MDO; - else - mii_reg &= ~MII_MDO; - - SMC_SET_MII(lp, mii_reg); - udelay(MII_DELAY); - SMC_SET_MII(lp, mii_reg | MII_MCLK); - udelay(MII_DELAY); - } -} - -static unsigned int smc_mii_in(struct net_device *dev, int bits) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int mii_reg, mask, val; - - mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO); - SMC_SET_MII(lp, mii_reg); - - for (mask = 1 << (bits - 1), val = 0; mask; mask >>= 1) { - if (SMC_GET_MII(lp) & MII_MDI) - val |= mask; - - SMC_SET_MII(lp, mii_reg); - udelay(MII_DELAY); - SMC_SET_MII(lp, mii_reg | MII_MCLK); - udelay(MII_DELAY); - } - - return val; -} - -/* - * Reads a register from the MII Management serial interface - */ -static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int phydata; - - SMC_SELECT_BANK(lp, 3); - - /* Idle - 32 ones */ - smc_mii_out(dev, 0xffffffff, 32); - - /* Start code (01) + read (10) + phyaddr + phyreg */ - smc_mii_out(dev, 6 << 10 | phyaddr << 5 | phyreg, 14); - - /* Turnaround (2bits) + phydata */ - phydata = smc_mii_in(dev, 18); - - /* Return to idle state */ - SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO)); - - DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __func__, phyaddr, phyreg, phydata); - - SMC_SELECT_BANK(lp, 2); - return phydata; -} - -/* - * Writes a register to the MII Management serial interface - */ -static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, - int phydata) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - - SMC_SELECT_BANK(lp, 3); - - /* Idle - 32 ones */ - smc_mii_out(dev, 0xffffffff, 32); - - /* Start code (01) + write (01) + phyaddr + phyreg + turnaround + phydata */ - smc_mii_out(dev, 5 << 28 | phyaddr << 23 | phyreg << 18 | 2 << 16 | phydata, 32); - - /* Return to idle state */ - SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO)); - - DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", - __func__, phyaddr, phyreg, phydata); - - SMC_SELECT_BANK(lp, 2); -} - -/* - * Finds and reports the PHY address - */ -static void smc_phy_detect(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - int phyaddr; - - DBG(2, "%s: %s\n", dev->name, __func__); - - lp->phy_type = 0; - - /* - * Scan all 32 PHY addresses if necessary, starting at - * PHY#1 to PHY#31, and then PHY#0 last. - */ - for (phyaddr = 1; phyaddr < 33; ++phyaddr) { - unsigned int id1, id2; - - /* Read the PHY identifiers */ - id1 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID1); - id2 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID2); - - DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n", - dev->name, id1, id2); - - /* Make sure it is a valid identifier */ - if (id1 != 0x0000 && id1 != 0xffff && id1 != 0x8000 && - id2 != 0x0000 && id2 != 0xffff && id2 != 0x8000) { - /* Save the PHY's address */ - lp->mii.phy_id = phyaddr & 31; - lp->phy_type = id1 << 16 | id2; - break; - } - } -} - -/* - * Sets the PHY to a configuration as determined by the user - */ -static int smc_phy_fixed(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - int phyaddr = lp->mii.phy_id; - int bmcr, cfg1; - - DBG(3, "%s: %s\n", dev->name, __func__); - - /* Enter Link Disable state */ - cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG); - cfg1 |= PHY_CFG1_LNKDIS; - smc_phy_write(dev, phyaddr, PHY_CFG1_REG, cfg1); - - /* - * Set our fixed capabilities - * Disable auto-negotiation - */ - bmcr = 0; - - if (lp->ctl_rfduplx) - bmcr |= BMCR_FULLDPLX; - - if (lp->ctl_rspeed == 100) - bmcr |= BMCR_SPEED100; - - /* Write our capabilities to the phy control register */ - smc_phy_write(dev, phyaddr, MII_BMCR, bmcr); - - /* Re-Configure the Receive/Phy Control register */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_RPC(lp, lp->rpc_cur_mode); - SMC_SELECT_BANK(lp, 2); - - return 1; -} - -/* - * smc_phy_reset - reset the phy - * @dev: net device - * @phy: phy address - * - * Issue a software reset for the specified PHY and - * wait up to 100ms for the reset to complete. We should - * not access the PHY for 50ms after issuing the reset. - * - * The time to wait appears to be dependent on the PHY. - * - * Must be called with lp->lock locked. - */ -static int smc_phy_reset(struct net_device *dev, int phy) -{ - struct smc_local *lp = netdev_priv(dev); - unsigned int bmcr; - int timeout; - - smc_phy_write(dev, phy, MII_BMCR, BMCR_RESET); - - for (timeout = 2; timeout; timeout--) { - spin_unlock_irq(&lp->lock); - msleep(50); - spin_lock_irq(&lp->lock); - - bmcr = smc_phy_read(dev, phy, MII_BMCR); - if (!(bmcr & BMCR_RESET)) - break; - } - - return bmcr & BMCR_RESET; -} - -/* - * smc_phy_powerdown - powerdown phy - * @dev: net device - * - * Power down the specified PHY - */ -static void smc_phy_powerdown(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - unsigned int bmcr; - int phy = lp->mii.phy_id; - - if (lp->phy_type == 0) - return; - - /* We need to ensure that no calls to smc_phy_configure are - pending. - */ - cancel_work_sync(&lp->phy_configure); - - bmcr = smc_phy_read(dev, phy, MII_BMCR); - smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); -} - -/* - * smc_phy_check_media - check the media status and adjust TCR - * @dev: net device - * @init: set true for initialisation - * - * Select duplex mode depending on negotiation state. This - * also updates our carrier state. - */ -static void smc_phy_check_media(struct net_device *dev, int init) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - - if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { - /* duplex state has changed */ - if (lp->mii.full_duplex) { - lp->tcr_cur_mode |= TCR_SWFDUP; - } else { - lp->tcr_cur_mode &= ~TCR_SWFDUP; - } - - SMC_SELECT_BANK(lp, 0); - SMC_SET_TCR(lp, lp->tcr_cur_mode); - } -} - -/* - * Configures the specified PHY through the MII management interface - * using Autonegotiation. - * Calls smc_phy_fixed() if the user has requested a certain config. - * If RPC ANEG bit is set, the media selection is dependent purely on - * the selection by the MII (either in the MII BMCR reg or the result - * of autonegotiation.) If the RPC ANEG bit is cleared, the selection - * is controlled by the RPC SPEED and RPC DPLX bits. - */ -static void smc_phy_configure(struct work_struct *work) -{ - struct smc_local *lp = - container_of(work, struct smc_local, phy_configure); - struct net_device *dev = lp->dev; - void __iomem *ioaddr = lp->base; - int phyaddr = lp->mii.phy_id; - int my_phy_caps; /* My PHY capabilities */ - int my_ad_caps; /* My Advertised capabilities */ - int status; - - DBG(3, "%s:smc_program_phy()\n", dev->name); - - spin_lock_irq(&lp->lock); - - /* - * We should not be called if phy_type is zero. - */ - if (lp->phy_type == 0) - goto smc_phy_configure_exit; - - if (smc_phy_reset(dev, phyaddr)) { - printk("%s: PHY reset timed out\n", dev->name); - goto smc_phy_configure_exit; - } - - /* - * Enable PHY Interrupts (for register 18) - * Interrupts listed here are disabled - */ - smc_phy_write(dev, phyaddr, PHY_MASK_REG, - PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | - PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | - PHY_INT_SPDDET | PHY_INT_DPLXDET); - - /* Configure the Receive/Phy Control register */ - SMC_SELECT_BANK(lp, 0); - SMC_SET_RPC(lp, lp->rpc_cur_mode); - - /* If the user requested no auto neg, then go set his request */ - if (lp->mii.force_media) { - smc_phy_fixed(dev); - goto smc_phy_configure_exit; - } - - /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ - my_phy_caps = smc_phy_read(dev, phyaddr, MII_BMSR); - - if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { - printk(KERN_INFO "Auto negotiation NOT supported\n"); - smc_phy_fixed(dev); - goto smc_phy_configure_exit; - } - - my_ad_caps = ADVERTISE_CSMA; /* I am CSMA capable */ - - if (my_phy_caps & BMSR_100BASE4) - my_ad_caps |= ADVERTISE_100BASE4; - if (my_phy_caps & BMSR_100FULL) - my_ad_caps |= ADVERTISE_100FULL; - if (my_phy_caps & BMSR_100HALF) - my_ad_caps |= ADVERTISE_100HALF; - if (my_phy_caps & BMSR_10FULL) - my_ad_caps |= ADVERTISE_10FULL; - if (my_phy_caps & BMSR_10HALF) - my_ad_caps |= ADVERTISE_10HALF; - - /* Disable capabilities not selected by our user */ - if (lp->ctl_rspeed != 100) - my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); - - if (!lp->ctl_rfduplx) - my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); - - /* Update our Auto-Neg Advertisement Register */ - smc_phy_write(dev, phyaddr, MII_ADVERTISE, my_ad_caps); - lp->mii.advertising = my_ad_caps; - - /* - * Read the register back. Without this, it appears that when - * auto-negotiation is restarted, sometimes it isn't ready and - * the link does not come up. - */ - status = smc_phy_read(dev, phyaddr, MII_ADVERTISE); - - DBG(2, "%s: phy caps=%x\n", dev->name, my_phy_caps); - DBG(2, "%s: phy advertised caps=%x\n", dev->name, my_ad_caps); - - /* Restart auto-negotiation process in order to advertise my caps */ - smc_phy_write(dev, phyaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); - - smc_phy_check_media(dev, 1); - -smc_phy_configure_exit: - SMC_SELECT_BANK(lp, 2); - spin_unlock_irq(&lp->lock); -} - -/* - * smc_phy_interrupt - * - * Purpose: Handle interrupts relating to PHY register 18. This is - * called from the "hard" interrupt handler under our private spinlock. - */ -static void smc_phy_interrupt(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - int phyaddr = lp->mii.phy_id; - int phy18; - - DBG(2, "%s: %s\n", dev->name, __func__); - - if (lp->phy_type == 0) - return; - - for(;;) { - smc_phy_check_media(dev, 0); - - /* Read PHY Register 18, Status Output */ - phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG); - if ((phy18 & PHY_INT_INT) == 0) - break; - } -} - -/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ - -static void smc_10bt_check_media(struct net_device *dev, int init) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int old_carrier, new_carrier; - - old_carrier = netif_carrier_ok(dev) ? 1 : 0; - - SMC_SELECT_BANK(lp, 0); - new_carrier = (SMC_GET_EPH_STATUS(lp) & ES_LINK_OK) ? 1 : 0; - SMC_SELECT_BANK(lp, 2); - - if (init || (old_carrier != new_carrier)) { - if (!new_carrier) { - netif_carrier_off(dev); - } else { - netif_carrier_on(dev); - } - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: link %s\n", dev->name, - new_carrier ? "up" : "down"); - } -} - -static void smc_eph_interrupt(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned int ctl; - - smc_10bt_check_media(dev, 0); - - SMC_SELECT_BANK(lp, 1); - ctl = SMC_GET_CTL(lp); - SMC_SET_CTL(lp, ctl & ~CTL_LE_ENABLE); - SMC_SET_CTL(lp, ctl); - SMC_SELECT_BANK(lp, 2); -} - -/* - * This is the main routine of the driver, to handle the device when - * it needs some attention. - */ -static irqreturn_t smc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - int status, mask, timeout, card_stats; - int saved_pointer; - - DBG(3, "%s: %s\n", dev->name, __func__); - - spin_lock(&lp->lock); - - /* A preamble may be used when there is a potential race - * between the interruptible transmit functions and this - * ISR. */ - SMC_INTERRUPT_PREAMBLE; - - saved_pointer = SMC_GET_PTR(lp); - mask = SMC_GET_INT_MASK(lp); - SMC_SET_INT_MASK(lp, 0); - - /* set a timeout value, so I don't stay here forever */ - timeout = MAX_IRQ_LOOPS; - - do { - status = SMC_GET_INT(lp); - - DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", - dev->name, status, mask, - ({ int meminfo; SMC_SELECT_BANK(lp, 0); - meminfo = SMC_GET_MIR(lp); - SMC_SELECT_BANK(lp, 2); meminfo; }), - SMC_GET_FIFO(lp)); - - status &= mask; - if (!status) - break; - - if (status & IM_TX_INT) { - /* do this before RX as it will free memory quickly */ - DBG(3, "%s: TX int\n", dev->name); - smc_tx(dev); - SMC_ACK_INT(lp, IM_TX_INT); - if (THROTTLE_TX_PKTS) - netif_wake_queue(dev); - } else if (status & IM_RCV_INT) { - DBG(3, "%s: RX irq\n", dev->name); - smc_rcv(dev); - } else if (status & IM_ALLOC_INT) { - DBG(3, "%s: Allocation irq\n", dev->name); - tasklet_hi_schedule(&lp->tx_task); - mask &= ~IM_ALLOC_INT; - } else if (status & IM_TX_EMPTY_INT) { - DBG(3, "%s: TX empty\n", dev->name); - mask &= ~IM_TX_EMPTY_INT; - - /* update stats */ - SMC_SELECT_BANK(lp, 0); - card_stats = SMC_GET_COUNTER(lp); - SMC_SELECT_BANK(lp, 2); - - /* single collisions */ - dev->stats.collisions += card_stats & 0xF; - card_stats >>= 4; - - /* multiple collisions */ - dev->stats.collisions += card_stats & 0xF; - } else if (status & IM_RX_OVRN_INT) { - DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name, - ({ int eph_st; SMC_SELECT_BANK(lp, 0); - eph_st = SMC_GET_EPH_STATUS(lp); - SMC_SELECT_BANK(lp, 2); eph_st; })); - SMC_ACK_INT(lp, IM_RX_OVRN_INT); - dev->stats.rx_errors++; - dev->stats.rx_fifo_errors++; - } else if (status & IM_EPH_INT) { - smc_eph_interrupt(dev); - } else if (status & IM_MDINT) { - SMC_ACK_INT(lp, IM_MDINT); - smc_phy_interrupt(dev); - } else if (status & IM_ERCV_INT) { - SMC_ACK_INT(lp, IM_ERCV_INT); - PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT\n", dev->name); - } - } while (--timeout); - - /* restore register states */ - SMC_SET_PTR(lp, saved_pointer); - SMC_SET_INT_MASK(lp, mask); - spin_unlock(&lp->lock); - -#ifndef CONFIG_NET_POLL_CONTROLLER - if (timeout == MAX_IRQ_LOOPS) - PRINTK("%s: spurious interrupt (mask = 0x%02x)\n", - dev->name, mask); -#endif - DBG(3, "%s: Interrupt done (%d loops)\n", - dev->name, MAX_IRQ_LOOPS - timeout); - - /* - * We return IRQ_HANDLED unconditionally here even if there was - * nothing to do. There is a possibility that a packet might - * get enqueued into the chip right after TX_EMPTY_INT is raised - * but just before the CPU acknowledges the IRQ. - * Better take an unneeded IRQ in some occasions than complexifying - * the code for all cases. - */ - return IRQ_HANDLED; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling receive - used by netconsole and other diagnostic tools - * to allow network i/o with interrupts disabled. - */ -static void smc_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - smc_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -/* Our watchdog timed out. Called by the networking layer */ -static void smc_timeout(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - int status, mask, eph_st, meminfo, fifo; - - DBG(2, "%s: %s\n", dev->name, __func__); - - spin_lock_irq(&lp->lock); - status = SMC_GET_INT(lp); - mask = SMC_GET_INT_MASK(lp); - fifo = SMC_GET_FIFO(lp); - SMC_SELECT_BANK(lp, 0); - eph_st = SMC_GET_EPH_STATUS(lp); - meminfo = SMC_GET_MIR(lp); - SMC_SELECT_BANK(lp, 2); - spin_unlock_irq(&lp->lock); - PRINTK( "%s: TX timeout (INT 0x%02x INTMASK 0x%02x " - "MEM 0x%04x FIFO 0x%04x EPH_ST 0x%04x)\n", - dev->name, status, mask, meminfo, fifo, eph_st ); - - smc_reset(dev); - smc_enable(dev); - - /* - * Reconfiguring the PHY doesn't seem like a bad idea here, but - * smc_phy_configure() calls msleep() which calls schedule_timeout() - * which calls schedule(). Hence we use a work queue. - */ - if (lp->phy_type != 0) - schedule_work(&lp->phy_configure); - - /* We can accept TX packets again */ - dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(dev); -} - -/* - * This routine will, depending on the values passed to it, - * either make it accept multicast packets, go into - * promiscuous mode (for TCPDUMP and cousins) or accept - * a select set of multicast packets - */ -static void smc_set_multicast_list(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - unsigned char multicast_table[8]; - int update_multicast = 0; - - DBG(2, "%s: %s\n", dev->name, __func__); - - if (dev->flags & IFF_PROMISC) { - DBG(2, "%s: RCR_PRMS\n", dev->name); - lp->rcr_cur_mode |= RCR_PRMS; - } - -/* BUG? I never disable promiscuous mode if multicasting was turned on. - Now, I turn off promiscuous mode, but I don't do anything to multicasting - when promiscuous mode is turned on. -*/ - - /* - * Here, I am setting this to accept all multicast packets. - * I don't need to zero the multicast table, because the flag is - * checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) { - DBG(2, "%s: RCR_ALMUL\n", dev->name); - lp->rcr_cur_mode |= RCR_ALMUL; - } - - /* - * This sets the internal hardware table to filter out unwanted - * multicast packets before they take up memory. - * - * The SMC chip uses a hash table where the high 6 bits of the CRC of - * address are the offset into the table. If that bit is 1, then the - * multicast packet is accepted. Otherwise, it's dropped silently. - * - * To use the 6 bits as an offset into the table, the high 3 bits are - * the number of the 8 bit register, while the low 3 bits are the bit - * within that register. - */ - else if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - - /* table for flipping the order of 3 bits */ - static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7}; - - /* start with a table of all zeros: reject all */ - memset(multicast_table, 0, sizeof(multicast_table)); - - netdev_for_each_mc_addr(ha, dev) { - int position; - - /* only use the low order bits */ - position = crc32_le(~0, ha->addr, 6) & 0x3f; - - /* do some messy swapping to put the bit in the right spot */ - multicast_table[invert3[position&7]] |= - (1<<invert3[(position>>3)&7]); - } - - /* be sure I get rid of flags I might have set */ - lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); - - /* now, the table can be loaded into the chipset */ - update_multicast = 1; - } else { - DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); - lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); - - /* - * since I'm disabling all multicast entirely, I need to - * clear the multicast list - */ - memset(multicast_table, 0, sizeof(multicast_table)); - update_multicast = 1; - } - - spin_lock_irq(&lp->lock); - SMC_SELECT_BANK(lp, 0); - SMC_SET_RCR(lp, lp->rcr_cur_mode); - if (update_multicast) { - SMC_SELECT_BANK(lp, 3); - SMC_SET_MCAST(lp, multicast_table); - } - SMC_SELECT_BANK(lp, 2); - spin_unlock_irq(&lp->lock); -} - - -/* - * Open and Initialize the board - * - * Set up everything, reset the card, etc.. - */ -static int -smc_open(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - - DBG(2, "%s: %s\n", dev->name, __func__); - - /* - * Check that the address is valid. If its not, refuse - * to bring the device up. The user must specify an - * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx - */ - if (!is_valid_ether_addr(dev->dev_addr)) { - PRINTK("%s: no valid ethernet hw addr\n", __func__); - return -EINVAL; - } - - /* Setup the default Register Modes */ - lp->tcr_cur_mode = TCR_DEFAULT; - lp->rcr_cur_mode = RCR_DEFAULT; - lp->rpc_cur_mode = RPC_DEFAULT | - lp->cfg.leda << RPC_LSXA_SHFT | - lp->cfg.ledb << RPC_LSXB_SHFT; - - /* - * If we are not using a MII interface, we need to - * monitor our own carrier signal to detect faults. - */ - if (lp->phy_type == 0) - lp->tcr_cur_mode |= TCR_MON_CSN; - - /* reset the hardware */ - smc_reset(dev); - smc_enable(dev); - - /* Configure the PHY, initialize the link state */ - if (lp->phy_type != 0) - smc_phy_configure(&lp->phy_configure); - else { - spin_lock_irq(&lp->lock); - smc_10bt_check_media(dev, 1); - spin_unlock_irq(&lp->lock); - } - - netif_start_queue(dev); - return 0; -} - -/* - * smc_close - * - * this makes the board clean up everything that it can - * and not talk to the outside world. Caused by - * an 'ifconfig ethX down' - */ -static int smc_close(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - - DBG(2, "%s: %s\n", dev->name, __func__); - - netif_stop_queue(dev); - netif_carrier_off(dev); - - /* clear everything */ - smc_shutdown(dev); - tasklet_kill(&lp->tx_task); - smc_phy_powerdown(dev); - return 0; -} - -/* - * Ethtool support - */ -static int -smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smc_local *lp = netdev_priv(dev); - int ret; - - cmd->maxtxpkt = 1; - cmd->maxrxpkt = 1; - - if (lp->phy_type != 0) { - spin_lock_irq(&lp->lock); - ret = mii_ethtool_gset(&lp->mii, cmd); - spin_unlock_irq(&lp->lock); - } else { - cmd->supported = SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_TP | SUPPORTED_AUI; - - if (lp->ctl_rspeed == 10) - ethtool_cmd_speed_set(cmd, SPEED_10); - else if (lp->ctl_rspeed == 100) - ethtool_cmd_speed_set(cmd, SPEED_100); - - cmd->autoneg = AUTONEG_DISABLE; - cmd->transceiver = XCVR_INTERNAL; - cmd->port = 0; - cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF; - - ret = 0; - } - - return ret; -} - -static int -smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smc_local *lp = netdev_priv(dev); - int ret; - - if (lp->phy_type != 0) { - spin_lock_irq(&lp->lock); - ret = mii_ethtool_sset(&lp->mii, cmd); - spin_unlock_irq(&lp->lock); - } else { - if (cmd->autoneg != AUTONEG_DISABLE || - cmd->speed != SPEED_10 || - (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) || - (cmd->port != PORT_TP && cmd->port != PORT_AUI)) - return -EINVAL; - -// lp->port = cmd->port; - lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL; - -// if (netif_running(dev)) -// smc_set_port(dev); - - ret = 0; - } - - return ret; -} - -static void -smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strncpy(info->driver, CARDNAME, sizeof(info->driver)); - strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info)); -} - -static int smc_ethtool_nwayreset(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - int ret = -EINVAL; - - if (lp->phy_type != 0) { - spin_lock_irq(&lp->lock); - ret = mii_nway_restart(&lp->mii); - spin_unlock_irq(&lp->lock); - } - - return ret; -} - -static u32 smc_ethtool_getmsglevel(struct net_device *dev) -{ - struct smc_local *lp = netdev_priv(dev); - return lp->msg_enable; -} - -static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level) -{ - struct smc_local *lp = netdev_priv(dev); - lp->msg_enable = level; -} - -static int smc_write_eeprom_word(struct net_device *dev, u16 addr, u16 word) -{ - u16 ctl; - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - - spin_lock_irq(&lp->lock); - /* load word into GP register */ - SMC_SELECT_BANK(lp, 1); - SMC_SET_GP(lp, word); - /* set the address to put the data in EEPROM */ - SMC_SELECT_BANK(lp, 2); - SMC_SET_PTR(lp, addr); - /* tell it to write */ - SMC_SELECT_BANK(lp, 1); - ctl = SMC_GET_CTL(lp); - SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_STORE)); - /* wait for it to finish */ - do { - udelay(1); - } while (SMC_GET_CTL(lp) & CTL_STORE); - /* clean up */ - SMC_SET_CTL(lp, ctl); - SMC_SELECT_BANK(lp, 2); - spin_unlock_irq(&lp->lock); - return 0; -} - -static int smc_read_eeprom_word(struct net_device *dev, u16 addr, u16 *word) -{ - u16 ctl; - struct smc_local *lp = netdev_priv(dev); - void __iomem *ioaddr = lp->base; - - spin_lock_irq(&lp->lock); - /* set the EEPROM address to get the data from */ - SMC_SELECT_BANK(lp, 2); - SMC_SET_PTR(lp, addr | PTR_READ); - /* tell it to load */ - SMC_SELECT_BANK(lp, 1); - SMC_SET_GP(lp, 0xffff); /* init to known */ - ctl = SMC_GET_CTL(lp); - SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_RELOAD)); - /* wait for it to finish */ - do { - udelay(1); - } while (SMC_GET_CTL(lp) & CTL_RELOAD); - /* read word from GP register */ - *word = SMC_GET_GP(lp); - /* clean up */ - SMC_SET_CTL(lp, ctl); - SMC_SELECT_BANK(lp, 2); - spin_unlock_irq(&lp->lock); - return 0; -} - -static int smc_ethtool_geteeprom_len(struct net_device *dev) -{ - return 0x23 * 2; -} - -static int smc_ethtool_geteeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - int i; - int imax; - - DBG(1, "Reading %d bytes at %d(0x%x)\n", - eeprom->len, eeprom->offset, eeprom->offset); - imax = smc_ethtool_geteeprom_len(dev); - for (i = 0; i < eeprom->len; i += 2) { - int ret; - u16 wbuf; - int offset = i + eeprom->offset; - if (offset > imax) - break; - ret = smc_read_eeprom_word(dev, offset >> 1, &wbuf); - if (ret != 0) - return ret; - DBG(2, "Read 0x%x from 0x%x\n", wbuf, offset >> 1); - data[i] = (wbuf >> 8) & 0xff; - data[i+1] = wbuf & 0xff; - } - return 0; -} - -static int smc_ethtool_seteeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - int i; - int imax; - - DBG(1, "Writing %d bytes to %d(0x%x)\n", - eeprom->len, eeprom->offset, eeprom->offset); - imax = smc_ethtool_geteeprom_len(dev); - for (i = 0; i < eeprom->len; i += 2) { - int ret; - u16 wbuf; - int offset = i + eeprom->offset; - if (offset > imax) - break; - wbuf = (data[i] << 8) | data[i + 1]; - DBG(2, "Writing 0x%x to 0x%x\n", wbuf, offset >> 1); - ret = smc_write_eeprom_word(dev, offset >> 1, wbuf); - if (ret != 0) - return ret; - } - return 0; -} - - -static const struct ethtool_ops smc_ethtool_ops = { - .get_settings = smc_ethtool_getsettings, - .set_settings = smc_ethtool_setsettings, - .get_drvinfo = smc_ethtool_getdrvinfo, - - .get_msglevel = smc_ethtool_getmsglevel, - .set_msglevel = smc_ethtool_setmsglevel, - .nway_reset = smc_ethtool_nwayreset, - .get_link = ethtool_op_get_link, - .get_eeprom_len = smc_ethtool_geteeprom_len, - .get_eeprom = smc_ethtool_geteeprom, - .set_eeprom = smc_ethtool_seteeprom, -}; - -static const struct net_device_ops smc_netdev_ops = { - .ndo_open = smc_open, - .ndo_stop = smc_close, - .ndo_start_xmit = smc_hard_start_xmit, - .ndo_tx_timeout = smc_timeout, - .ndo_set_rx_mode = smc_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = smc_poll_controller, -#endif -}; - -/* - * smc_findirq - * - * This routine has a simple purpose -- make the SMC chip generate an - * interrupt, so an auto-detect routine can detect it, and find the IRQ, - */ -/* - * does this still work? - * - * I just deleted auto_irq.c, since it was never built... - * --jgarzik - */ -static int __devinit smc_findirq(struct smc_local *lp) -{ - void __iomem *ioaddr = lp->base; - int timeout = 20; - unsigned long cookie; - - DBG(2, "%s: %s\n", CARDNAME, __func__); - - cookie = probe_irq_on(); - - /* - * What I try to do here is trigger an ALLOC_INT. This is done - * by allocating a small chunk of memory, which will give an interrupt - * when done. - */ - /* enable ALLOCation interrupts ONLY */ - SMC_SELECT_BANK(lp, 2); - SMC_SET_INT_MASK(lp, IM_ALLOC_INT); - - /* - * Allocate 512 bytes of memory. Note that the chip was just - * reset so all the memory is available - */ - SMC_SET_MMU_CMD(lp, MC_ALLOC | 1); - - /* - * Wait until positive that the interrupt has been generated - */ - do { - int int_status; - udelay(10); - int_status = SMC_GET_INT(lp); - if (int_status & IM_ALLOC_INT) - break; /* got the interrupt */ - } while (--timeout); - - /* - * there is really nothing that I can do here if timeout fails, - * as autoirq_report will return a 0 anyway, which is what I - * want in this case. Plus, the clean up is needed in both - * cases. - */ - - /* and disable all interrupts again */ - SMC_SET_INT_MASK(lp, 0); - - /* and return what I found */ - return probe_irq_off(cookie); -} - -/* - * Function: smc_probe(unsigned long ioaddr) - * - * Purpose: - * Tests to see if a given ioaddr points to an SMC91x chip. - * Returns a 0 on success - * - * Algorithm: - * (1) see if the high byte of BANK_SELECT is 0x33 - * (2) compare the ioaddr with the base register's address - * (3) see if I recognize the chip ID in the appropriate register - * - * Here I do typical initialization tasks. - * - * o Initialize the structure if needed - * o print out my vanity message if not done so already - * o print out what type of hardware is detected - * o print out the ethernet address - * o find the IRQ - * o set up my private data - * o configure the dev structure with my subroutines - * o actually GRAB the irq. - * o GRAB the region - */ -static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, - unsigned long irq_flags) -{ - struct smc_local *lp = netdev_priv(dev); - static int version_printed = 0; - int retval; - unsigned int val, revision_register; - const char *version_string; - - DBG(2, "%s: %s\n", CARDNAME, __func__); - - /* First, see if the high byte is 0x33 */ - val = SMC_CURRENT_BANK(lp); - DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val); - if ((val & 0xFF00) != 0x3300) { - if ((val & 0xFF) == 0x33) { - printk(KERN_WARNING - "%s: Detected possible byte-swapped interface" - " at IOADDR %p\n", CARDNAME, ioaddr); - } - retval = -ENODEV; - goto err_out; - } - - /* - * The above MIGHT indicate a device, but I need to write to - * further test this. - */ - SMC_SELECT_BANK(lp, 0); - val = SMC_CURRENT_BANK(lp); - if ((val & 0xFF00) != 0x3300) { - retval = -ENODEV; - goto err_out; - } - - /* - * well, we've already written once, so hopefully another - * time won't hurt. This time, I need to switch the bank - * register to bank 1, so I can access the base address - * register - */ - SMC_SELECT_BANK(lp, 1); - val = SMC_GET_BASE(lp); - val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; - if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) { - printk("%s: IOADDR %p doesn't match configuration (%x).\n", - CARDNAME, ioaddr, val); - } - - /* - * check if the revision register is something that I - * recognize. These might need to be added to later, - * as future revisions could be added. - */ - SMC_SELECT_BANK(lp, 3); - revision_register = SMC_GET_REV(lp); - DBG(2, "%s: revision = 0x%04x\n", CARDNAME, revision_register); - version_string = chip_ids[ (revision_register >> 4) & 0xF]; - if (!version_string || (revision_register & 0xff00) != 0x3300) { - /* I don't recognize this chip, so... */ - printk("%s: IO %p: Unrecognized revision register 0x%04x" - ", Contact author.\n", CARDNAME, - ioaddr, revision_register); - - retval = -ENODEV; - goto err_out; - } - - /* At this point I'll assume that the chip is an SMC91x. */ - if (version_printed++ == 0) - printk("%s", version); - - /* fill in some of the fields */ - dev->base_addr = (unsigned long)ioaddr; - lp->base = ioaddr; - lp->version = revision_register & 0xff; - spin_lock_init(&lp->lock); - - /* Get the MAC address */ - SMC_SELECT_BANK(lp, 1); - SMC_GET_MAC_ADDR(lp, dev->dev_addr); - - /* now, reset the chip, and put it into a known state */ - smc_reset(dev); - - /* - * If dev->irq is 0, then the device has to be banged on to see - * what the IRQ is. - * - * This banging doesn't always detect the IRQ, for unknown reasons. - * a workaround is to reset the chip and try again. - * - * Interestingly, the DOS packet driver *SETS* the IRQ on the card to - * be what is requested on the command line. I don't do that, mostly - * because the card that I have uses a non-standard method of accessing - * the IRQs, and because this _should_ work in most configurations. - * - * Specifying an IRQ is done with the assumption that the user knows - * what (s)he is doing. No checking is done!!!! - */ - if (dev->irq < 1) { - int trials; - - trials = 3; - while (trials--) { - dev->irq = smc_findirq(lp); - if (dev->irq) - break; - /* kick the card and try again */ - smc_reset(dev); - } - } - if (dev->irq == 0) { - printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", - dev->name); - retval = -ENODEV; - goto err_out; - } - dev->irq = irq_canonicalize(dev->irq); - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - dev->watchdog_timeo = msecs_to_jiffies(watchdog); - dev->netdev_ops = &smc_netdev_ops; - dev->ethtool_ops = &smc_ethtool_ops; - - tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev); - INIT_WORK(&lp->phy_configure, smc_phy_configure); - lp->dev = dev; - lp->mii.phy_id_mask = 0x1f; - lp->mii.reg_num_mask = 0x1f; - lp->mii.force_media = 0; - lp->mii.full_duplex = 0; - lp->mii.dev = dev; - lp->mii.mdio_read = smc_phy_read; - lp->mii.mdio_write = smc_phy_write; - - /* - * Locate the phy, if any. - */ - if (lp->version >= (CHIP_91100 << 4)) - smc_phy_detect(dev); - - /* then shut everything down to save power */ - smc_shutdown(dev); - smc_phy_powerdown(dev); - - /* Set default parameters */ - lp->msg_enable = NETIF_MSG_LINK; - lp->ctl_rfduplx = 0; - lp->ctl_rspeed = 10; - - if (lp->version >= (CHIP_91100 << 4)) { - lp->ctl_rfduplx = 1; - lp->ctl_rspeed = 100; - } - - /* Grab the IRQ */ - retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev); - if (retval) - goto err_out; - -#ifdef CONFIG_ARCH_PXA -# ifdef SMC_USE_PXA_DMA - lp->cfg.flags |= SMC91X_USE_DMA; -# endif - if (lp->cfg.flags & SMC91X_USE_DMA) { - int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, - smc_pxa_dma_irq, NULL); - if (dma >= 0) - dev->dma = dma; - } -#endif - - retval = register_netdev(dev); - if (retval == 0) { - /* now, print out the card info, in a short format.. */ - printk("%s: %s (rev %d) at %p IRQ %d", - dev->name, version_string, revision_register & 0x0f, - lp->base, dev->irq); - - if (dev->dma != (unsigned char)-1) - printk(" DMA %d", dev->dma); - - printk("%s%s\n", - lp->cfg.flags & SMC91X_NOWAIT ? " [nowait]" : "", - THROTTLE_TX_PKTS ? " [throttle_tx]" : ""); - - if (!is_valid_ether_addr(dev->dev_addr)) { - printk("%s: Invalid ethernet MAC address. Please " - "set using ifconfig\n", dev->name); - } else { - /* Print the Ethernet address */ - printk("%s: Ethernet addr: %pM\n", - dev->name, dev->dev_addr); - } - - if (lp->phy_type == 0) { - PRINTK("%s: No PHY found\n", dev->name); - } else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) { - PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name); - } else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) { - PRINTK("%s: PHY LAN83C180\n", dev->name); - } - } - -err_out: -#ifdef CONFIG_ARCH_PXA - if (retval && dev->dma != (unsigned char)-1) - pxa_free_dma(dev->dma); -#endif - return retval; -} - -static int smc_enable_device(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smc_local *lp = netdev_priv(ndev); - unsigned long flags; - unsigned char ecor, ecsr; - void __iomem *addr; - struct resource * res; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); - if (!res) - return 0; - - /* - * Map the attribute space. This is overkill, but clean. - */ - addr = ioremap(res->start, ATTRIB_SIZE); - if (!addr) - return -ENOMEM; - - /* - * Reset the device. We must disable IRQs around this - * since a reset causes the IRQ line become active. - */ - local_irq_save(flags); - ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET; - writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT)); - readb(addr + (ECOR << SMC_IO_SHIFT)); - - /* - * Wait 100us for the chip to reset. - */ - udelay(100); - - /* - * The device will ignore all writes to the enable bit while - * reset is asserted, even if the reset bit is cleared in the - * same write. Must clear reset first, then enable the device. - */ - writeb(ecor, addr + (ECOR << SMC_IO_SHIFT)); - writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT)); - - /* - * Set the appropriate byte/word mode. - */ - ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8; - if (!SMC_16BIT(lp)) - ecsr |= ECSR_IOIS8; - writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT)); - local_irq_restore(flags); - - iounmap(addr); - - /* - * Wait for the chip to wake up. We could poll the control - * register in the main register space, but that isn't mapped - * yet. We know this is going to take 750us. - */ - msleep(1); - - return 0; -} - -static int smc_request_attrib(struct platform_device *pdev, - struct net_device *ndev) -{ - struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); - struct smc_local *lp __maybe_unused = netdev_priv(ndev); - - if (!res) - return 0; - - if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME)) - return -EBUSY; - - return 0; -} - -static void smc_release_attrib(struct platform_device *pdev, - struct net_device *ndev) -{ - struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); - struct smc_local *lp __maybe_unused = netdev_priv(ndev); - - if (res) - release_mem_region(res->start, ATTRIB_SIZE); -} - -static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) -{ - if (SMC_CAN_USE_DATACS) { - struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); - struct smc_local *lp = netdev_priv(ndev); - - if (!res) - return; - - if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) { - printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME); - return; - } - - lp->datacs = ioremap(res->start, SMC_DATA_EXTENT); - } -} - -static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) -{ - if (SMC_CAN_USE_DATACS) { - struct smc_local *lp = netdev_priv(ndev); - struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); - - if (lp->datacs) - iounmap(lp->datacs); - - lp->datacs = NULL; - - if (res) - release_mem_region(res->start, SMC_DATA_EXTENT); - } -} - -/* - * smc_init(void) - * Input parameters: - * dev->base_addr == 0, try to find all possible locations - * dev->base_addr > 0x1ff, this is the address to check - * dev->base_addr == <anything else>, return failure code - * - * Output: - * 0 --> there is a device - * anything else, error - */ -static int __devinit smc_drv_probe(struct platform_device *pdev) -{ - struct smc91x_platdata *pd = pdev->dev.platform_data; - struct smc_local *lp; - struct net_device *ndev; - struct resource *res, *ires; - unsigned int __iomem *addr; - unsigned long irq_flags = SMC_IRQ_FLAGS; - int ret; - - ndev = alloc_etherdev(sizeof(struct smc_local)); - if (!ndev) { - ret = -ENOMEM; - goto out; - } - SET_NETDEV_DEV(ndev, &pdev->dev); - - /* get configuration from platform data, only allow use of - * bus width if both SMC_CAN_USE_xxx and SMC91X_USE_xxx are set. - */ - - lp = netdev_priv(ndev); - - if (pd) { - memcpy(&lp->cfg, pd, sizeof(lp->cfg)); - lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags); - } else { - lp->cfg.flags |= (SMC_CAN_USE_8BIT) ? SMC91X_USE_8BIT : 0; - lp->cfg.flags |= (SMC_CAN_USE_16BIT) ? SMC91X_USE_16BIT : 0; - lp->cfg.flags |= (SMC_CAN_USE_32BIT) ? SMC91X_USE_32BIT : 0; - lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0; - } - - if (!lp->cfg.leda && !lp->cfg.ledb) { - lp->cfg.leda = RPC_LSA_DEFAULT; - lp->cfg.ledb = RPC_LSB_DEFAULT; - } - - ndev->dma = (unsigned char)-1; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto out_free_netdev; - } - - - if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) { - ret = -EBUSY; - goto out_free_netdev; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { - ret = -ENODEV; - goto out_release_io; - } - - ndev->irq = ires->start; - - if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK) - irq_flags = ires->flags & IRQF_TRIGGER_MASK; - - ret = smc_request_attrib(pdev, ndev); - if (ret) - goto out_release_io; -#if defined(CONFIG_SA1100_ASSABET) - neponset_ncr_set(NCR_ENET_OSC_EN); -#endif - platform_set_drvdata(pdev, ndev); - ret = smc_enable_device(pdev); - if (ret) - goto out_release_attrib; - - addr = ioremap(res->start, SMC_IO_EXTENT); - if (!addr) { - ret = -ENOMEM; - goto out_release_attrib; - } - -#ifdef CONFIG_ARCH_PXA - { - struct smc_local *lp = netdev_priv(ndev); - lp->device = &pdev->dev; - lp->physaddr = res->start; - } -#endif - - ret = smc_probe(ndev, addr, irq_flags); - if (ret != 0) - goto out_iounmap; - - smc_request_datacs(pdev, ndev); - - return 0; - - out_iounmap: - platform_set_drvdata(pdev, NULL); - iounmap(addr); - out_release_attrib: - smc_release_attrib(pdev, ndev); - out_release_io: - release_mem_region(res->start, SMC_IO_EXTENT); - out_free_netdev: - free_netdev(ndev); - out: - printk("%s: not found (%d).\n", CARDNAME, ret); - - return ret; -} - -static int __devexit smc_drv_remove(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smc_local *lp = netdev_priv(ndev); - struct resource *res; - - platform_set_drvdata(pdev, NULL); - - unregister_netdev(ndev); - - free_irq(ndev->irq, ndev); - -#ifdef CONFIG_ARCH_PXA - if (ndev->dma != (unsigned char)-1) - pxa_free_dma(ndev->dma); -#endif - iounmap(lp->base); - - smc_release_datacs(pdev,ndev); - smc_release_attrib(pdev,ndev); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, SMC_IO_EXTENT); - - free_netdev(ndev); - - return 0; -} - -static int smc_drv_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct net_device *ndev = platform_get_drvdata(pdev); - - if (ndev) { - if (netif_running(ndev)) { - netif_device_detach(ndev); - smc_shutdown(ndev); - smc_phy_powerdown(ndev); - } - } - return 0; -} - -static int smc_drv_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct net_device *ndev = platform_get_drvdata(pdev); - - if (ndev) { - struct smc_local *lp = netdev_priv(ndev); - smc_enable_device(pdev); - if (netif_running(ndev)) { - smc_reset(ndev); - smc_enable(ndev); - if (lp->phy_type != 0) - smc_phy_configure(&lp->phy_configure); - netif_device_attach(ndev); - } - } - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id smc91x_match[] = { - { .compatible = "smsc,lan91c94", }, - { .compatible = "smsc,lan91c111", }, - {}, -}; -MODULE_DEVICE_TABLE(of, smc91x_match); -#else -#define smc91x_match NULL -#endif - -static struct dev_pm_ops smc_drv_pm_ops = { - .suspend = smc_drv_suspend, - .resume = smc_drv_resume, -}; - -static struct platform_driver smc_driver = { - .probe = smc_drv_probe, - .remove = __devexit_p(smc_drv_remove), - .driver = { - .name = CARDNAME, - .owner = THIS_MODULE, - .pm = &smc_drv_pm_ops, - .of_match_table = smc91x_match, - }, -}; - -module_platform_driver(smc_driver); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.h b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.h deleted file mode 100644 index 5f53fbbf..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smc91x.h +++ /dev/null @@ -1,1180 +0,0 @@ -/*------------------------------------------------------------------------ - . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device. - . - . Copyright (C) 1996 by Erik Stahlman - . Copyright (C) 2001 Standard Microsystems Corporation - . Developed by Simple Network Magic Corporation - . Copyright (C) 2003 Monta Vista Software, Inc. - . Unified SMC91x driver by Nicolas Pitre - . - . This program is free software; you can redistribute it and/or modify - . it under the terms of the GNU General Public License as published by - . the Free Software Foundation; either version 2 of the License, or - . (at your option) any later version. - . - . This program is distributed in the hope that it will be useful, - . but WITHOUT ANY WARRANTY; without even the implied warranty of - . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - . GNU General Public License for more details. - . - . You should have received a copy of the GNU General Public License - . along with this program; if not, write to the Free Software - . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - . - . Information contained in this file was obtained from the LAN91C111 - . manual from SMC. To get a copy, if you really want one, you can find - . information under www.smsc.com. - . - . Authors - . Erik Stahlman <erik@vt.edu> - . Daris A Nevil <dnevil@snmc.com> - . Nicolas Pitre <nico@fluxnic.net> - . - ---------------------------------------------------------------------------*/ -#ifndef _SMC91X_H_ -#define _SMC91X_H_ - -#include <linux/smc91x.h> - -/* - * Define your architecture specific bus configuration parameters here. - */ - -#if defined(CONFIG_ARCH_LUBBOCK) ||\ - defined(CONFIG_MACH_MAINSTONE) ||\ - defined(CONFIG_MACH_ZYLONITE) ||\ - defined(CONFIG_MACH_LITTLETON) ||\ - defined(CONFIG_MACH_ZYLONITE2) ||\ - defined(CONFIG_ARCH_VIPER) ||\ - defined(CONFIG_MACH_STARGATE2) - -#include <asm/mach-types.h> - -/* Now the bus width is specified in the platform data - * pretend here to support all I/O access types - */ -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 1 -#define SMC_NOWAIT 1 - -#define SMC_IO_SHIFT (lp->io_shift) - -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) -#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) -#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) -#define SMC_IRQ_FLAGS (-1) /* from resource */ - -/* We actually can't write halfwords properly if not word aligned */ -static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg) -{ - if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) { - unsigned int v = val << 16; - v |= readl(ioaddr + (reg & ~2)) & 0xffff; - writel(v, ioaddr + (reg & ~2)); - } else { - writew(val, ioaddr + reg); - } -} - -#elif defined(CONFIG_SA1100_PLEB) -/* We can only do 16-bit reads and writes in the static memory space. */ -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 -#define SMC_IO_SHIFT 0 -#define SMC_NOWAIT 1 - -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_insb(a, r, p, l) readsb((a) + (r), p, (l)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) - -#define SMC_IRQ_FLAGS (-1) - -#elif defined(CONFIG_SA1100_ASSABET) - -#include <mach/neponset.h> - -/* We can only do 8-bit reads and writes in the static memory space. */ -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 0 -#define SMC_CAN_USE_32BIT 0 -#define SMC_NOWAIT 1 - -/* The first two address lines aren't connected... */ -#define SMC_IO_SHIFT 2 - -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_insb(a, r, p, l) readsb((a) + (r), p, (l)) -#define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l)) -#define SMC_IRQ_FLAGS (-1) /* from resource */ - -#elif defined(CONFIG_MACH_LOGICPD_PXA270) || \ - defined(CONFIG_MACH_NOMADIK_8815NHK) - -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 -#define SMC_IO_SHIFT 0 -#define SMC_NOWAIT 1 - -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) -#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) - -#elif defined(CONFIG_ARCH_INNOKOM) || \ - defined(CONFIG_ARCH_PXA_IDP) || \ - defined(CONFIG_ARCH_RAMSES) || \ - defined(CONFIG_ARCH_PCM027) - -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 1 -#define SMC_IO_SHIFT 0 -#define SMC_NOWAIT 1 -#define SMC_USE_PXA_DMA 1 - -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) -#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) -#define SMC_IRQ_FLAGS (-1) /* from resource */ - -/* We actually can't write halfwords properly if not word aligned */ -static inline void -SMC_outw(u16 val, void __iomem *ioaddr, int reg) -{ - if (reg & 2) { - unsigned int v = val << 16; - v |= readl(ioaddr + (reg & ~2)) & 0xffff; - writel(v, ioaddr + (reg & ~2)); - } else { - writew(val, ioaddr + reg); - } -} - -#elif defined(CONFIG_SH_SH4202_MICRODEV) - -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 - -#define SMC_inb(a, r) inb((a) + (r) - 0xa0000000) -#define SMC_inw(a, r) inw((a) + (r) - 0xa0000000) -#define SMC_inl(a, r) inl((a) + (r) - 0xa0000000) -#define SMC_outb(v, a, r) outb(v, (a) + (r) - 0xa0000000) -#define SMC_outw(v, a, r) outw(v, (a) + (r) - 0xa0000000) -#define SMC_outl(v, a, r) outl(v, (a) + (r) - 0xa0000000) -#define SMC_insl(a, r, p, l) insl((a) + (r) - 0xa0000000, p, l) -#define SMC_outsl(a, r, p, l) outsl((a) + (r) - 0xa0000000, p, l) -#define SMC_insw(a, r, p, l) insw((a) + (r) - 0xa0000000, p, l) -#define SMC_outsw(a, r, p, l) outsw((a) + (r) - 0xa0000000, p, l) - -#define SMC_IRQ_FLAGS (0) - -#elif defined(CONFIG_M32R) - -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 - -#define SMC_inb(a, r) inb(((u32)a) + (r)) -#define SMC_inw(a, r) inw(((u32)a) + (r)) -#define SMC_outb(v, a, r) outb(v, ((u32)a) + (r)) -#define SMC_outw(v, a, r) outw(v, ((u32)a) + (r)) -#define SMC_insw(a, r, p, l) insw(((u32)a) + (r), p, l) -#define SMC_outsw(a, r, p, l) outsw(((u32)a) + (r), p, l) - -#define SMC_IRQ_FLAGS (0) - -#define RPC_LSA_DEFAULT RPC_LED_TX_RX -#define RPC_LSB_DEFAULT RPC_LED_100_10 - -#elif defined(CONFIG_ARCH_VERSATILE) - -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 1 -#define SMC_NOWAIT 1 - -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) -#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) -#define SMC_IRQ_FLAGS (-1) /* from resource */ - -#elif defined(CONFIG_MN10300) - -/* - * MN10300/AM33 configuration - */ - -#include <unit/smc91111.h> - -#elif defined(CONFIG_ARCH_MSM) - -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 -#define SMC_NOWAIT 1 - -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) -#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) - -#define SMC_IRQ_FLAGS IRQF_TRIGGER_HIGH - -#elif defined(CONFIG_COLDFIRE) - -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 -#define SMC_NOWAIT 1 - -static inline void mcf_insw(void *a, unsigned char *p, int l) -{ - u16 *wp = (u16 *) p; - while (l-- > 0) - *wp++ = readw(a); -} - -static inline void mcf_outsw(void *a, unsigned char *p, int l) -{ - u16 *wp = (u16 *) p; - while (l-- > 0) - writew(*wp++, a); -} - -#define SMC_inw(a, r) _swapw(readw((a) + (r))) -#define SMC_outw(v, a, r) writew(_swapw(v), (a) + (r)) -#define SMC_insw(a, r, p, l) mcf_insw(a + r, p, l) -#define SMC_outsw(a, r, p, l) mcf_outsw(a + r, p, l) - -#define SMC_IRQ_FLAGS (IRQF_DISABLED) - -#else - -/* - * Default configuration - */ - -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 1 -#define SMC_NOWAIT 1 - -#define SMC_IO_SHIFT (lp->io_shift) - -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) -#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) -#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) - -#define RPC_LSA_DEFAULT RPC_LED_100_10 -#define RPC_LSB_DEFAULT RPC_LED_TX_RX - -#endif - - -/* store this information for the driver.. */ -struct smc_local { - /* - * If I have to wait until memory is available to send a - * packet, I will store the skbuff here, until I get the - * desired memory. Then, I'll send it out and free it. - */ - struct sk_buff *pending_tx_skb; - struct tasklet_struct tx_task; - - /* version/revision of the SMC91x chip */ - int version; - - /* Contains the current active transmission mode */ - int tcr_cur_mode; - - /* Contains the current active receive mode */ - int rcr_cur_mode; - - /* Contains the current active receive/phy mode */ - int rpc_cur_mode; - int ctl_rfduplx; - int ctl_rspeed; - - u32 msg_enable; - u32 phy_type; - struct mii_if_info mii; - - /* work queue */ - struct work_struct phy_configure; - struct net_device *dev; - int work_pending; - - spinlock_t lock; - -#ifdef CONFIG_ARCH_PXA - /* DMA needs the physical address of the chip */ - u_long physaddr; - struct device *device; -#endif - void __iomem *base; - void __iomem *datacs; - - /* the low address lines on some platforms aren't connected... */ - int io_shift; - - struct smc91x_platdata cfg; -}; - -#define SMC_8BIT(p) ((p)->cfg.flags & SMC91X_USE_8BIT) -#define SMC_16BIT(p) ((p)->cfg.flags & SMC91X_USE_16BIT) -#define SMC_32BIT(p) ((p)->cfg.flags & SMC91X_USE_32BIT) - -#ifdef CONFIG_ARCH_PXA -/* - * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is - * always happening in irq context so no need to worry about races. TX is - * different and probably not worth it for that reason, and not as critical - * as RX which can overrun memory and lose packets. - */ -#include <linux/dma-mapping.h> -#include <mach/dma.h> - -#ifdef SMC_insl -#undef SMC_insl -#define SMC_insl(a, r, p, l) \ - smc_pxa_dma_insl(a, lp, r, dev->dma, p, l) -static inline void -smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma, - u_char *buf, int len) -{ - u_long physaddr = lp->physaddr; - dma_addr_t dmabuf; - - /* fallback if no DMA available */ - if (dma == (unsigned char)-1) { - readsl(ioaddr + reg, buf, len); - return; - } - - /* 64 bit alignment is required for memory to memory DMA */ - if ((long)buf & 4) { - *((u32 *)buf) = SMC_inl(ioaddr, reg); - buf += 4; - len--; - } - - len *= 4; - dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE); - DCSR(dma) = DCSR_NODESC; - DTADR(dma) = dmabuf; - DSADR(dma) = physaddr + reg; - DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | - DCMD_WIDTH4 | (DCMD_LENGTH & len)); - DCSR(dma) = DCSR_NODESC | DCSR_RUN; - while (!(DCSR(dma) & DCSR_STOPSTATE)) - cpu_relax(); - DCSR(dma) = 0; - dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE); -} -#endif - -#ifdef SMC_insw -#undef SMC_insw -#define SMC_insw(a, r, p, l) \ - smc_pxa_dma_insw(a, lp, r, dev->dma, p, l) -static inline void -smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma, - u_char *buf, int len) -{ - u_long physaddr = lp->physaddr; - dma_addr_t dmabuf; - - /* fallback if no DMA available */ - if (dma == (unsigned char)-1) { - readsw(ioaddr + reg, buf, len); - return; - } - - /* 64 bit alignment is required for memory to memory DMA */ - while ((long)buf & 6) { - *((u16 *)buf) = SMC_inw(ioaddr, reg); - buf += 2; - len--; - } - - len *= 2; - dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE); - DCSR(dma) = DCSR_NODESC; - DTADR(dma) = dmabuf; - DSADR(dma) = physaddr + reg; - DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | - DCMD_WIDTH2 | (DCMD_LENGTH & len)); - DCSR(dma) = DCSR_NODESC | DCSR_RUN; - while (!(DCSR(dma) & DCSR_STOPSTATE)) - cpu_relax(); - DCSR(dma) = 0; - dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE); -} -#endif - -static void -smc_pxa_dma_irq(int dma, void *dummy) -{ - DCSR(dma) = 0; -} -#endif /* CONFIG_ARCH_PXA */ - - -/* - * Everything a particular hardware setup needs should have been defined - * at this point. Add stubs for the undefined cases, mainly to avoid - * compilation warnings since they'll be optimized away, or to prevent buggy - * use of them. - */ - -#if ! SMC_CAN_USE_32BIT -#define SMC_inl(ioaddr, reg) ({ BUG(); 0; }) -#define SMC_outl(x, ioaddr, reg) BUG() -#define SMC_insl(a, r, p, l) BUG() -#define SMC_outsl(a, r, p, l) BUG() -#endif - -#if !defined(SMC_insl) || !defined(SMC_outsl) -#define SMC_insl(a, r, p, l) BUG() -#define SMC_outsl(a, r, p, l) BUG() -#endif - -#if ! SMC_CAN_USE_16BIT - -/* - * Any 16-bit access is performed with two 8-bit accesses if the hardware - * can't do it directly. Most registers are 16-bit so those are mandatory. - */ -#define SMC_outw(x, ioaddr, reg) \ - do { \ - unsigned int __val16 = (x); \ - SMC_outb( __val16, ioaddr, reg ); \ - SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\ - } while (0) -#define SMC_inw(ioaddr, reg) \ - ({ \ - unsigned int __val16; \ - __val16 = SMC_inb( ioaddr, reg ); \ - __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \ - __val16; \ - }) - -#define SMC_insw(a, r, p, l) BUG() -#define SMC_outsw(a, r, p, l) BUG() - -#endif - -#if !defined(SMC_insw) || !defined(SMC_outsw) -#define SMC_insw(a, r, p, l) BUG() -#define SMC_outsw(a, r, p, l) BUG() -#endif - -#if ! SMC_CAN_USE_8BIT -#define SMC_inb(ioaddr, reg) ({ BUG(); 0; }) -#define SMC_outb(x, ioaddr, reg) BUG() -#define SMC_insb(a, r, p, l) BUG() -#define SMC_outsb(a, r, p, l) BUG() -#endif - -#if !defined(SMC_insb) || !defined(SMC_outsb) -#define SMC_insb(a, r, p, l) BUG() -#define SMC_outsb(a, r, p, l) BUG() -#endif - -#ifndef SMC_CAN_USE_DATACS -#define SMC_CAN_USE_DATACS 0 -#endif - -#ifndef SMC_IO_SHIFT -#define SMC_IO_SHIFT 0 -#endif - -#ifndef SMC_IRQ_FLAGS -#define SMC_IRQ_FLAGS IRQF_TRIGGER_RISING -#endif - -#ifndef SMC_INTERRUPT_PREAMBLE -#define SMC_INTERRUPT_PREAMBLE -#endif - - -/* Because of bank switching, the LAN91x uses only 16 I/O ports */ -#define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) -#define SMC_DATA_EXTENT (4) - -/* - . Bank Select Register: - . - . yyyy yyyy 0000 00xx - . xx = bank number - . yyyy yyyy = 0x33, for identification purposes. -*/ -#define BANK_SELECT (14 << SMC_IO_SHIFT) - - -// Transmit Control Register -/* BANK 0 */ -#define TCR_REG(lp) SMC_REG(lp, 0x0000, 0) -#define TCR_ENABLE 0x0001 // When 1 we can transmit -#define TCR_LOOP 0x0002 // Controls output pin LBK -#define TCR_FORCOL 0x0004 // When 1 will force a collision -#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0 -#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames -#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier -#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation -#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error -#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback -#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode - -#define TCR_CLEAR 0 /* do NOTHING */ -/* the default settings for the TCR register : */ -#define TCR_DEFAULT (TCR_ENABLE | TCR_PAD_EN) - - -// EPH Status Register -/* BANK 0 */ -#define EPH_STATUS_REG(lp) SMC_REG(lp, 0x0002, 0) -#define ES_TX_SUC 0x0001 // Last TX was successful -#define ES_SNGL_COL 0x0002 // Single collision detected for last tx -#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx -#define ES_LTX_MULT 0x0008 // Last tx was a multicast -#define ES_16COL 0x0010 // 16 Collisions Reached -#define ES_SQET 0x0020 // Signal Quality Error Test -#define ES_LTXBRD 0x0040 // Last tx was a broadcast -#define ES_TXDEFR 0x0080 // Transmit Deferred -#define ES_LATCOL 0x0200 // Late collision detected on last tx -#define ES_LOSTCARR 0x0400 // Lost Carrier Sense -#define ES_EXC_DEF 0x0800 // Excessive Deferral -#define ES_CTR_ROL 0x1000 // Counter Roll Over indication -#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin -#define ES_TXUNRN 0x8000 // Tx Underrun - - -// Receive Control Register -/* BANK 0 */ -#define RCR_REG(lp) SMC_REG(lp, 0x0004, 0) -#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted -#define RCR_PRMS 0x0002 // Enable promiscuous mode -#define RCR_ALMUL 0x0004 // When set accepts all multicast frames -#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets -#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets -#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision -#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier -#define RCR_SOFTRST 0x8000 // resets the chip - -/* the normal settings for the RCR register : */ -#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) -#define RCR_CLEAR 0x0 // set it to a base state - - -// Counter Register -/* BANK 0 */ -#define COUNTER_REG(lp) SMC_REG(lp, 0x0006, 0) - - -// Memory Information Register -/* BANK 0 */ -#define MIR_REG(lp) SMC_REG(lp, 0x0008, 0) - - -// Receive/Phy Control Register -/* BANK 0 */ -#define RPC_REG(lp) SMC_REG(lp, 0x000A, 0) -#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode. -#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode -#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode -#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb -#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb - -#ifndef RPC_LSA_DEFAULT -#define RPC_LSA_DEFAULT RPC_LED_100 -#endif -#ifndef RPC_LSB_DEFAULT -#define RPC_LSB_DEFAULT RPC_LED_FD -#endif - -#define RPC_DEFAULT (RPC_ANEG | RPC_SPEED | RPC_DPLX) - - -/* Bank 0 0x0C is reserved */ - -// Bank Select Register -/* All Banks */ -#define BSR_REG 0x000E - - -// Configuration Reg -/* BANK 1 */ -#define CONFIG_REG(lp) SMC_REG(lp, 0x0000, 1) -#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy -#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL -#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus -#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode. - -// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low -#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN) - - -// Base Address Register -/* BANK 1 */ -#define BASE_REG(lp) SMC_REG(lp, 0x0002, 1) - - -// Individual Address Registers -/* BANK 1 */ -#define ADDR0_REG(lp) SMC_REG(lp, 0x0004, 1) -#define ADDR1_REG(lp) SMC_REG(lp, 0x0006, 1) -#define ADDR2_REG(lp) SMC_REG(lp, 0x0008, 1) - - -// General Purpose Register -/* BANK 1 */ -#define GP_REG(lp) SMC_REG(lp, 0x000A, 1) - - -// Control Register -/* BANK 1 */ -#define CTL_REG(lp) SMC_REG(lp, 0x000C, 1) -#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received -#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically -#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt -#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt -#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt -#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store -#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers -#define CTL_STORE 0x0001 // When set stores registers into EEPROM - - -// MMU Command Register -/* BANK 2 */ -#define MMU_CMD_REG(lp) SMC_REG(lp, 0x0000, 2) -#define MC_BUSY 1 // When 1 the last release has not completed -#define MC_NOP (0<<5) // No Op -#define MC_ALLOC (1<<5) // OR with number of 256 byte packets -#define MC_RESET (2<<5) // Reset MMU to initial state -#define MC_REMOVE (3<<5) // Remove the current rx packet -#define MC_RELEASE (4<<5) // Remove and release the current rx packet -#define MC_FREEPKT (5<<5) // Release packet in PNR register -#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit -#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs - - -// Packet Number Register -/* BANK 2 */ -#define PN_REG(lp) SMC_REG(lp, 0x0002, 2) - - -// Allocation Result Register -/* BANK 2 */ -#define AR_REG(lp) SMC_REG(lp, 0x0003, 2) -#define AR_FAILED 0x80 // Alocation Failed - - -// TX FIFO Ports Register -/* BANK 2 */ -#define TXFIFO_REG(lp) SMC_REG(lp, 0x0004, 2) -#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty - -// RX FIFO Ports Register -/* BANK 2 */ -#define RXFIFO_REG(lp) SMC_REG(lp, 0x0005, 2) -#define RXFIFO_REMPTY 0x80 // RX FIFO Empty - -#define FIFO_REG(lp) SMC_REG(lp, 0x0004, 2) - -// Pointer Register -/* BANK 2 */ -#define PTR_REG(lp) SMC_REG(lp, 0x0006, 2) -#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area -#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access -#define PTR_READ 0x2000 // When 1 the operation is a read - - -// Data Register -/* BANK 2 */ -#define DATA_REG(lp) SMC_REG(lp, 0x0008, 2) - - -// Interrupt Status/Acknowledge Register -/* BANK 2 */ -#define INT_REG(lp) SMC_REG(lp, 0x000C, 2) - - -// Interrupt Mask Register -/* BANK 2 */ -#define IM_REG(lp) SMC_REG(lp, 0x000D, 2) -#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt -#define IM_ERCV_INT 0x40 // Early Receive Interrupt -#define IM_EPH_INT 0x20 // Set by Ethernet Protocol Handler section -#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns -#define IM_ALLOC_INT 0x08 // Set when allocation request is completed -#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty -#define IM_TX_INT 0x02 // Transmit Interrupt -#define IM_RCV_INT 0x01 // Receive Interrupt - - -// Multicast Table Registers -/* BANK 3 */ -#define MCAST_REG1(lp) SMC_REG(lp, 0x0000, 3) -#define MCAST_REG2(lp) SMC_REG(lp, 0x0002, 3) -#define MCAST_REG3(lp) SMC_REG(lp, 0x0004, 3) -#define MCAST_REG4(lp) SMC_REG(lp, 0x0006, 3) - - -// Management Interface Register (MII) -/* BANK 3 */ -#define MII_REG(lp) SMC_REG(lp, 0x0008, 3) -#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup -#define MII_MDOE 0x0008 // MII Output Enable -#define MII_MCLK 0x0004 // MII Clock, pin MDCLK -#define MII_MDI 0x0002 // MII Input, pin MDI -#define MII_MDO 0x0001 // MII Output, pin MDO - - -// Revision Register -/* BANK 3 */ -/* ( hi: chip id low: rev # ) */ -#define REV_REG(lp) SMC_REG(lp, 0x000A, 3) - - -// Early RCV Register -/* BANK 3 */ -/* this is NOT on SMC9192 */ -#define ERCV_REG(lp) SMC_REG(lp, 0x000C, 3) -#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received -#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask - - -// External Register -/* BANK 7 */ -#define EXT_REG(lp) SMC_REG(lp, 0x0000, 7) - - -#define CHIP_9192 3 -#define CHIP_9194 4 -#define CHIP_9195 5 -#define CHIP_9196 6 -#define CHIP_91100 7 -#define CHIP_91100FD 8 -#define CHIP_91111FD 9 - -static const char * chip_ids[ 16 ] = { - NULL, NULL, NULL, - /* 3 */ "SMC91C90/91C92", - /* 4 */ "SMC91C94", - /* 5 */ "SMC91C95", - /* 6 */ "SMC91C96", - /* 7 */ "SMC91C100", - /* 8 */ "SMC91C100FD", - /* 9 */ "SMC91C11xFD", - NULL, NULL, NULL, - NULL, NULL, NULL}; - - -/* - . Receive status bits -*/ -#define RS_ALGNERR 0x8000 -#define RS_BRODCAST 0x4000 -#define RS_BADCRC 0x2000 -#define RS_ODDFRAME 0x1000 -#define RS_TOOLONG 0x0800 -#define RS_TOOSHORT 0x0400 -#define RS_MULTICAST 0x0001 -#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) - - -/* - * PHY IDs - * LAN83C183 == LAN91C111 Internal PHY - */ -#define PHY_LAN83C183 0x0016f840 -#define PHY_LAN83C180 0x02821c50 - -/* - * PHY Register Addresses (LAN91C111 Internal PHY) - * - * Generic PHY registers can be found in <linux/mii.h> - * - * These phy registers are specific to our on-board phy. - */ - -// PHY Configuration Register 1 -#define PHY_CFG1_REG 0x10 -#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled -#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled -#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down -#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler -#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable -#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled -#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) -#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db -#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust -#define PHY_CFG1_TLVL_MASK 0x003C -#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time - - -// PHY Configuration Register 2 -#define PHY_CFG2_REG 0x11 -#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled -#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled -#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) -#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo - -// PHY Status Output (and Interrupt status) Register -#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) -#define PHY_INT_INT 0x8000 // 1=bits have changed since last read -#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected -#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync -#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx -#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx -#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx -#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected -#define PHY_INT_JAB 0x0100 // 1=Jabber detected -#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode -#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex - -// PHY Interrupt/Status Mask Register -#define PHY_MASK_REG 0x13 // Interrupt Mask -// Uses the same bit definitions as PHY_INT_REG - - -/* - * SMC91C96 ethernet config and status registers. - * These are in the "attribute" space. - */ -#define ECOR 0x8000 -#define ECOR_RESET 0x80 -#define ECOR_LEVEL_IRQ 0x40 -#define ECOR_WR_ATTRIB 0x04 -#define ECOR_ENABLE 0x01 - -#define ECSR 0x8002 -#define ECSR_IOIS8 0x20 -#define ECSR_PWRDWN 0x04 -#define ECSR_INT 0x02 - -#define ATTRIB_SIZE ((64*1024) << SMC_IO_SHIFT) - - -/* - * Macros to abstract register access according to the data bus - * capabilities. Please use those and not the in/out primitives. - * Note: the following macros do *not* select the bank -- this must - * be done separately as needed in the main code. The SMC_REG() macro - * only uses the bank argument for debugging purposes (when enabled). - * - * Note: despite inline functions being safer, everything leading to this - * should preferably be macros to let BUG() display the line number in - * the core source code since we're interested in the top call site - * not in any inline function location. - */ - -#if SMC_DEBUG > 0 -#define SMC_REG(lp, reg, bank) \ - ({ \ - int __b = SMC_CURRENT_BANK(lp); \ - if (unlikely((__b & ~0xf0) != (0x3300 | bank))) { \ - printk( "%s: bank reg screwed (0x%04x)\n", \ - CARDNAME, __b ); \ - BUG(); \ - } \ - reg<<SMC_IO_SHIFT; \ - }) -#else -#define SMC_REG(lp, reg, bank) (reg<<SMC_IO_SHIFT) -#endif - -/* - * Hack Alert: Some setups just can't write 8 or 16 bits reliably when not - * aligned to a 32 bit boundary. I tell you that does exist! - * Fortunately the affected register accesses can be easily worked around - * since we can write zeroes to the preceding 16 bits without adverse - * effects and use a 32-bit access. - * - * Enforce it on any 32-bit capable setup for now. - */ -#define SMC_MUST_ALIGN_WRITE(lp) SMC_32BIT(lp) - -#define SMC_GET_PN(lp) \ - (SMC_8BIT(lp) ? (SMC_inb(ioaddr, PN_REG(lp))) \ - : (SMC_inw(ioaddr, PN_REG(lp)) & 0xFF)) - -#define SMC_SET_PN(lp, x) \ - do { \ - if (SMC_MUST_ALIGN_WRITE(lp)) \ - SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 0, 2)); \ - else if (SMC_8BIT(lp)) \ - SMC_outb(x, ioaddr, PN_REG(lp)); \ - else \ - SMC_outw(x, ioaddr, PN_REG(lp)); \ - } while (0) - -#define SMC_GET_AR(lp) \ - (SMC_8BIT(lp) ? (SMC_inb(ioaddr, AR_REG(lp))) \ - : (SMC_inw(ioaddr, PN_REG(lp)) >> 8)) - -#define SMC_GET_TXFIFO(lp) \ - (SMC_8BIT(lp) ? (SMC_inb(ioaddr, TXFIFO_REG(lp))) \ - : (SMC_inw(ioaddr, TXFIFO_REG(lp)) & 0xFF)) - -#define SMC_GET_RXFIFO(lp) \ - (SMC_8BIT(lp) ? (SMC_inb(ioaddr, RXFIFO_REG(lp))) \ - : (SMC_inw(ioaddr, TXFIFO_REG(lp)) >> 8)) - -#define SMC_GET_INT(lp) \ - (SMC_8BIT(lp) ? (SMC_inb(ioaddr, INT_REG(lp))) \ - : (SMC_inw(ioaddr, INT_REG(lp)) & 0xFF)) - -#define SMC_ACK_INT(lp, x) \ - do { \ - if (SMC_8BIT(lp)) \ - SMC_outb(x, ioaddr, INT_REG(lp)); \ - else { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_inw(ioaddr, INT_REG(lp)) & ~0xff; \ - SMC_outw(__mask | (x), ioaddr, INT_REG(lp)); \ - local_irq_restore(__flags); \ - } \ - } while (0) - -#define SMC_GET_INT_MASK(lp) \ - (SMC_8BIT(lp) ? (SMC_inb(ioaddr, IM_REG(lp))) \ - : (SMC_inw(ioaddr, INT_REG(lp)) >> 8)) - -#define SMC_SET_INT_MASK(lp, x) \ - do { \ - if (SMC_8BIT(lp)) \ - SMC_outb(x, ioaddr, IM_REG(lp)); \ - else \ - SMC_outw((x) << 8, ioaddr, INT_REG(lp)); \ - } while (0) - -#define SMC_CURRENT_BANK(lp) SMC_inw(ioaddr, BANK_SELECT) - -#define SMC_SELECT_BANK(lp, x) \ - do { \ - if (SMC_MUST_ALIGN_WRITE(lp)) \ - SMC_outl((x)<<16, ioaddr, 12<<SMC_IO_SHIFT); \ - else \ - SMC_outw(x, ioaddr, BANK_SELECT); \ - } while (0) - -#define SMC_GET_BASE(lp) SMC_inw(ioaddr, BASE_REG(lp)) - -#define SMC_SET_BASE(lp, x) SMC_outw(x, ioaddr, BASE_REG(lp)) - -#define SMC_GET_CONFIG(lp) SMC_inw(ioaddr, CONFIG_REG(lp)) - -#define SMC_SET_CONFIG(lp, x) SMC_outw(x, ioaddr, CONFIG_REG(lp)) - -#define SMC_GET_COUNTER(lp) SMC_inw(ioaddr, COUNTER_REG(lp)) - -#define SMC_GET_CTL(lp) SMC_inw(ioaddr, CTL_REG(lp)) - -#define SMC_SET_CTL(lp, x) SMC_outw(x, ioaddr, CTL_REG(lp)) - -#define SMC_GET_MII(lp) SMC_inw(ioaddr, MII_REG(lp)) - -#define SMC_GET_GP(lp) SMC_inw(ioaddr, GP_REG(lp)) - -#define SMC_SET_GP(lp, x) \ - do { \ - if (SMC_MUST_ALIGN_WRITE(lp)) \ - SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 1)); \ - else \ - SMC_outw(x, ioaddr, GP_REG(lp)); \ - } while (0) - -#define SMC_SET_MII(lp, x) SMC_outw(x, ioaddr, MII_REG(lp)) - -#define SMC_GET_MIR(lp) SMC_inw(ioaddr, MIR_REG(lp)) - -#define SMC_SET_MIR(lp, x) SMC_outw(x, ioaddr, MIR_REG(lp)) - -#define SMC_GET_MMU_CMD(lp) SMC_inw(ioaddr, MMU_CMD_REG(lp)) - -#define SMC_SET_MMU_CMD(lp, x) SMC_outw(x, ioaddr, MMU_CMD_REG(lp)) - -#define SMC_GET_FIFO(lp) SMC_inw(ioaddr, FIFO_REG(lp)) - -#define SMC_GET_PTR(lp) SMC_inw(ioaddr, PTR_REG(lp)) - -#define SMC_SET_PTR(lp, x) \ - do { \ - if (SMC_MUST_ALIGN_WRITE(lp)) \ - SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 4, 2)); \ - else \ - SMC_outw(x, ioaddr, PTR_REG(lp)); \ - } while (0) - -#define SMC_GET_EPH_STATUS(lp) SMC_inw(ioaddr, EPH_STATUS_REG(lp)) - -#define SMC_GET_RCR(lp) SMC_inw(ioaddr, RCR_REG(lp)) - -#define SMC_SET_RCR(lp, x) SMC_outw(x, ioaddr, RCR_REG(lp)) - -#define SMC_GET_REV(lp) SMC_inw(ioaddr, REV_REG(lp)) - -#define SMC_GET_RPC(lp) SMC_inw(ioaddr, RPC_REG(lp)) - -#define SMC_SET_RPC(lp, x) \ - do { \ - if (SMC_MUST_ALIGN_WRITE(lp)) \ - SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 0)); \ - else \ - SMC_outw(x, ioaddr, RPC_REG(lp)); \ - } while (0) - -#define SMC_GET_TCR(lp) SMC_inw(ioaddr, TCR_REG(lp)) - -#define SMC_SET_TCR(lp, x) SMC_outw(x, ioaddr, TCR_REG(lp)) - -#ifndef SMC_GET_MAC_ADDR -#define SMC_GET_MAC_ADDR(lp, addr) \ - do { \ - unsigned int __v; \ - __v = SMC_inw(ioaddr, ADDR0_REG(lp)); \ - addr[0] = __v; addr[1] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \ - addr[2] = __v; addr[3] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \ - addr[4] = __v; addr[5] = __v >> 8; \ - } while (0) -#endif - -#define SMC_SET_MAC_ADDR(lp, addr) \ - do { \ - SMC_outw(addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG(lp)); \ - SMC_outw(addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG(lp)); \ - SMC_outw(addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG(lp)); \ - } while (0) - -#define SMC_SET_MCAST(lp, x) \ - do { \ - const unsigned char *mt = (x); \ - SMC_outw(mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1(lp)); \ - SMC_outw(mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2(lp)); \ - SMC_outw(mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3(lp)); \ - SMC_outw(mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4(lp)); \ - } while (0) - -#define SMC_PUT_PKT_HDR(lp, status, length) \ - do { \ - if (SMC_32BIT(lp)) \ - SMC_outl((status) | (length)<<16, ioaddr, \ - DATA_REG(lp)); \ - else { \ - SMC_outw(status, ioaddr, DATA_REG(lp)); \ - SMC_outw(length, ioaddr, DATA_REG(lp)); \ - } \ - } while (0) - -#define SMC_GET_PKT_HDR(lp, status, length) \ - do { \ - if (SMC_32BIT(lp)) { \ - unsigned int __val = SMC_inl(ioaddr, DATA_REG(lp)); \ - (status) = __val & 0xffff; \ - (length) = __val >> 16; \ - } else { \ - (status) = SMC_inw(ioaddr, DATA_REG(lp)); \ - (length) = SMC_inw(ioaddr, DATA_REG(lp)); \ - } \ - } while (0) - -#define SMC_PUSH_DATA(lp, p, l) \ - do { \ - if (SMC_32BIT(lp)) { \ - void *__ptr = (p); \ - int __len = (l); \ - void __iomem *__ioaddr = ioaddr; \ - if (__len >= 2 && (unsigned long)__ptr & 2) { \ - __len -= 2; \ - SMC_outw(*(u16 *)__ptr, ioaddr, \ - DATA_REG(lp)); \ - __ptr += 2; \ - } \ - if (SMC_CAN_USE_DATACS && lp->datacs) \ - __ioaddr = lp->datacs; \ - SMC_outsl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \ - if (__len & 2) { \ - __ptr += (__len & ~3); \ - SMC_outw(*((u16 *)__ptr), ioaddr, \ - DATA_REG(lp)); \ - } \ - } else if (SMC_16BIT(lp)) \ - SMC_outsw(ioaddr, DATA_REG(lp), p, (l) >> 1); \ - else if (SMC_8BIT(lp)) \ - SMC_outsb(ioaddr, DATA_REG(lp), p, l); \ - } while (0) - -#define SMC_PULL_DATA(lp, p, l) \ - do { \ - if (SMC_32BIT(lp)) { \ - void *__ptr = (p); \ - int __len = (l); \ - void __iomem *__ioaddr = ioaddr; \ - if ((unsigned long)__ptr & 2) { \ - /* \ - * We want 32bit alignment here. \ - * Since some buses perform a full \ - * 32bit fetch even for 16bit data \ - * we can't use SMC_inw() here. \ - * Back both source (on-chip) and \ - * destination pointers of 2 bytes. \ - * This is possible since the call to \ - * SMC_GET_PKT_HDR() already advanced \ - * the source pointer of 4 bytes, and \ - * the skb_reserve(skb, 2) advanced \ - * the destination pointer of 2 bytes. \ - */ \ - __ptr -= 2; \ - __len += 2; \ - SMC_SET_PTR(lp, \ - 2|PTR_READ|PTR_RCV|PTR_AUTOINC); \ - } \ - if (SMC_CAN_USE_DATACS && lp->datacs) \ - __ioaddr = lp->datacs; \ - __len += 2; \ - SMC_insl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \ - } else if (SMC_16BIT(lp)) \ - SMC_insw(ioaddr, DATA_REG(lp), p, (l) >> 1); \ - else if (SMC_8BIT(lp)) \ - SMC_insb(ioaddr, DATA_REG(lp), p, l); \ - } while (0) - -#endif /* _SMC91X_H_ */ diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.c deleted file mode 100644 index cd3defb1..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.c +++ /dev/null @@ -1,2597 +0,0 @@ -/*************************************************************************** - * - * Copyright (C) 2004-2008 SMSC - * Copyright (C) 2005-2008 ARM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - *************************************************************************** - * Rewritten, heavily based on smsc911x simple driver by SMSC. - * Partly uses io macros from smc91x.c by Nicolas Pitre - * - * Supported devices: - * LAN9115, LAN9116, LAN9117, LAN9118 - * LAN9215, LAN9216, LAN9217, LAN9218 - * LAN9210, LAN9211 - * LAN9220, LAN9221 - * LAN89218 - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/crc32.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/platform_device.h> -#include <linux/regulator/consumer.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/bug.h> -#include <linux/bitops.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/swab.h> -#include <linux/phy.h> -#include <linux/smsc911x.h> -#include <linux/device.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <linux/of_net.h> -#include "smsc911x.h" - -#define SMSC_CHIPNAME "smsc911x" -#define SMSC_MDIONAME "smsc911x-mdio" -#define SMSC_DRV_VERSION "2008-10-21" - -MODULE_LICENSE("GPL"); -MODULE_VERSION(SMSC_DRV_VERSION); -MODULE_ALIAS("platform:smsc911x"); - -#if USE_DEBUG > 0 -static int debug = 16; -#else -static int debug = 3; -#endif - -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); - -struct smsc911x_data; - -struct smsc911x_ops { - u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg); - void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val); - void (*rx_readfifo)(struct smsc911x_data *pdata, - unsigned int *buf, unsigned int wordcount); - void (*tx_writefifo)(struct smsc911x_data *pdata, - unsigned int *buf, unsigned int wordcount); -}; - -#define SMSC911X_NUM_SUPPLIES 2 - -struct smsc911x_data { - void __iomem *ioaddr; - - unsigned int idrev; - - /* used to decide which workarounds apply */ - unsigned int generation; - - /* device configuration (copied from platform_data during probe) */ - struct smsc911x_platform_config config; - - /* This needs to be acquired before calling any of below: - * smsc911x_mac_read(), smsc911x_mac_write() - */ - spinlock_t mac_lock; - - /* spinlock to ensure register accesses are serialised */ - spinlock_t dev_lock; - - struct phy_device *phy_dev; - struct mii_bus *mii_bus; - int phy_irq[PHY_MAX_ADDR]; - unsigned int using_extphy; - int last_duplex; - int last_carrier; - - u32 msg_enable; - unsigned int gpio_setting; - unsigned int gpio_orig_setting; - struct net_device *dev; - struct napi_struct napi; - - unsigned int software_irq_signal; - -#ifdef USE_PHY_WORK_AROUND -#define MIN_PACKET_SIZE (64) - char loopback_tx_pkt[MIN_PACKET_SIZE]; - char loopback_rx_pkt[MIN_PACKET_SIZE]; - unsigned int resetcount; -#endif - - /* Members for Multicast filter workaround */ - unsigned int multicast_update_pending; - unsigned int set_bits_mask; - unsigned int clear_bits_mask; - unsigned int hashhi; - unsigned int hashlo; - - /* register access functions */ - const struct smsc911x_ops *ops; - - /* regulators */ - struct regulator_bulk_data supplies[SMSC911X_NUM_SUPPLIES]; -}; - -/* Easy access to information */ -#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift)) - -static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) - return readl(pdata->ioaddr + reg); - - if (pdata->config.flags & SMSC911X_USE_16BIT) - return ((readw(pdata->ioaddr + reg) & 0xFFFF) | - ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); - - BUG(); - return 0; -} - -static inline u32 -__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) - return readl(pdata->ioaddr + __smsc_shift(pdata, reg)); - - if (pdata->config.flags & SMSC911X_USE_16BIT) - return (readw(pdata->ioaddr + - __smsc_shift(pdata, reg)) & 0xFFFF) | - ((readw(pdata->ioaddr + - __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16); - - BUG(); - return 0; -} - -static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) -{ - u32 data; - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - data = pdata->ops->reg_read(pdata, reg); - spin_unlock_irqrestore(&pdata->dev_lock, flags); - - return data; -} - -static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, - u32 val) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writel(val, pdata->ioaddr + reg); - return; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - writew(val & 0xFFFF, pdata->ioaddr + reg); - writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); - return; - } - - BUG(); -} - -static inline void -__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val) -{ - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writel(val, pdata->ioaddr + __smsc_shift(pdata, reg)); - return; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - writew(val & 0xFFFF, - pdata->ioaddr + __smsc_shift(pdata, reg)); - writew((val >> 16) & 0xFFFF, - pdata->ioaddr + __smsc_shift(pdata, reg + 2)); - return; - } - - BUG(); -} - -static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, - u32 val) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - pdata->ops->reg_write(pdata, reg, val); - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Writes a packet to the TX_DATA_FIFO */ -static inline void -smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - __smsc911x_reg_write(pdata, TX_DATA_FIFO, - swab32(*buf++)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - __smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Writes a packet to the TX_DATA_FIFO - shifted version */ -static inline void -smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO, - swab32(*buf++)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - writesl(pdata->ioaddr + __smsc_shift(pdata, - TX_DATA_FIFO), buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - __smsc911x_reg_write_shift(pdata, - TX_DATA_FIFO, *buf++); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Reads a packet out of the RX_DATA_FIFO */ -static inline void -smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - *buf++ = swab32(__smsc911x_reg_read(pdata, - RX_DATA_FIFO)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* Reads a packet out of the RX_DATA_FIFO - shifted version */ -static inline void -smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - unsigned long flags; - - spin_lock_irqsave(&pdata->dev_lock, flags); - - if (pdata->config.flags & SMSC911X_SWAP_FIFO) { - while (wordcount--) - *buf++ = swab32(__smsc911x_reg_read_shift(pdata, - RX_DATA_FIFO)); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_32BIT) { - readsl(pdata->ioaddr + __smsc_shift(pdata, - RX_DATA_FIFO), buf, wordcount); - goto out; - } - - if (pdata->config.flags & SMSC911X_USE_16BIT) { - while (wordcount--) - *buf++ = __smsc911x_reg_read_shift(pdata, - RX_DATA_FIFO); - goto out; - } - - BUG(); -out: - spin_unlock_irqrestore(&pdata->dev_lock, flags); -} - -/* - * enable resources, currently just regulators. - */ -static int smsc911x_enable_resources(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(ndev); - int ret = 0; - - ret = regulator_bulk_enable(ARRAY_SIZE(pdata->supplies), - pdata->supplies); - if (ret) - netdev_err(ndev, "failed to enable regulators %d\n", - ret); - return ret; -} - -/* - * disable resources, currently just regulators. - */ -static int smsc911x_disable_resources(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(ndev); - int ret = 0; - - ret = regulator_bulk_disable(ARRAY_SIZE(pdata->supplies), - pdata->supplies); - return ret; -} - -/* - * Request resources, currently just regulators. - * - * The SMSC911x has two power pins: vddvario and vdd33a, in designs where - * these are not always-on we need to request regulators to be turned on - * before we can try to access the device registers. - */ -static int smsc911x_request_resources(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(ndev); - int ret = 0; - - /* Request regulators */ - pdata->supplies[0].supply = "vdd33a"; - pdata->supplies[1].supply = "vddvario"; - ret = regulator_bulk_get(&pdev->dev, - ARRAY_SIZE(pdata->supplies), - pdata->supplies); - if (ret) - netdev_err(ndev, "couldn't get regulators %d\n", - ret); - return ret; -} - -/* - * Free resources, currently just regulators. - * - */ -static void smsc911x_free_resources(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct smsc911x_data *pdata = netdev_priv(ndev); - - /* Free regulators */ - regulator_bulk_free(ARRAY_SIZE(pdata->supplies), - pdata->supplies); -} - -/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read - * and smsc911x_mac_write, so assumes mac_lock is held */ -static int smsc911x_mac_complete(struct smsc911x_data *pdata) -{ - int i; - u32 val; - - SMSC_ASSERT_MAC_LOCK(pdata); - - for (i = 0; i < 40; i++) { - val = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (!(val & MAC_CSR_CMD_CSR_BUSY_)) - return 0; - } - SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. " - "MAC_CSR_CMD: 0x%08X", val); - return -EIO; -} - -/* Fetches a MAC register value. Assumes mac_lock is acquired */ -static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) -{ - unsigned int temp; - - SMSC_ASSERT_MAC_LOCK(pdata); - - temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARN(pdata, hw, "MAC busy at entry"); - return 0xFFFFFFFF; - } - - /* Send the MAC cmd */ - smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | - MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_)); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - /* Wait for the read to complete */ - if (likely(smsc911x_mac_complete(pdata) == 0)) - return smsc911x_reg_read(pdata, MAC_CSR_DATA); - - SMSC_WARN(pdata, hw, "MAC busy after read"); - return 0xFFFFFFFF; -} - -/* Set a mac register, mac_lock must be acquired before calling */ -static void smsc911x_mac_write(struct smsc911x_data *pdata, - unsigned int offset, u32 val) -{ - unsigned int temp; - - SMSC_ASSERT_MAC_LOCK(pdata); - - temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARN(pdata, hw, - "smsc911x_mac_write failed, MAC busy at entry"); - return; - } - - /* Send data to write */ - smsc911x_reg_write(pdata, MAC_CSR_DATA, val); - - /* Write the actual data */ - smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | - MAC_CSR_CMD_CSR_BUSY_)); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - /* Wait for the write to complete */ - if (likely(smsc911x_mac_complete(pdata) == 0)) - return; - - SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write"); -} - -/* Get a phy register */ -static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) -{ - struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; - unsigned long flags; - unsigned int addr; - int i, reg; - - spin_lock_irqsave(&pdata->mac_lock, flags); - - /* Confirm MII not busy */ - if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???"); - reg = -EIO; - goto out; - } - - /* Set the address, index & direction (read from PHY) */ - addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6); - smsc911x_mac_write(pdata, MII_ACC, addr); - - /* Wait for read to complete w/ timeout */ - for (i = 0; i < 100; i++) - if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - reg = smsc911x_mac_read(pdata, MII_DATA); - goto out; - } - - SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish"); - reg = -EIO; - -out: - spin_unlock_irqrestore(&pdata->mac_lock, flags); - return reg; -} - -/* Set a phy register */ -static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, - u16 val) -{ - struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; - unsigned long flags; - unsigned int addr; - int i, reg; - - spin_lock_irqsave(&pdata->mac_lock, flags); - - /* Confirm MII not busy */ - if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???"); - reg = -EIO; - goto out; - } - - /* Put the data to write in the MAC */ - smsc911x_mac_write(pdata, MII_DATA, val); - - /* Set the address, index & direction (write to PHY) */ - addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | - MII_ACC_MII_WRITE_; - smsc911x_mac_write(pdata, MII_ACC, addr); - - /* Wait for write to complete w/ timeout */ - for (i = 0; i < 100; i++) - if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - reg = 0; - goto out; - } - - SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish"); - reg = -EIO; - -out: - spin_unlock_irqrestore(&pdata->mac_lock, flags); - return reg; -} - -/* Switch to external phy. Assumes tx and rx are stopped. */ -static void smsc911x_phy_enable_external(struct smsc911x_data *pdata) -{ - unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); - - /* Disable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); - udelay(10); /* Enough time for clocks to stop */ - - /* Switch to external phy */ - hwcfg |= HW_CFG_EXT_PHY_EN_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); - - /* Enable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); - udelay(10); /* Enough time for clocks to restart */ - - hwcfg |= HW_CFG_SMI_SEL_; - smsc911x_reg_write(pdata, HW_CFG, hwcfg); -} - -/* Autodetects and enables external phy if present on supported chips. - * autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY - * or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags. */ -static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata) -{ - unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); - - if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) { - SMSC_TRACE(pdata, hw, "Forcing internal PHY"); - pdata->using_extphy = 0; - } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) { - SMSC_TRACE(pdata, hw, "Forcing external PHY"); - smsc911x_phy_enable_external(pdata); - pdata->using_extphy = 1; - } else if (hwcfg & HW_CFG_EXT_PHY_DET_) { - SMSC_TRACE(pdata, hw, - "HW_CFG EXT_PHY_DET set, using external PHY"); - smsc911x_phy_enable_external(pdata); - pdata->using_extphy = 1; - } else { - SMSC_TRACE(pdata, hw, - "HW_CFG EXT_PHY_DET clear, using internal PHY"); - pdata->using_extphy = 0; - } -} - -/* Fetches a tx status out of the status fifo */ -static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata) -{ - unsigned int result = - smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_; - - if (result != 0) - result = smsc911x_reg_read(pdata, TX_STATUS_FIFO); - - return result; -} - -/* Fetches the next rx status */ -static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata) -{ - unsigned int result = - smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_; - - if (result != 0) - result = smsc911x_reg_read(pdata, RX_STATUS_FIFO); - - return result; -} - -#ifdef USE_PHY_WORK_AROUND -static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) -{ - unsigned int tries; - u32 wrsz; - u32 rdsz; - ulong bufp; - - for (tries = 0; tries < 10; tries++) { - unsigned int txcmd_a; - unsigned int txcmd_b; - unsigned int status; - unsigned int pktlength; - unsigned int i; - - /* Zero-out rx packet memory */ - memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE); - - /* Write tx packet to 118 */ - txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16; - txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - txcmd_a |= MIN_PACKET_SIZE; - - txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE; - - smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a); - smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b); - - bufp = (ulong)pdata->loopback_tx_pkt & (~0x3); - wrsz = MIN_PACKET_SIZE + 3; - wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); - wrsz >>= 2; - - pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); - - /* Wait till transmit is done */ - i = 60; - do { - udelay(5); - status = smsc911x_tx_get_txstatus(pdata); - } while ((i--) && (!status)); - - if (!status) { - SMSC_WARN(pdata, hw, - "Failed to transmit during loopback test"); - continue; - } - if (status & TX_STS_ES_) { - SMSC_WARN(pdata, hw, - "Transmit encountered errors during loopback test"); - continue; - } - - /* Wait till receive is done */ - i = 60; - do { - udelay(5); - status = smsc911x_rx_get_rxstatus(pdata); - } while ((i--) && (!status)); - - if (!status) { - SMSC_WARN(pdata, hw, - "Failed to receive during loopback test"); - continue; - } - if (status & RX_STS_ES_) { - SMSC_WARN(pdata, hw, - "Receive encountered errors during loopback test"); - continue; - } - - pktlength = ((status & 0x3FFF0000UL) >> 16); - bufp = (ulong)pdata->loopback_rx_pkt; - rdsz = pktlength + 3; - rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); - rdsz >>= 2; - - pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz); - - if (pktlength != (MIN_PACKET_SIZE + 4)) { - SMSC_WARN(pdata, hw, "Unexpected packet size " - "during loop back test, size=%d, will retry", - pktlength); - } else { - unsigned int j; - int mismatch = 0; - for (j = 0; j < MIN_PACKET_SIZE; j++) { - if (pdata->loopback_tx_pkt[j] - != pdata->loopback_rx_pkt[j]) { - mismatch = 1; - break; - } - } - if (!mismatch) { - SMSC_TRACE(pdata, hw, "Successfully verified " - "loopback packet"); - return 0; - } else { - SMSC_WARN(pdata, hw, "Data mismatch " - "during loop back test, will retry"); - } - } - } - - return -EIO; -} - -static int smsc911x_phy_reset(struct smsc911x_data *pdata) -{ - struct phy_device *phy_dev = pdata->phy_dev; - unsigned int temp; - unsigned int i = 100000; - - BUG_ON(!phy_dev); - BUG_ON(!phy_dev->bus); - - SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset"); - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); - do { - msleep(1); - temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, - MII_BMCR); - } while ((i--) && (temp & BMCR_RESET)); - - if (temp & BMCR_RESET) { - SMSC_WARN(pdata, hw, "PHY reset failed to complete"); - return -EIO; - } - /* Extra delay required because the phy may not be completed with - * its reset when BMCR_RESET is cleared. Specs say 256 uS is - * enough delay but using 1ms here to be safe */ - msleep(1); - - return 0; -} - -static int smsc911x_phy_loopbacktest(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phy_dev = pdata->phy_dev; - int result = -EIO; - unsigned int i, val; - unsigned long flags; - - /* Initialise tx packet using broadcast destination address */ - memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN); - - /* Use incrementing source address */ - for (i = 6; i < 12; i++) - pdata->loopback_tx_pkt[i] = (char)i; - - /* Set length type field */ - pdata->loopback_tx_pkt[12] = 0x00; - pdata->loopback_tx_pkt[13] = 0x00; - - for (i = 14; i < MIN_PACKET_SIZE; i++) - pdata->loopback_tx_pkt[i] = (char)i; - - val = smsc911x_reg_read(pdata, HW_CFG); - val &= HW_CFG_TX_FIF_SZ_; - val |= HW_CFG_SF_; - smsc911x_reg_write(pdata, HW_CFG, val); - - smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); - smsc911x_reg_write(pdata, RX_CFG, - (u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8); - - for (i = 0; i < 10; i++) { - /* Set PHY to 10/FD, no ANEG, and loopback mode */ - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, - BMCR_LOOPBACK | BMCR_FULLDPLX); - - /* Enable MAC tx/rx, FD */ - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_ - | MAC_CR_TXEN_ | MAC_CR_RXEN_); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - if (smsc911x_phy_check_loopbackpkt(pdata) == 0) { - result = 0; - break; - } - pdata->resetcount++; - - /* Disable MAC rx */ - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, 0); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - smsc911x_phy_reset(pdata); - } - - /* Disable MAC */ - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, 0); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - /* Cancel PHY loopback mode */ - smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0); - - smsc911x_reg_write(pdata, TX_CFG, 0); - smsc911x_reg_write(pdata, RX_CFG, 0); - - return result; -} -#endif /* USE_PHY_WORK_AROUND */ - -static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) -{ - struct phy_device *phy_dev = pdata->phy_dev; - u32 afc = smsc911x_reg_read(pdata, AFC_CFG); - u32 flow; - unsigned long flags; - - if (phy_dev->duplex == DUPLEX_FULL) { - u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); - u16 rmtadv = phy_read(phy_dev, MII_LPA); - u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); - - if (cap & FLOW_CTRL_RX) - flow = 0xFFFF0002; - else - flow = 0; - - if (cap & FLOW_CTRL_TX) - afc |= 0xF; - else - afc &= ~0xF; - - SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); - } else { - SMSC_TRACE(pdata, hw, "half duplex"); - flow = 0; - afc |= 0xF; - } - - spin_lock_irqsave(&pdata->mac_lock, flags); - smsc911x_mac_write(pdata, FLOW, flow); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - smsc911x_reg_write(pdata, AFC_CFG, afc); -} - -/* Update link mode if anything has changed. Called periodically when the - * PHY is in polling mode, even if nothing has changed. */ -static void smsc911x_phy_adjust_link(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phy_dev = pdata->phy_dev; - unsigned long flags; - int carrier; - - if (phy_dev->duplex != pdata->last_duplex) { - unsigned int mac_cr; - SMSC_TRACE(pdata, hw, "duplex state has changed"); - - spin_lock_irqsave(&pdata->mac_lock, flags); - mac_cr = smsc911x_mac_read(pdata, MAC_CR); - if (phy_dev->duplex) { - SMSC_TRACE(pdata, hw, - "configuring for full duplex mode"); - mac_cr |= MAC_CR_FDPX_; - } else { - SMSC_TRACE(pdata, hw, - "configuring for half duplex mode"); - mac_cr &= ~MAC_CR_FDPX_; - } - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - - smsc911x_phy_update_flowcontrol(pdata); - pdata->last_duplex = phy_dev->duplex; - } - - carrier = netif_carrier_ok(dev); - if (carrier != pdata->last_carrier) { - SMSC_TRACE(pdata, hw, "carrier state has changed"); - if (carrier) { - SMSC_TRACE(pdata, hw, "configuring for carrier OK"); - if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && - (!pdata->using_extphy)) { - /* Restore original GPIO configuration */ - pdata->gpio_setting = pdata->gpio_orig_setting; - smsc911x_reg_write(pdata, GPIO_CFG, - pdata->gpio_setting); - } - } else { - SMSC_TRACE(pdata, hw, "configuring for no carrier"); - /* Check global setting that LED1 - * usage is 10/100 indicator */ - pdata->gpio_setting = smsc911x_reg_read(pdata, - GPIO_CFG); - if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) && - (!pdata->using_extphy)) { - /* Force 10/100 LED off, after saving - * original GPIO configuration */ - pdata->gpio_orig_setting = pdata->gpio_setting; - - pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_; - pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_ - | GPIO_CFG_GPIODIR0_ - | GPIO_CFG_GPIOD0_); - smsc911x_reg_write(pdata, GPIO_CFG, - pdata->gpio_setting); - } - } - pdata->last_carrier = carrier; - } -} - -static int smsc911x_mii_probe(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phydev = NULL; - int ret; - - /* find the first phy */ - phydev = phy_find_first(pdata->mii_bus); - if (!phydev) { - netdev_err(dev, "no PHY found\n"); - return -ENODEV; - } - - SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X", - phydev->addr, phydev->phy_id); - - ret = phy_connect_direct(dev, phydev, - &smsc911x_phy_adjust_link, 0, - pdata->config.phy_interface); - - if (ret) { - netdev_err(dev, "Could not attach to PHY\n"); - return ret; - } - - netdev_info(dev, - "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - phydev->drv->name, dev_name(&phydev->dev), phydev->irq); - - /* mask with MAC supported features */ - phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - phydev->advertising = phydev->supported; - - pdata->phy_dev = phydev; - pdata->last_duplex = -1; - pdata->last_carrier = -1; - -#ifdef USE_PHY_WORK_AROUND - if (smsc911x_phy_loopbacktest(dev) < 0) { - SMSC_WARN(pdata, hw, "Failed Loop Back Test"); - return -ENODEV; - } - SMSC_TRACE(pdata, hw, "Passed Loop Back Test"); -#endif /* USE_PHY_WORK_AROUND */ - - SMSC_TRACE(pdata, hw, "phy initialised successfully"); - return 0; -} - -static int __devinit smsc911x_mii_init(struct platform_device *pdev, - struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - int err = -ENXIO, i; - - pdata->mii_bus = mdiobus_alloc(); - if (!pdata->mii_bus) { - err = -ENOMEM; - goto err_out_1; - } - - pdata->mii_bus->name = SMSC_MDIONAME; - snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", - pdev->name, pdev->id); - pdata->mii_bus->priv = pdata; - pdata->mii_bus->read = smsc911x_mii_read; - pdata->mii_bus->write = smsc911x_mii_write; - pdata->mii_bus->irq = pdata->phy_irq; - for (i = 0; i < PHY_MAX_ADDR; ++i) - pdata->mii_bus->irq[i] = PHY_POLL; - - pdata->mii_bus->parent = &pdev->dev; - - switch (pdata->idrev & 0xFFFF0000) { - case 0x01170000: - case 0x01150000: - case 0x117A0000: - case 0x115A0000: - /* External PHY supported, try to autodetect */ - smsc911x_phy_initialise_external(pdata); - break; - default: - SMSC_TRACE(pdata, hw, "External PHY is not supported, " - "using internal PHY"); - pdata->using_extphy = 0; - break; - } - - if (!pdata->using_extphy) { - /* Mask all PHYs except ID 1 (internal) */ - pdata->mii_bus->phy_mask = ~(1 << 1); - } - - if (mdiobus_register(pdata->mii_bus)) { - SMSC_WARN(pdata, probe, "Error registering mii bus"); - goto err_out_free_bus_2; - } - - if (smsc911x_mii_probe(dev) < 0) { - SMSC_WARN(pdata, probe, "Error registering mii bus"); - goto err_out_unregister_bus_3; - } - - return 0; - -err_out_unregister_bus_3: - mdiobus_unregister(pdata->mii_bus); -err_out_free_bus_2: - mdiobus_free(pdata->mii_bus); -err_out_1: - return err; -} - -/* Gets the number of tx statuses in the fifo */ -static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata) -{ - return (smsc911x_reg_read(pdata, TX_FIFO_INF) - & TX_FIFO_INF_TSUSED_) >> 16; -} - -/* Reads tx statuses and increments counters where necessary */ -static void smsc911x_tx_update_txcounters(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int tx_stat; - - while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) { - if (unlikely(tx_stat & 0x80000000)) { - /* In this driver the packet tag is used as the packet - * length. Since a packet length can never reach the - * size of 0x8000, this bit is reserved. It is worth - * noting that the "reserved bit" in the warning above - * does not reference a hardware defined reserved bit - * but rather a driver defined one. - */ - SMSC_WARN(pdata, hw, "Packet tag reserved bit is high"); - } else { - if (unlikely(tx_stat & TX_STS_ES_)) { - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += (tx_stat >> 16); - } - if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) { - dev->stats.collisions += 16; - dev->stats.tx_aborted_errors += 1; - } else { - dev->stats.collisions += - ((tx_stat >> 3) & 0xF); - } - if (unlikely(tx_stat & TX_STS_LOST_CARRIER_)) - dev->stats.tx_carrier_errors += 1; - if (unlikely(tx_stat & TX_STS_LATE_COL_)) { - dev->stats.collisions++; - dev->stats.tx_aborted_errors++; - } - } - } -} - -/* Increments the Rx error counters */ -static void -smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat) -{ - int crc_err = 0; - - if (unlikely(rxstat & RX_STS_ES_)) { - dev->stats.rx_errors++; - if (unlikely(rxstat & RX_STS_CRC_ERR_)) { - dev->stats.rx_crc_errors++; - crc_err = 1; - } - } - if (likely(!crc_err)) { - if (unlikely((rxstat & RX_STS_FRAME_TYPE_) && - (rxstat & RX_STS_LENGTH_ERR_))) - dev->stats.rx_length_errors++; - if (rxstat & RX_STS_MCAST_) - dev->stats.multicast++; - } -} - -/* Quickly dumps bad packets */ -static void -smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktwords) -{ - if (likely(pktwords >= 4)) { - unsigned int timeout = 500; - unsigned int val; - smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_); - do { - udelay(1); - val = smsc911x_reg_read(pdata, RX_DP_CTRL); - } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout); - - if (unlikely(timeout == 0)) - SMSC_WARN(pdata, hw, "Timed out waiting for " - "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); - } else { - unsigned int temp; - while (pktwords--) - temp = smsc911x_reg_read(pdata, RX_DATA_FIFO); - } -} - -/* NAPI poll function */ -static int smsc911x_poll(struct napi_struct *napi, int budget) -{ - struct smsc911x_data *pdata = - container_of(napi, struct smsc911x_data, napi); - struct net_device *dev = pdata->dev; - int npackets = 0; - - while (npackets < budget) { - unsigned int pktlength; - unsigned int pktwords; - struct sk_buff *skb; - unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata); - - if (!rxstat) { - unsigned int temp; - /* We processed all packets available. Tell NAPI it can - * stop polling then re-enable rx interrupts */ - smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_); - napi_complete(napi); - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= INT_EN_RSFL_EN_; - smsc911x_reg_write(pdata, INT_EN, temp); - break; - } - - /* Count packet for NAPI scheduling, even if it has an error. - * Error packets still require cycles to discard */ - npackets++; - - pktlength = ((rxstat & 0x3FFF0000) >> 16); - pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2; - smsc911x_rx_counterrors(dev, rxstat); - - if (unlikely(rxstat & RX_STS_ES_)) { - SMSC_WARN(pdata, rx_err, - "Discarding packet with error bit set"); - /* Packet has an error, discard it and continue with - * the next */ - smsc911x_rx_fastforward(pdata, pktwords); - dev->stats.rx_dropped++; - continue; - } - - skb = netdev_alloc_skb(dev, pktwords << 2); - if (unlikely(!skb)) { - SMSC_WARN(pdata, rx_err, - "Unable to allocate skb for rx packet"); - /* Drop the packet and stop this polling iteration */ - smsc911x_rx_fastforward(pdata, pktwords); - dev->stats.rx_dropped++; - break; - } - - pdata->ops->rx_readfifo(pdata, - (unsigned int *)skb->data, pktwords); - - /* Align IP on 16B boundary */ - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, pktlength - 4); - skb->protocol = eth_type_trans(skb, dev); - skb_checksum_none_assert(skb); - netif_receive_skb(skb); - - /* Update counters */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += (pktlength - 4); - } - - /* Return total received packets */ - return npackets; -} - -/* Returns hash bit number for given MAC address - * Example: - * 01 00 5E 00 00 01 -> returns bit number 31 */ -static unsigned int smsc911x_hash(char addr[ETH_ALEN]) -{ - return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; -} - -static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) -{ - /* Performs the multicast & mac_cr update. This is called when - * safe on the current hardware, and with the mac_lock held */ - unsigned int mac_cr; - - SMSC_ASSERT_MAC_LOCK(pdata); - - mac_cr = smsc911x_mac_read(pdata, MAC_CR); - mac_cr |= pdata->set_bits_mask; - mac_cr &= ~(pdata->clear_bits_mask); - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - smsc911x_mac_write(pdata, HASHH, pdata->hashhi); - smsc911x_mac_write(pdata, HASHL, pdata->hashlo); - SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", - mac_cr, pdata->hashhi, pdata->hashlo); -} - -static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) -{ - unsigned int mac_cr; - - /* This function is only called for older LAN911x devices - * (revA or revB), where MAC_CR, HASHH and HASHL should not - * be modified during Rx - newer devices immediately update the - * registers. - * - * This is called from interrupt context */ - - spin_lock(&pdata->mac_lock); - - /* Check Rx has stopped */ - if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) - SMSC_WARN(pdata, drv, "Rx not stopped"); - - /* Perform the update - safe to do now Rx has stopped */ - smsc911x_rx_multicast_update(pdata); - - /* Re-enable Rx */ - mac_cr = smsc911x_mac_read(pdata, MAC_CR); - mac_cr |= MAC_CR_RXEN_; - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - - pdata->multicast_update_pending = 0; - - spin_unlock(&pdata->mac_lock); -} - -static int smsc911x_phy_disable_energy_detect(struct smsc911x_data *pdata) -{ - int rc = 0; - - if (!pdata->phy_dev) - return rc; - - rc = phy_read(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS); - - if (rc < 0) { - SMSC_WARN(pdata, drv, "Failed reading PHY control reg"); - return rc; - } - - /* - * If energy is detected the PHY is already awake so is not necessary - * to disable the energy detect power-down mode. - */ - if ((rc & MII_LAN83C185_EDPWRDOWN) && - !(rc & MII_LAN83C185_ENERGYON)) { - /* Disable energy detect mode for this SMSC Transceivers */ - rc = phy_write(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS, - rc & (~MII_LAN83C185_EDPWRDOWN)); - - if (rc < 0) { - SMSC_WARN(pdata, drv, "Failed writing PHY control reg"); - return rc; - } - - mdelay(1); - } - - return 0; -} - -static int smsc911x_phy_enable_energy_detect(struct smsc911x_data *pdata) -{ - int rc = 0; - - if (!pdata->phy_dev) - return rc; - - rc = phy_read(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS); - - if (rc < 0) { - SMSC_WARN(pdata, drv, "Failed reading PHY control reg"); - return rc; - } - - /* Only enable if energy detect mode is already disabled */ - if (!(rc & MII_LAN83C185_EDPWRDOWN)) { - mdelay(100); - /* Enable energy detect mode for this SMSC Transceivers */ - rc = phy_write(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS, - rc | MII_LAN83C185_EDPWRDOWN); - - if (rc < 0) { - SMSC_WARN(pdata, drv, "Failed writing PHY control reg"); - return rc; - } - - mdelay(1); - } - return 0; -} - -static int smsc911x_soft_reset(struct smsc911x_data *pdata) -{ - unsigned int timeout; - unsigned int temp; - int ret; - - /* - * LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that - * are initialized in a Energy Detect Power-Down mode that prevents - * the MAC chip to be software reseted. So we have to wakeup the PHY - * before. - */ - if (pdata->generation == 4) { - ret = smsc911x_phy_disable_energy_detect(pdata); - - if (ret) { - SMSC_WARN(pdata, drv, "Failed to wakeup the PHY chip"); - return ret; - } - } - - /* Reset the LAN911x */ - smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_); - timeout = 10; - do { - udelay(10); - temp = smsc911x_reg_read(pdata, HW_CFG); - } while ((--timeout) && (temp & HW_CFG_SRST_)); - - if (unlikely(temp & HW_CFG_SRST_)) { - SMSC_WARN(pdata, drv, "Failed to complete reset"); - return -EIO; - } - - if (pdata->generation == 4) { - ret = smsc911x_phy_enable_energy_detect(pdata); - - if (ret) { - SMSC_WARN(pdata, drv, "Failed to wakeup the PHY chip"); - return ret; - } - } - - return 0; -} - -/* Sets the device MAC address to dev_addr, called with mac_lock held */ -static void -smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6]) -{ - u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; - u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | - (dev_addr[1] << 8) | dev_addr[0]; - - SMSC_ASSERT_MAC_LOCK(pdata); - - smsc911x_mac_write(pdata, ADDRH, mac_high16); - smsc911x_mac_write(pdata, ADDRL, mac_low32); -} - -static int smsc911x_open(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int timeout; - unsigned int temp; - unsigned int intcfg; - - /* if the phy is not yet registered, retry later*/ - if (!pdata->phy_dev) { - SMSC_WARN(pdata, hw, "phy_dev is NULL"); - return -EAGAIN; - } - - if (!is_valid_ether_addr(dev->dev_addr)) { - SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address"); - return -EADDRNOTAVAIL; - } - - /* Reset the LAN911x */ - if (smsc911x_soft_reset(pdata)) { - SMSC_WARN(pdata, hw, "soft reset failed"); - return -EIO; - } - - smsc911x_reg_write(pdata, HW_CFG, 0x00050000); - smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740); - - /* Increase the legal frame size of VLAN tagged frames to 1522 bytes */ - spin_lock_irq(&pdata->mac_lock); - smsc911x_mac_write(pdata, VLAN1, ETH_P_8021Q); - spin_unlock_irq(&pdata->mac_lock); - - /* Make sure EEPROM has finished loading before setting GPIO_CFG */ - timeout = 50; - while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) && - --timeout) { - udelay(10); - } - - if (unlikely(timeout == 0)) - SMSC_WARN(pdata, ifup, - "Timed out waiting for EEPROM busy bit to clear"); - - smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000); - - /* The soft reset above cleared the device's MAC address, - * restore it from local copy (set in probe) */ - spin_lock_irq(&pdata->mac_lock); - smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - spin_unlock_irq(&pdata->mac_lock); - - /* Initialise irqs, but leave all sources disabled */ - smsc911x_reg_write(pdata, INT_EN, 0); - smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); - - /* Set interrupt deassertion to 100uS */ - intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); - - if (pdata->config.irq_polarity) { - SMSC_TRACE(pdata, ifup, "irq polarity: active high"); - intcfg |= INT_CFG_IRQ_POL_; - } else { - SMSC_TRACE(pdata, ifup, "irq polarity: active low"); - } - - if (pdata->config.irq_type) { - SMSC_TRACE(pdata, ifup, "irq type: push-pull"); - intcfg |= INT_CFG_IRQ_TYPE_; - } else { - SMSC_TRACE(pdata, ifup, "irq type: open drain"); - } - - smsc911x_reg_write(pdata, INT_CFG, intcfg); - - SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq); - pdata->software_irq_signal = 0; - smp_wmb(); - - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= INT_EN_SW_INT_EN_; - smsc911x_reg_write(pdata, INT_EN, temp); - - timeout = 1000; - while (timeout--) { - if (pdata->software_irq_signal) - break; - msleep(1); - } - - if (!pdata->software_irq_signal) { - netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n", - dev->irq); - return -ENODEV; - } - SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d", - dev->irq); - - netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", - (unsigned long)pdata->ioaddr, dev->irq); - - /* Reset the last known duplex and carrier */ - pdata->last_duplex = -1; - pdata->last_carrier = -1; - - /* Bring the PHY up */ - phy_start(pdata->phy_dev); - - temp = smsc911x_reg_read(pdata, HW_CFG); - /* Preserve TX FIFO size and external PHY configuration */ - temp &= (HW_CFG_TX_FIF_SZ_|0x00000FFF); - temp |= HW_CFG_SF_; - smsc911x_reg_write(pdata, HW_CFG, temp); - - temp = smsc911x_reg_read(pdata, FIFO_INT); - temp |= FIFO_INT_TX_AVAIL_LEVEL_; - temp &= ~(FIFO_INT_RX_STS_LEVEL_); - smsc911x_reg_write(pdata, FIFO_INT, temp); - - /* set RX Data offset to 2 bytes for alignment */ - smsc911x_reg_write(pdata, RX_CFG, (NET_IP_ALIGN << 8)); - - /* enable NAPI polling before enabling RX interrupts */ - napi_enable(&pdata->napi); - - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RXSTOP_INT_EN_); - smsc911x_reg_write(pdata, INT_EN, temp); - - spin_lock_irq(&pdata->mac_lock); - temp = smsc911x_mac_read(pdata, MAC_CR); - temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_); - smsc911x_mac_write(pdata, MAC_CR, temp); - spin_unlock_irq(&pdata->mac_lock); - - smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); - - netif_start_queue(dev); - return 0; -} - -/* Entry point for stopping the interface */ -static int smsc911x_stop(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int temp; - - /* Disable all device interrupts */ - temp = smsc911x_reg_read(pdata, INT_CFG); - temp &= ~INT_CFG_IRQ_EN_; - smsc911x_reg_write(pdata, INT_CFG, temp); - - /* Stop Tx and Rx polling */ - netif_stop_queue(dev); - napi_disable(&pdata->napi); - - /* At this point all Rx and Tx activity is stopped */ - dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); - smsc911x_tx_update_txcounters(dev); - - /* Bring the PHY down */ - if (pdata->phy_dev) - phy_stop(pdata->phy_dev); - - SMSC_TRACE(pdata, ifdown, "Interface stopped"); - return 0; -} - -/* Entry point for transmitting a packet */ -static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int freespace; - unsigned int tx_cmd_a; - unsigned int tx_cmd_b; - unsigned int temp; - u32 wrsz; - ulong bufp; - - freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; - - if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) - SMSC_WARN(pdata, tx_err, - "Tx data fifo low, space available: %d", freespace); - - /* Word alignment adjustment */ - tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16; - tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - tx_cmd_a |= (unsigned int)skb->len; - - tx_cmd_b = ((unsigned int)skb->len) << 16; - tx_cmd_b |= (unsigned int)skb->len; - - smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_a); - smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_b); - - bufp = (ulong)skb->data & (~0x3); - wrsz = (u32)skb->len + 3; - wrsz += (u32)((ulong)skb->data & 0x3); - wrsz >>= 2; - - pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz); - freespace -= (skb->len + 32); - skb_tx_timestamp(skb); - dev_kfree_skb(skb); - - if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30)) - smsc911x_tx_update_txcounters(dev); - - if (freespace < TX_FIFO_LOW_THRESHOLD) { - netif_stop_queue(dev); - temp = smsc911x_reg_read(pdata, FIFO_INT); - temp &= 0x00FFFFFF; - temp |= 0x32000000; - smsc911x_reg_write(pdata, FIFO_INT, temp); - } - - return NETDEV_TX_OK; -} - -/* Entry point for getting status counters */ -static struct net_device_stats *smsc911x_get_stats(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - smsc911x_tx_update_txcounters(dev); - dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); - return &dev->stats; -} - -/* Entry point for setting addressing modes */ -static void smsc911x_set_multicast_list(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned long flags; - - if (dev->flags & IFF_PROMISC) { - /* Enabling promiscuous mode */ - pdata->set_bits_mask = MAC_CR_PRMS_; - pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_); - pdata->hashhi = 0; - pdata->hashlo = 0; - } else if (dev->flags & IFF_ALLMULTI) { - /* Enabling all multicast mode */ - pdata->set_bits_mask = MAC_CR_MCPAS_; - pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_); - pdata->hashhi = 0; - pdata->hashlo = 0; - } else if (!netdev_mc_empty(dev)) { - /* Enabling specific multicast addresses */ - unsigned int hash_high = 0; - unsigned int hash_low = 0; - struct netdev_hw_addr *ha; - - pdata->set_bits_mask = MAC_CR_HPFILT_; - pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - netdev_for_each_mc_addr(ha, dev) { - unsigned int bitnum = smsc911x_hash(ha->addr); - unsigned int mask = 0x01 << (bitnum & 0x1F); - - if (bitnum & 0x20) - hash_high |= mask; - else - hash_low |= mask; - } - - pdata->hashhi = hash_high; - pdata->hashlo = hash_low; - } else { - /* Enabling local MAC address only */ - pdata->set_bits_mask = 0; - pdata->clear_bits_mask = - (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); - pdata->hashhi = 0; - pdata->hashlo = 0; - } - - spin_lock_irqsave(&pdata->mac_lock, flags); - - if (pdata->generation <= 1) { - /* Older hardware revision - cannot change these flags while - * receiving data */ - if (!pdata->multicast_update_pending) { - unsigned int temp; - SMSC_TRACE(pdata, hw, "scheduling mcast update"); - pdata->multicast_update_pending = 1; - - /* Request the hardware to stop, then perform the - * update when we get an RX_STOP interrupt */ - temp = smsc911x_mac_read(pdata, MAC_CR); - temp &= ~(MAC_CR_RXEN_); - smsc911x_mac_write(pdata, MAC_CR, temp); - } else { - /* There is another update pending, this should now - * use the newer values */ - } - } else { - /* Newer hardware revision - can write immediately */ - smsc911x_rx_multicast_update(pdata); - } - - spin_unlock_irqrestore(&pdata->mac_lock, flags); -} - -static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smsc911x_data *pdata = netdev_priv(dev); - u32 intsts = smsc911x_reg_read(pdata, INT_STS); - u32 inten = smsc911x_reg_read(pdata, INT_EN); - int serviced = IRQ_NONE; - u32 temp; - - if (unlikely(intsts & inten & INT_STS_SW_INT_)) { - temp = smsc911x_reg_read(pdata, INT_EN); - temp &= (~INT_EN_SW_INT_EN_); - smsc911x_reg_write(pdata, INT_EN, temp); - smsc911x_reg_write(pdata, INT_STS, INT_STS_SW_INT_); - pdata->software_irq_signal = 1; - smp_wmb(); - serviced = IRQ_HANDLED; - } - - if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { - /* Called when there is a multicast update scheduled and - * it is now safe to complete the update */ - SMSC_TRACE(pdata, intr, "RX Stop interrupt"); - smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); - if (pdata->multicast_update_pending) - smsc911x_rx_multicast_update_workaround(pdata); - serviced = IRQ_HANDLED; - } - - if (intsts & inten & INT_STS_TDFA_) { - temp = smsc911x_reg_read(pdata, FIFO_INT); - temp |= FIFO_INT_TX_AVAIL_LEVEL_; - smsc911x_reg_write(pdata, FIFO_INT, temp); - smsc911x_reg_write(pdata, INT_STS, INT_STS_TDFA_); - netif_wake_queue(dev); - serviced = IRQ_HANDLED; - } - - if (unlikely(intsts & inten & INT_STS_RXE_)) { - SMSC_TRACE(pdata, intr, "RX Error interrupt"); - smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_); - serviced = IRQ_HANDLED; - } - - if (likely(intsts & inten & INT_STS_RSFL_)) { - if (likely(napi_schedule_prep(&pdata->napi))) { - /* Disable Rx interrupts */ - temp = smsc911x_reg_read(pdata, INT_EN); - temp &= (~INT_EN_RSFL_EN_); - smsc911x_reg_write(pdata, INT_EN, temp); - /* Schedule a NAPI poll */ - __napi_schedule(&pdata->napi); - } else { - SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed"); - } - serviced = IRQ_HANDLED; - } - - return serviced; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void smsc911x_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - smsc911x_irqhandler(0, dev); - enable_irq(dev->irq); -} -#endif /* CONFIG_NET_POLL_CONTROLLER */ - -static int smsc911x_set_mac_address(struct net_device *dev, void *p) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct sockaddr *addr = p; - - /* On older hardware revisions we cannot change the mac address - * registers while receiving data. Newer devices can safely change - * this at any time. */ - if (pdata->generation <= 1 && netif_running(dev)) - return -EBUSY; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - dev->addr_assign_type &= ~NET_ADDR_RANDOM; - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); - - spin_lock_irq(&pdata->mac_lock); - smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - spin_unlock_irq(&pdata->mac_lock); - - netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); - - return 0; -} - -/* Standard ioctls for mii-tool */ -static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - if (!netif_running(dev) || !pdata->phy_dev) - return -EINVAL; - - return phy_mii_ioctl(pdata->phy_dev, ifr, cmd); -} - -static int -smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - cmd->maxtxpkt = 1; - cmd->maxrxpkt = 1; - return phy_ethtool_gset(pdata->phy_dev, cmd); -} - -static int -smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - return phy_ethtool_sset(pdata->phy_dev, cmd); -} - -static void smsc911x_ethtool_getdrvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver)); - strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev_name(dev->dev.parent), - sizeof(info->bus_info)); -} - -static int smsc911x_ethtool_nwayreset(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - return phy_start_aneg(pdata->phy_dev); -} - -static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - return pdata->msg_enable; -} - -static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - pdata->msg_enable = level; -} - -static int smsc911x_ethtool_getregslen(struct net_device *dev) -{ - return (((E2P_DATA - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) * - sizeof(u32); -} - -static void -smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - struct phy_device *phy_dev = pdata->phy_dev; - unsigned long flags; - unsigned int i; - unsigned int j = 0; - u32 *data = buf; - - regs->version = pdata->idrev; - for (i = ID_REV; i <= E2P_DATA; i += (sizeof(u32))) - data[j++] = smsc911x_reg_read(pdata, i); - - for (i = MAC_CR; i <= WUCSR; i++) { - spin_lock_irqsave(&pdata->mac_lock, flags); - data[j++] = smsc911x_mac_read(pdata, i); - spin_unlock_irqrestore(&pdata->mac_lock, flags); - } - - for (i = 0; i <= 31; i++) - data[j++] = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, i); -} - -static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata) -{ - unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG); - temp &= ~GPIO_CFG_EEPR_EN_; - smsc911x_reg_write(pdata, GPIO_CFG, temp); - msleep(1); -} - -static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) -{ - int timeout = 100; - u32 e2cmd; - - SMSC_TRACE(pdata, drv, "op 0x%08x", op); - if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - SMSC_WARN(pdata, drv, "Busy at start"); - return -EBUSY; - } - - e2cmd = op | E2P_CMD_EPC_BUSY_; - smsc911x_reg_write(pdata, E2P_CMD, e2cmd); - - do { - msleep(1); - e2cmd = smsc911x_reg_read(pdata, E2P_CMD); - } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); - - if (!timeout) { - SMSC_TRACE(pdata, drv, "TIMED OUT"); - return -EAGAIN; - } - - if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - SMSC_TRACE(pdata, drv, "Error occurred during eeprom operation"); - return -EINVAL; - } - - return 0; -} - -static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, - u8 address, u8 *data) -{ - u32 op = E2P_CMD_EPC_CMD_READ_ | address; - int ret; - - SMSC_TRACE(pdata, drv, "address 0x%x", address); - ret = smsc911x_eeprom_send_cmd(pdata, op); - - if (!ret) - data[address] = smsc911x_reg_read(pdata, E2P_DATA); - - return ret; -} - -static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, - u8 address, u8 data) -{ - u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; - u32 temp; - int ret; - - SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data); - ret = smsc911x_eeprom_send_cmd(pdata, op); - - if (!ret) { - op = E2P_CMD_EPC_CMD_WRITE_ | address; - smsc911x_reg_write(pdata, E2P_DATA, (u32)data); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - ret = smsc911x_eeprom_send_cmd(pdata, op); - } - - return ret; -} - -static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev) -{ - return SMSC911X_EEPROM_SIZE; -} - -static int smsc911x_ethtool_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - u8 eeprom_data[SMSC911X_EEPROM_SIZE]; - int len; - int i; - - smsc911x_eeprom_enable_access(pdata); - - len = min(eeprom->len, SMSC911X_EEPROM_SIZE); - for (i = 0; i < len; i++) { - int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data); - if (ret < 0) { - eeprom->len = 0; - return ret; - } - } - - memcpy(data, &eeprom_data[eeprom->offset], len); - eeprom->len = len; - return 0; -} - -static int smsc911x_ethtool_set_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - int ret; - struct smsc911x_data *pdata = netdev_priv(dev); - - smsc911x_eeprom_enable_access(pdata); - smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_); - ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data); - smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_); - - /* Single byte write, according to man page */ - eeprom->len = 1; - - return ret; -} - -static const struct ethtool_ops smsc911x_ethtool_ops = { - .get_settings = smsc911x_ethtool_getsettings, - .set_settings = smsc911x_ethtool_setsettings, - .get_link = ethtool_op_get_link, - .get_drvinfo = smsc911x_ethtool_getdrvinfo, - .nway_reset = smsc911x_ethtool_nwayreset, - .get_msglevel = smsc911x_ethtool_getmsglevel, - .set_msglevel = smsc911x_ethtool_setmsglevel, - .get_regs_len = smsc911x_ethtool_getregslen, - .get_regs = smsc911x_ethtool_getregs, - .get_eeprom_len = smsc911x_ethtool_get_eeprom_len, - .get_eeprom = smsc911x_ethtool_get_eeprom, - .set_eeprom = smsc911x_ethtool_set_eeprom, -}; - -static const struct net_device_ops smsc911x_netdev_ops = { - .ndo_open = smsc911x_open, - .ndo_stop = smsc911x_stop, - .ndo_start_xmit = smsc911x_hard_start_xmit, - .ndo_get_stats = smsc911x_get_stats, - .ndo_set_rx_mode = smsc911x_set_multicast_list, - .ndo_do_ioctl = smsc911x_do_ioctl, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = smsc911x_set_mac_address, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = smsc911x_poll_controller, -#endif -}; - -/* copies the current mac address from hardware to dev->dev_addr */ -static void __devinit smsc911x_read_mac_address(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH); - u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL); - - dev->dev_addr[0] = (u8)(mac_low32); - dev->dev_addr[1] = (u8)(mac_low32 >> 8); - dev->dev_addr[2] = (u8)(mac_low32 >> 16); - dev->dev_addr[3] = (u8)(mac_low32 >> 24); - dev->dev_addr[4] = (u8)(mac_high16); - dev->dev_addr[5] = (u8)(mac_high16 >> 8); -} - -/* Initializing private device structures, only called from probe */ -static int __devinit smsc911x_init(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int byte_test; - unsigned int to = 100; - - SMSC_TRACE(pdata, probe, "Driver Parameters:"); - SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX", - (unsigned long)pdata->ioaddr); - SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq); - SMSC_TRACE(pdata, probe, "PHY will be autodetected."); - - spin_lock_init(&pdata->dev_lock); - spin_lock_init(&pdata->mac_lock); - - if (pdata->ioaddr == 0) { - SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000"); - return -ENODEV; - } - - /* - * poll the READY bit in PMT_CTRL. Any other access to the device is - * forbidden while this bit isn't set. Try for 100ms - */ - while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) - udelay(1000); - if (to == 0) { - pr_err("Device not READY in 100ms aborting\n"); - return -ENODEV; - } - - /* Check byte ordering */ - byte_test = smsc911x_reg_read(pdata, BYTE_TEST); - SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test); - if (byte_test == 0x43218765) { - SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, " - "applying WORD_SWAP"); - smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff); - - /* 1 dummy read of BYTE_TEST is needed after a write to - * WORD_SWAP before its contents are valid */ - byte_test = smsc911x_reg_read(pdata, BYTE_TEST); - - byte_test = smsc911x_reg_read(pdata, BYTE_TEST); - } - - if (byte_test != 0x87654321) { - SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test); - if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) { - SMSC_WARN(pdata, probe, - "top 16 bits equal to bottom 16 bits"); - SMSC_TRACE(pdata, probe, - "This may mean the chip is set " - "for 32 bit while the bus is reading 16 bit"); - } - return -ENODEV; - } - - /* Default generation to zero (all workarounds apply) */ - pdata->generation = 0; - - pdata->idrev = smsc911x_reg_read(pdata, ID_REV); - switch (pdata->idrev & 0xFFFF0000) { - case 0x01180000: - case 0x01170000: - case 0x01160000: - case 0x01150000: - case 0x218A0000: - /* LAN911[5678] family */ - pdata->generation = pdata->idrev & 0x0000FFFF; - break; - - case 0x118A0000: - case 0x117A0000: - case 0x116A0000: - case 0x115A0000: - /* LAN921[5678] family */ - pdata->generation = 3; - break; - - case 0x92100000: - case 0x92110000: - case 0x92200000: - case 0x92210000: - /* LAN9210/LAN9211/LAN9220/LAN9221 */ - pdata->generation = 4; - break; - - default: - SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X", - pdata->idrev); - return -ENODEV; - } - - SMSC_TRACE(pdata, probe, - "LAN911x identified, idrev: 0x%08X, generation: %d", - pdata->idrev, pdata->generation); - - if (pdata->generation == 0) - SMSC_WARN(pdata, probe, - "This driver is not intended for this chip revision"); - - /* workaround for platforms without an eeprom, where the mac address - * is stored elsewhere and set by the bootloader. This saves the - * mac address before resetting the device */ - if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) { - spin_lock_irq(&pdata->mac_lock); - smsc911x_read_mac_address(dev); - spin_unlock_irq(&pdata->mac_lock); - } - - /* Reset the LAN911x */ - if (smsc911x_soft_reset(pdata)) - return -ENODEV; - - /* Disable all interrupt sources until we bring the device up */ - smsc911x_reg_write(pdata, INT_EN, 0); - - ether_setup(dev); - dev->flags |= IFF_MULTICAST; - netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT); - dev->netdev_ops = &smsc911x_netdev_ops; - dev->ethtool_ops = &smsc911x_ethtool_ops; - - return 0; -} - -static int __devexit smsc911x_drv_remove(struct platform_device *pdev) -{ - struct net_device *dev; - struct smsc911x_data *pdata; - struct resource *res; - - dev = platform_get_drvdata(pdev); - BUG_ON(!dev); - pdata = netdev_priv(dev); - BUG_ON(!pdata); - BUG_ON(!pdata->ioaddr); - BUG_ON(!pdata->phy_dev); - - SMSC_TRACE(pdata, ifdown, "Stopping driver"); - - phy_disconnect(pdata->phy_dev); - pdata->phy_dev = NULL; - mdiobus_unregister(pdata->mii_bus); - mdiobus_free(pdata->mii_bus); - - platform_set_drvdata(pdev, NULL); - unregister_netdev(dev); - free_irq(dev->irq, dev); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "smsc911x-memory"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - release_mem_region(res->start, resource_size(res)); - - iounmap(pdata->ioaddr); - - (void)smsc911x_disable_resources(pdev); - smsc911x_free_resources(pdev); - - free_netdev(dev); - - return 0; -} - -/* standard register acces */ -static const struct smsc911x_ops standard_smsc911x_ops = { - .reg_read = __smsc911x_reg_read, - .reg_write = __smsc911x_reg_write, - .rx_readfifo = smsc911x_rx_readfifo, - .tx_writefifo = smsc911x_tx_writefifo, -}; - -/* shifted register access */ -static const struct smsc911x_ops shifted_smsc911x_ops = { - .reg_read = __smsc911x_reg_read_shift, - .reg_write = __smsc911x_reg_write_shift, - .rx_readfifo = smsc911x_rx_readfifo_shift, - .tx_writefifo = smsc911x_tx_writefifo_shift, -}; - -#ifdef CONFIG_OF -static int __devinit smsc911x_probe_config_dt( - struct smsc911x_platform_config *config, - struct device_node *np) -{ - const char *mac; - u32 width = 0; - - if (!np) - return -ENODEV; - - config->phy_interface = of_get_phy_mode(np); - - mac = of_get_mac_address(np); - if (mac) - memcpy(config->mac, mac, ETH_ALEN); - - of_property_read_u32(np, "reg-shift", &config->shift); - - of_property_read_u32(np, "reg-io-width", &width); - if (width == 4) - config->flags |= SMSC911X_USE_32BIT; - else - config->flags |= SMSC911X_USE_16BIT; - - if (of_get_property(np, "smsc,irq-active-high", NULL)) - config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH; - - if (of_get_property(np, "smsc,irq-push-pull", NULL)) - config->irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL; - - if (of_get_property(np, "smsc,force-internal-phy", NULL)) - config->flags |= SMSC911X_FORCE_INTERNAL_PHY; - - if (of_get_property(np, "smsc,force-external-phy", NULL)) - config->flags |= SMSC911X_FORCE_EXTERNAL_PHY; - - if (of_get_property(np, "smsc,save-mac-address", NULL)) - config->flags |= SMSC911X_SAVE_MAC_ADDRESS; - - return 0; -} -#else -static inline int smsc911x_probe_config_dt( - struct smsc911x_platform_config *config, - struct device_node *np) -{ - return -ENODEV; -} -#endif /* CONFIG_OF */ - -static int __devinit smsc911x_drv_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct net_device *dev; - struct smsc911x_data *pdata; - struct smsc911x_platform_config *config = pdev->dev.platform_data; - struct resource *res, *irq_res; - unsigned int intcfg = 0; - int res_size, irq_flags; - int retval; - - pr_info("Driver version %s\n", SMSC_DRV_VERSION); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "smsc911x-memory"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - pr_warn("Could not allocate resource\n"); - retval = -ENODEV; - goto out_0; - } - res_size = resource_size(res); - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { - pr_warn("Could not allocate irq resource\n"); - retval = -ENODEV; - goto out_0; - } - - if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) { - retval = -EBUSY; - goto out_0; - } - - dev = alloc_etherdev(sizeof(struct smsc911x_data)); - if (!dev) { - retval = -ENOMEM; - goto out_release_io_1; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - - pdata = netdev_priv(dev); - dev->irq = irq_res->start; - irq_flags = irq_res->flags & IRQF_TRIGGER_MASK; - pdata->ioaddr = ioremap_nocache(res->start, res_size); - - pdata->dev = dev; - pdata->msg_enable = ((1 << debug) - 1); - - platform_set_drvdata(pdev, dev); - - retval = smsc911x_request_resources(pdev); - if (retval) - goto out_return_resources; - - retval = smsc911x_enable_resources(pdev); - if (retval) - goto out_disable_resources; - - if (pdata->ioaddr == NULL) { - SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); - retval = -ENOMEM; - goto out_disable_resources; - } - - retval = smsc911x_probe_config_dt(&pdata->config, np); - if (retval && config) { - /* copy config parameters across to pdata */ - memcpy(&pdata->config, config, sizeof(pdata->config)); - retval = 0; - } - - if (retval) { - SMSC_WARN(pdata, probe, "Error smsc911x config not found"); - goto out_disable_resources; - } - - /* assume standard, non-shifted, access to HW registers */ - pdata->ops = &standard_smsc911x_ops; - /* apply the right access if shifting is needed */ - if (pdata->config.shift) - pdata->ops = &shifted_smsc911x_ops; - - retval = smsc911x_init(dev); - if (retval < 0) - goto out_disable_resources; - - /* configure irq polarity and type before connecting isr */ - if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) - intcfg |= INT_CFG_IRQ_POL_; - - if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL) - intcfg |= INT_CFG_IRQ_TYPE_; - - smsc911x_reg_write(pdata, INT_CFG, intcfg); - - /* Ensure interrupts are globally disabled before connecting ISR */ - smsc911x_reg_write(pdata, INT_EN, 0); - smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); - - retval = request_irq(dev->irq, smsc911x_irqhandler, - irq_flags | IRQF_SHARED, dev->name, dev); - if (retval) { - SMSC_WARN(pdata, probe, - "Unable to claim requested irq: %d", dev->irq); - goto out_disable_resources; - } - - retval = register_netdev(dev); - if (retval) { - SMSC_WARN(pdata, probe, "Error %i registering device", retval); - goto out_free_irq; - } else { - SMSC_TRACE(pdata, probe, - "Network interface: \"%s\"", dev->name); - } - - retval = smsc911x_mii_init(pdev, dev); - if (retval) { - SMSC_WARN(pdata, probe, "Error %i initialising mii", retval); - goto out_unregister_netdev_5; - } - - spin_lock_irq(&pdata->mac_lock); - - /* Check if mac address has been specified when bringing interface up */ - if (is_valid_ether_addr(dev->dev_addr)) { - smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(pdata, probe, - "MAC Address is specified by configuration"); - } else if (is_valid_ether_addr(pdata->config.mac)) { - memcpy(dev->dev_addr, pdata->config.mac, 6); - SMSC_TRACE(pdata, probe, - "MAC Address specified by platform data"); - } else { - /* Try reading mac address from device. if EEPROM is present - * it will already have been set */ - smsc_get_mac(dev); - - if (is_valid_ether_addr(dev->dev_addr)) { - /* eeprom values are valid so use them */ - SMSC_TRACE(pdata, probe, - "Mac Address is read from LAN911x EEPROM"); - } else { - /* eeprom values are invalid, generate random MAC */ - eth_hw_addr_random(dev); - smsc911x_set_hw_mac_address(pdata, dev->dev_addr); - SMSC_TRACE(pdata, probe, - "MAC Address is set to random_ether_addr"); - } - } - - spin_unlock_irq(&pdata->mac_lock); - - netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr); - - return 0; - -out_unregister_netdev_5: - unregister_netdev(dev); -out_free_irq: - free_irq(dev->irq, dev); -out_disable_resources: - (void)smsc911x_disable_resources(pdev); -out_return_resources: - smsc911x_free_resources(pdev); - platform_set_drvdata(pdev, NULL); - iounmap(pdata->ioaddr); - free_netdev(dev); -out_release_io_1: - release_mem_region(res->start, resource_size(res)); -out_0: - return retval; -} - -#ifdef CONFIG_PM -/* This implementation assumes the devices remains powered on its VDDVARIO - * pins during suspend. */ - -/* TODO: implement freeze/thaw callbacks for hibernation.*/ - -static int smsc911x_suspend(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct smsc911x_data *pdata = netdev_priv(ndev); - - /* enable wake on LAN, energy detection and the external PME - * signal. */ - smsc911x_reg_write(pdata, PMT_CTRL, - PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ | - PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_); - - return 0; -} - -static int smsc911x_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct smsc911x_data *pdata = netdev_priv(ndev); - unsigned int to = 100; - - /* Note 3.11 from the datasheet: - * "When the LAN9220 is in a power saving state, a write of any - * data to the BYTE_TEST register will wake-up the device." - */ - smsc911x_reg_write(pdata, BYTE_TEST, 0); - - /* poll the READY bit in PMT_CTRL. Any other access to the device is - * forbidden while this bit isn't set. Try for 100ms and return -EIO - * if it failed. */ - while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) - udelay(1000); - - return (to == 0) ? -EIO : 0; -} - -static const struct dev_pm_ops smsc911x_pm_ops = { - .suspend = smsc911x_suspend, - .resume = smsc911x_resume, -}; - -#define SMSC911X_PM_OPS (&smsc911x_pm_ops) - -#else -#define SMSC911X_PM_OPS NULL -#endif - -static const struct of_device_id smsc911x_dt_ids[] = { - { .compatible = "smsc,lan9115", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, smsc911x_dt_ids); - -static struct platform_driver smsc911x_driver = { - .probe = smsc911x_drv_probe, - .remove = __devexit_p(smsc911x_drv_remove), - .driver = { - .name = SMSC_CHIPNAME, - .owner = THIS_MODULE, - .pm = SMSC911X_PM_OPS, - .of_match_table = smsc911x_dt_ids, - }, -}; - -/* Entry point for loading the module */ -static int __init smsc911x_init_module(void) -{ - SMSC_INITIALIZE(); - return platform_driver_register(&smsc911x_driver); -} - -/* entry point for unloading the module */ -static void __exit smsc911x_cleanup_module(void) -{ - platform_driver_unregister(&smsc911x_driver); -} - -module_init(smsc911x_init_module); -module_exit(smsc911x_cleanup_module); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.h b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.h deleted file mode 100644 index 9ad5e5d3..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc911x.h +++ /dev/null @@ -1,406 +0,0 @@ -/*************************************************************************** - * - * Copyright (C) 2004-2008 SMSC - * Copyright (C) 2005-2008 ARM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ***************************************************************************/ -#ifndef __SMSC911X_H__ -#define __SMSC911X_H__ - -#define TX_FIFO_LOW_THRESHOLD ((u32)1600) -#define SMSC911X_EEPROM_SIZE ((u32)128) -#define USE_DEBUG 0 - -/* This is the maximum number of packets to be received every - * NAPI poll */ -#define SMSC_NAPI_WEIGHT 16 - -/* implements a PHY loopback test at initialisation time, to ensure a packet - * can be successfully looped back */ -#define USE_PHY_WORK_AROUND - -#if USE_DEBUG >= 1 -#define SMSC_WARN(pdata, nlevel, fmt, args...) \ - netif_warn(pdata, nlevel, (pdata)->dev, \ - "%s: " fmt "\n", __func__, ##args) -#else -#define SMSC_WARN(pdata, nlevel, fmt, args...) \ - no_printk(fmt "\n", ##args) -#endif - -#if USE_DEBUG >= 2 -#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ - netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args) -#else -#define SMSC_TRACE(pdata, nlevel, fmt, args...) \ - no_printk(fmt "\n", ##args) -#endif - -#ifdef CONFIG_DEBUG_SPINLOCK -#define SMSC_ASSERT_MAC_LOCK(pdata) \ - WARN_ON(!spin_is_locked(&pdata->mac_lock)) -#else -#define SMSC_ASSERT_MAC_LOCK(pdata) do {} while (0) -#endif /* CONFIG_DEBUG_SPINLOCK */ - -/* SMSC911x registers and bitfields */ -#define RX_DATA_FIFO 0x00 - -#define TX_DATA_FIFO 0x20 -#define TX_CMD_A_ON_COMP_ 0x80000000 -#define TX_CMD_A_BUF_END_ALGN_ 0x03000000 -#define TX_CMD_A_4_BYTE_ALGN_ 0x00000000 -#define TX_CMD_A_16_BYTE_ALGN_ 0x01000000 -#define TX_CMD_A_32_BYTE_ALGN_ 0x02000000 -#define TX_CMD_A_DATA_OFFSET_ 0x001F0000 -#define TX_CMD_A_FIRST_SEG_ 0x00002000 -#define TX_CMD_A_LAST_SEG_ 0x00001000 -#define TX_CMD_A_BUF_SIZE_ 0x000007FF -#define TX_CMD_B_PKT_TAG_ 0xFFFF0000 -#define TX_CMD_B_ADD_CRC_DISABLE_ 0x00002000 -#define TX_CMD_B_DISABLE_PADDING_ 0x00001000 -#define TX_CMD_B_PKT_BYTE_LENGTH_ 0x000007FF - -#define RX_STATUS_FIFO 0x40 -#define RX_STS_ES_ 0x00008000 -#define RX_STS_LENGTH_ERR_ 0x00001000 -#define RX_STS_MCAST_ 0x00000400 -#define RX_STS_FRAME_TYPE_ 0x00000020 -#define RX_STS_CRC_ERR_ 0x00000002 - -#define RX_STATUS_FIFO_PEEK 0x44 - -#define TX_STATUS_FIFO 0x48 -#define TX_STS_ES_ 0x00008000 -#define TX_STS_LOST_CARRIER_ 0x00000800 -#define TX_STS_NO_CARRIER_ 0x00000400 -#define TX_STS_LATE_COL_ 0x00000200 -#define TX_STS_EXCESS_COL_ 0x00000100 - -#define TX_STATUS_FIFO_PEEK 0x4C - -#define ID_REV 0x50 -#define ID_REV_CHIP_ID_ 0xFFFF0000 -#define ID_REV_REV_ID_ 0x0000FFFF - -#define INT_CFG 0x54 -#define INT_CFG_INT_DEAS_ 0xFF000000 -#define INT_CFG_INT_DEAS_CLR_ 0x00004000 -#define INT_CFG_INT_DEAS_STS_ 0x00002000 -#define INT_CFG_IRQ_INT_ 0x00001000 -#define INT_CFG_IRQ_EN_ 0x00000100 -#define INT_CFG_IRQ_POL_ 0x00000010 -#define INT_CFG_IRQ_TYPE_ 0x00000001 - -#define INT_STS 0x58 -#define INT_STS_SW_INT_ 0x80000000 -#define INT_STS_TXSTOP_INT_ 0x02000000 -#define INT_STS_RXSTOP_INT_ 0x01000000 -#define INT_STS_RXDFH_INT_ 0x00800000 -#define INT_STS_RXDF_INT_ 0x00400000 -#define INT_STS_TX_IOC_ 0x00200000 -#define INT_STS_RXD_INT_ 0x00100000 -#define INT_STS_GPT_INT_ 0x00080000 -#define INT_STS_PHY_INT_ 0x00040000 -#define INT_STS_PME_INT_ 0x00020000 -#define INT_STS_TXSO_ 0x00010000 -#define INT_STS_RWT_ 0x00008000 -#define INT_STS_RXE_ 0x00004000 -#define INT_STS_TXE_ 0x00002000 -#define INT_STS_TDFU_ 0x00000800 -#define INT_STS_TDFO_ 0x00000400 -#define INT_STS_TDFA_ 0x00000200 -#define INT_STS_TSFF_ 0x00000100 -#define INT_STS_TSFL_ 0x00000080 -#define INT_STS_RXDF_ 0x00000040 -#define INT_STS_RDFL_ 0x00000020 -#define INT_STS_RSFF_ 0x00000010 -#define INT_STS_RSFL_ 0x00000008 -#define INT_STS_GPIO2_INT_ 0x00000004 -#define INT_STS_GPIO1_INT_ 0x00000002 -#define INT_STS_GPIO0_INT_ 0x00000001 - -#define INT_EN 0x5C -#define INT_EN_SW_INT_EN_ 0x80000000 -#define INT_EN_TXSTOP_INT_EN_ 0x02000000 -#define INT_EN_RXSTOP_INT_EN_ 0x01000000 -#define INT_EN_RXDFH_INT_EN_ 0x00800000 -#define INT_EN_TIOC_INT_EN_ 0x00200000 -#define INT_EN_RXD_INT_EN_ 0x00100000 -#define INT_EN_GPT_INT_EN_ 0x00080000 -#define INT_EN_PHY_INT_EN_ 0x00040000 -#define INT_EN_PME_INT_EN_ 0x00020000 -#define INT_EN_TXSO_EN_ 0x00010000 -#define INT_EN_RWT_EN_ 0x00008000 -#define INT_EN_RXE_EN_ 0x00004000 -#define INT_EN_TXE_EN_ 0x00002000 -#define INT_EN_TDFU_EN_ 0x00000800 -#define INT_EN_TDFO_EN_ 0x00000400 -#define INT_EN_TDFA_EN_ 0x00000200 -#define INT_EN_TSFF_EN_ 0x00000100 -#define INT_EN_TSFL_EN_ 0x00000080 -#define INT_EN_RXDF_EN_ 0x00000040 -#define INT_EN_RDFL_EN_ 0x00000020 -#define INT_EN_RSFF_EN_ 0x00000010 -#define INT_EN_RSFL_EN_ 0x00000008 -#define INT_EN_GPIO2_INT_ 0x00000004 -#define INT_EN_GPIO1_INT_ 0x00000002 -#define INT_EN_GPIO0_INT_ 0x00000001 - -#define BYTE_TEST 0x64 - -#define FIFO_INT 0x68 -#define FIFO_INT_TX_AVAIL_LEVEL_ 0xFF000000 -#define FIFO_INT_TX_STS_LEVEL_ 0x00FF0000 -#define FIFO_INT_RX_AVAIL_LEVEL_ 0x0000FF00 -#define FIFO_INT_RX_STS_LEVEL_ 0x000000FF - -#define RX_CFG 0x6C -#define RX_CFG_RX_END_ALGN_ 0xC0000000 -#define RX_CFG_RX_END_ALGN4_ 0x00000000 -#define RX_CFG_RX_END_ALGN16_ 0x40000000 -#define RX_CFG_RX_END_ALGN32_ 0x80000000 -#define RX_CFG_RX_DMA_CNT_ 0x0FFF0000 -#define RX_CFG_RX_DUMP_ 0x00008000 -#define RX_CFG_RXDOFF_ 0x00001F00 - -#define TX_CFG 0x70 -#define TX_CFG_TXS_DUMP_ 0x00008000 -#define TX_CFG_TXD_DUMP_ 0x00004000 -#define TX_CFG_TXSAO_ 0x00000004 -#define TX_CFG_TX_ON_ 0x00000002 -#define TX_CFG_STOP_TX_ 0x00000001 - -#define HW_CFG 0x74 -#define HW_CFG_TTM_ 0x00200000 -#define HW_CFG_SF_ 0x00100000 -#define HW_CFG_TX_FIF_SZ_ 0x000F0000 -#define HW_CFG_TR_ 0x00003000 -#define HW_CFG_SRST_ 0x00000001 - -/* only available on 115/117 */ -#define HW_CFG_PHY_CLK_SEL_ 0x00000060 -#define HW_CFG_PHY_CLK_SEL_INT_PHY_ 0x00000000 -#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ 0x00000020 -#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ 0x00000040 -#define HW_CFG_SMI_SEL_ 0x00000010 -#define HW_CFG_EXT_PHY_DET_ 0x00000008 -#define HW_CFG_EXT_PHY_EN_ 0x00000004 -#define HW_CFG_SRST_TO_ 0x00000002 - -/* only available on 116/118 */ -#define HW_CFG_32_16_BIT_MODE_ 0x00000004 - -#define RX_DP_CTRL 0x78 -#define RX_DP_CTRL_RX_FFWD_ 0x80000000 - -#define RX_FIFO_INF 0x7C -#define RX_FIFO_INF_RXSUSED_ 0x00FF0000 -#define RX_FIFO_INF_RXDUSED_ 0x0000FFFF - -#define TX_FIFO_INF 0x80 -#define TX_FIFO_INF_TSUSED_ 0x00FF0000 -#define TX_FIFO_INF_TDFREE_ 0x0000FFFF - -#define PMT_CTRL 0x84 -#define PMT_CTRL_PM_MODE_ 0x00003000 -#define PMT_CTRL_PM_MODE_D0_ 0x00000000 -#define PMT_CTRL_PM_MODE_D1_ 0x00001000 -#define PMT_CTRL_PM_MODE_D2_ 0x00002000 -#define PMT_CTRL_PM_MODE_D3_ 0x00003000 -#define PMT_CTRL_PHY_RST_ 0x00000400 -#define PMT_CTRL_WOL_EN_ 0x00000200 -#define PMT_CTRL_ED_EN_ 0x00000100 -#define PMT_CTRL_PME_TYPE_ 0x00000040 -#define PMT_CTRL_WUPS_ 0x00000030 -#define PMT_CTRL_WUPS_NOWAKE_ 0x00000000 -#define PMT_CTRL_WUPS_ED_ 0x00000010 -#define PMT_CTRL_WUPS_WOL_ 0x00000020 -#define PMT_CTRL_WUPS_MULTI_ 0x00000030 -#define PMT_CTRL_PME_IND_ 0x00000008 -#define PMT_CTRL_PME_POL_ 0x00000004 -#define PMT_CTRL_PME_EN_ 0x00000002 -#define PMT_CTRL_READY_ 0x00000001 - -#define GPIO_CFG 0x88 -#define GPIO_CFG_LED3_EN_ 0x40000000 -#define GPIO_CFG_LED2_EN_ 0x20000000 -#define GPIO_CFG_LED1_EN_ 0x10000000 -#define GPIO_CFG_GPIO2_INT_POL_ 0x04000000 -#define GPIO_CFG_GPIO1_INT_POL_ 0x02000000 -#define GPIO_CFG_GPIO0_INT_POL_ 0x01000000 -#define GPIO_CFG_EEPR_EN_ 0x00700000 -#define GPIO_CFG_GPIOBUF2_ 0x00040000 -#define GPIO_CFG_GPIOBUF1_ 0x00020000 -#define GPIO_CFG_GPIOBUF0_ 0x00010000 -#define GPIO_CFG_GPIODIR2_ 0x00000400 -#define GPIO_CFG_GPIODIR1_ 0x00000200 -#define GPIO_CFG_GPIODIR0_ 0x00000100 -#define GPIO_CFG_GPIOD4_ 0x00000020 -#define GPIO_CFG_GPIOD3_ 0x00000010 -#define GPIO_CFG_GPIOD2_ 0x00000004 -#define GPIO_CFG_GPIOD1_ 0x00000002 -#define GPIO_CFG_GPIOD0_ 0x00000001 - -#define GPT_CFG 0x8C -#define GPT_CFG_TIMER_EN_ 0x20000000 -#define GPT_CFG_GPT_LOAD_ 0x0000FFFF - -#define GPT_CNT 0x90 -#define GPT_CNT_GPT_CNT_ 0x0000FFFF - -#define WORD_SWAP 0x98 - -#define FREE_RUN 0x9C - -#define RX_DROP 0xA0 - -#define MAC_CSR_CMD 0xA4 -#define MAC_CSR_CMD_CSR_BUSY_ 0x80000000 -#define MAC_CSR_CMD_R_NOT_W_ 0x40000000 -#define MAC_CSR_CMD_CSR_ADDR_ 0x000000FF - -#define MAC_CSR_DATA 0xA8 - -#define AFC_CFG 0xAC -#define AFC_CFG_AFC_HI_ 0x00FF0000 -#define AFC_CFG_AFC_LO_ 0x0000FF00 -#define AFC_CFG_BACK_DUR_ 0x000000F0 -#define AFC_CFG_FCMULT_ 0x00000008 -#define AFC_CFG_FCBRD_ 0x00000004 -#define AFC_CFG_FCADD_ 0x00000002 -#define AFC_CFG_FCANY_ 0x00000001 - -#define E2P_CMD 0xB0 -#define E2P_CMD_EPC_BUSY_ 0x80000000 -#define E2P_CMD_EPC_CMD_ 0x70000000 -#define E2P_CMD_EPC_CMD_READ_ 0x00000000 -#define E2P_CMD_EPC_CMD_EWDS_ 0x10000000 -#define E2P_CMD_EPC_CMD_EWEN_ 0x20000000 -#define E2P_CMD_EPC_CMD_WRITE_ 0x30000000 -#define E2P_CMD_EPC_CMD_WRAL_ 0x40000000 -#define E2P_CMD_EPC_CMD_ERASE_ 0x50000000 -#define E2P_CMD_EPC_CMD_ERAL_ 0x60000000 -#define E2P_CMD_EPC_CMD_RELOAD_ 0x70000000 -#define E2P_CMD_EPC_TIMEOUT_ 0x00000200 -#define E2P_CMD_MAC_ADDR_LOADED_ 0x00000100 -#define E2P_CMD_EPC_ADDR_ 0x000000FF - -#define E2P_DATA 0xB4 -#define E2P_DATA_EEPROM_DATA_ 0x000000FF -#define LAN_REGISTER_EXTENT 0x00000100 - -/* - * MAC Control and Status Register (Indirect Address) - * Offset (through the MAC_CSR CMD and DATA port) - */ -#define MAC_CR 0x01 -#define MAC_CR_RXALL_ 0x80000000 -#define MAC_CR_HBDIS_ 0x10000000 -#define MAC_CR_RCVOWN_ 0x00800000 -#define MAC_CR_LOOPBK_ 0x00200000 -#define MAC_CR_FDPX_ 0x00100000 -#define MAC_CR_MCPAS_ 0x00080000 -#define MAC_CR_PRMS_ 0x00040000 -#define MAC_CR_INVFILT_ 0x00020000 -#define MAC_CR_PASSBAD_ 0x00010000 -#define MAC_CR_HFILT_ 0x00008000 -#define MAC_CR_HPFILT_ 0x00002000 -#define MAC_CR_LCOLL_ 0x00001000 -#define MAC_CR_BCAST_ 0x00000800 -#define MAC_CR_DISRTY_ 0x00000400 -#define MAC_CR_PADSTR_ 0x00000100 -#define MAC_CR_BOLMT_MASK_ 0x000000C0 -#define MAC_CR_DFCHK_ 0x00000020 -#define MAC_CR_TXEN_ 0x00000008 -#define MAC_CR_RXEN_ 0x00000004 - -#define ADDRH 0x02 - -#define ADDRL 0x03 - -#define HASHH 0x04 - -#define HASHL 0x05 - -#define MII_ACC 0x06 -#define MII_ACC_PHY_ADDR_ 0x0000F800 -#define MII_ACC_MIIRINDA_ 0x000007C0 -#define MII_ACC_MII_WRITE_ 0x00000002 -#define MII_ACC_MII_BUSY_ 0x00000001 - -#define MII_DATA 0x07 - -#define FLOW 0x08 -#define FLOW_FCPT_ 0xFFFF0000 -#define FLOW_FCPASS_ 0x00000004 -#define FLOW_FCEN_ 0x00000002 -#define FLOW_FCBSY_ 0x00000001 - -#define VLAN1 0x09 - -#define VLAN2 0x0A - -#define WUFF 0x0B - -#define WUCSR 0x0C -#define WUCSR_GUE_ 0x00000200 -#define WUCSR_WUFR_ 0x00000040 -#define WUCSR_MPR_ 0x00000020 -#define WUCSR_WAKE_EN_ 0x00000004 -#define WUCSR_MPEN_ 0x00000002 - -/* - * Phy definitions (vendor-specific) - */ -#define LAN9118_PHY_ID 0x00C0001C - -#define MII_INTSTS 0x1D - -#define MII_INTMSK 0x1E -#define PHY_INTMSK_AN_RCV_ (1 << 1) -#define PHY_INTMSK_PDFAULT_ (1 << 2) -#define PHY_INTMSK_AN_ACK_ (1 << 3) -#define PHY_INTMSK_LNKDOWN_ (1 << 4) -#define PHY_INTMSK_RFAULT_ (1 << 5) -#define PHY_INTMSK_AN_COMP_ (1 << 6) -#define PHY_INTMSK_ENERGYON_ (1 << 7) -#define PHY_INTMSK_DEFAULT_ (PHY_INTMSK_ENERGYON_ | \ - PHY_INTMSK_AN_COMP_ | \ - PHY_INTMSK_RFAULT_ | \ - PHY_INTMSK_LNKDOWN_) - -#define ADVERTISE_PAUSE_ALL (ADVERTISE_PAUSE_CAP | \ - ADVERTISE_PAUSE_ASYM) - -#define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \ - LPA_PAUSE_ASYM) - -/* - * Provide hooks to let the arch add to the initialisation procedure - * and to override the source of the MAC address. - */ -#define SMSC_INITIALIZE() do {} while (0) -#define smsc_get_mac(dev) smsc911x_read_mac_address((dev)) - -#ifdef CONFIG_SMSC911X_ARCH_HOOKS -#include <asm/smsc911x.h> -#endif - -#include <linux/smscphy.h> - -#endif /* __SMSC911X_H__ */ diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.c b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.c deleted file mode 100644 index 38386478..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.c +++ /dev/null @@ -1,1760 +0,0 @@ - /*************************************************************************** - * - * Copyright (C) 2007,2008 SMSC - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - *************************************************************************** - */ - -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/phy.h> -#include <linux/pci.h> -#include <linux/if_vlan.h> -#include <linux/dma-mapping.h> -#include <linux/crc32.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <asm/unaligned.h> -#include "smsc9420.h" - -#define DRV_NAME "smsc9420" -#define PFX DRV_NAME ": " -#define DRV_MDIONAME "smsc9420-mdio" -#define DRV_DESCRIPTION "SMSC LAN9420 driver" -#define DRV_VERSION "1.01" - -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -struct smsc9420_dma_desc { - u32 status; - u32 length; - u32 buffer1; - u32 buffer2; -}; - -struct smsc9420_ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - -struct smsc9420_pdata { - void __iomem *base_addr; - struct pci_dev *pdev; - struct net_device *dev; - - struct smsc9420_dma_desc *rx_ring; - struct smsc9420_dma_desc *tx_ring; - struct smsc9420_ring_info *tx_buffers; - struct smsc9420_ring_info *rx_buffers; - dma_addr_t rx_dma_addr; - dma_addr_t tx_dma_addr; - int tx_ring_head, tx_ring_tail; - int rx_ring_head, rx_ring_tail; - - spinlock_t int_lock; - spinlock_t phy_lock; - - struct napi_struct napi; - - bool software_irq_signal; - bool rx_csum; - u32 msg_enable; - - struct phy_device *phy_dev; - struct mii_bus *mii_bus; - int phy_irq[PHY_MAX_ADDR]; - int last_duplex; - int last_carrier; -}; - -static DEFINE_PCI_DEVICE_TABLE(smsc9420_id_table) = { - { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, smsc9420_id_table); - -#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) - -static uint smsc_debug; -static uint debug = -1; -module_param(debug, uint, 0); -MODULE_PARM_DESC(debug, "debug level"); - -#define smsc_dbg(TYPE, f, a...) \ -do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ - printk(KERN_DEBUG PFX f "\n", ## a); \ -} while (0) - -#define smsc_info(TYPE, f, a...) \ -do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ - printk(KERN_INFO PFX f "\n", ## a); \ -} while (0) - -#define smsc_warn(TYPE, f, a...) \ -do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ - printk(KERN_WARNING PFX f "\n", ## a); \ -} while (0) - -static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset) -{ - return ioread32(pd->base_addr + offset); -} - -static inline void -smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value) -{ - iowrite32(value, pd->base_addr + offset); -} - -static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd) -{ - /* to ensure PCI write completion, we must perform a PCI read */ - smsc9420_reg_read(pd, ID_REV); -} - -static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx) -{ - struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; - unsigned long flags; - u32 addr; - int i, reg = -EIO; - - spin_lock_irqsave(&pd->phy_lock, flags); - - /* confirm MII not busy */ - if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { - smsc_warn(DRV, "MII is busy???"); - goto out; - } - - /* set the address, index & direction (read from PHY) */ - addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | - MII_ACCESS_MII_READ_; - smsc9420_reg_write(pd, MII_ACCESS, addr); - - /* wait for read to complete with 50us timeout */ - for (i = 0; i < 5; i++) { - if (!(smsc9420_reg_read(pd, MII_ACCESS) & - MII_ACCESS_MII_BUSY_)) { - reg = (u16)smsc9420_reg_read(pd, MII_DATA); - goto out; - } - udelay(10); - } - - smsc_warn(DRV, "MII busy timeout!"); - -out: - spin_unlock_irqrestore(&pd->phy_lock, flags); - return reg; -} - -static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx, - u16 val) -{ - struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; - unsigned long flags; - u32 addr; - int i, reg = -EIO; - - spin_lock_irqsave(&pd->phy_lock, flags); - - /* confirm MII not busy */ - if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { - smsc_warn(DRV, "MII is busy???"); - goto out; - } - - /* put the data to write in the MAC */ - smsc9420_reg_write(pd, MII_DATA, (u32)val); - - /* set the address, index & direction (write to PHY) */ - addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | - MII_ACCESS_MII_WRITE_; - smsc9420_reg_write(pd, MII_ACCESS, addr); - - /* wait for write to complete with 50us timeout */ - for (i = 0; i < 5; i++) { - if (!(smsc9420_reg_read(pd, MII_ACCESS) & - MII_ACCESS_MII_BUSY_)) { - reg = 0; - goto out; - } - udelay(10); - } - - smsc_warn(DRV, "MII busy timeout!"); - -out: - spin_unlock_irqrestore(&pd->phy_lock, flags); - return reg; -} - -/* Returns hash bit number for given MAC address - * Example: - * 01 00 5E 00 00 01 -> returns bit number 31 */ -static u32 smsc9420_hash(u8 addr[ETH_ALEN]) -{ - return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; -} - -static int smsc9420_eeprom_reload(struct smsc9420_pdata *pd) -{ - int timeout = 100000; - - BUG_ON(!pd); - - if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy"); - return -EIO; - } - - smsc9420_reg_write(pd, E2P_CMD, - (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_)); - - do { - udelay(10); - if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_)) - return 0; - } while (timeout--); - - smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out"); - return -EIO; -} - -/* Standard ioctls for mii-tool */ -static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - - if (!netif_running(dev) || !pd->phy_dev) - return -EINVAL; - - return phy_mii_ioctl(pd->phy_dev, ifr, cmd); -} - -static int smsc9420_ethtool_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - - if (!pd->phy_dev) - return -ENODEV; - - cmd->maxtxpkt = 1; - cmd->maxrxpkt = 1; - return phy_ethtool_gset(pd->phy_dev, cmd); -} - -static int smsc9420_ethtool_set_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - - if (!pd->phy_dev) - return -ENODEV; - - return phy_ethtool_sset(pd->phy_dev, cmd); -} - -static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) -{ - struct smsc9420_pdata *pd = netdev_priv(netdev); - - strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); - strlcpy(drvinfo->bus_info, pci_name(pd->pdev), - sizeof(drvinfo->bus_info)); - strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); -} - -static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev) -{ - struct smsc9420_pdata *pd = netdev_priv(netdev); - return pd->msg_enable; -} - -static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data) -{ - struct smsc9420_pdata *pd = netdev_priv(netdev); - pd->msg_enable = data; -} - -static int smsc9420_ethtool_nway_reset(struct net_device *netdev) -{ - struct smsc9420_pdata *pd = netdev_priv(netdev); - - if (!pd->phy_dev) - return -ENODEV; - - return phy_start_aneg(pd->phy_dev); -} - -static int smsc9420_ethtool_getregslen(struct net_device *dev) -{ - /* all smsc9420 registers plus all phy registers */ - return 0x100 + (32 * sizeof(u32)); -} - -static void -smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - struct phy_device *phy_dev = pd->phy_dev; - unsigned int i, j = 0; - u32 *data = buf; - - regs->version = smsc9420_reg_read(pd, ID_REV); - for (i = 0; i < 0x100; i += (sizeof(u32))) - data[j++] = smsc9420_reg_read(pd, i); - - // cannot read phy registers if the net device is down - if (!phy_dev) - return; - - for (i = 0; i <= 31; i++) - data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i); -} - -static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd) -{ - unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG); - temp &= ~GPIO_CFG_EEPR_EN_; - smsc9420_reg_write(pd, GPIO_CFG, temp); - msleep(1); -} - -static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op) -{ - int timeout = 100; - u32 e2cmd; - - smsc_dbg(HW, "op 0x%08x", op); - if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - smsc_warn(HW, "Busy at start"); - return -EBUSY; - } - - e2cmd = op | E2P_CMD_EPC_BUSY_; - smsc9420_reg_write(pd, E2P_CMD, e2cmd); - - do { - msleep(1); - e2cmd = smsc9420_reg_read(pd, E2P_CMD); - } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout)); - - if (!timeout) { - smsc_info(HW, "TIMED OUT"); - return -EAGAIN; - } - - if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - smsc_info(HW, "Error occurred during eeprom operation"); - return -EINVAL; - } - - return 0; -} - -static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd, - u8 address, u8 *data) -{ - u32 op = E2P_CMD_EPC_CMD_READ_ | address; - int ret; - - smsc_dbg(HW, "address 0x%x", address); - ret = smsc9420_eeprom_send_cmd(pd, op); - - if (!ret) - data[address] = smsc9420_reg_read(pd, E2P_DATA); - - return ret; -} - -static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd, - u8 address, u8 data) -{ - u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; - int ret; - - smsc_dbg(HW, "address 0x%x, data 0x%x", address, data); - ret = smsc9420_eeprom_send_cmd(pd, op); - - if (!ret) { - op = E2P_CMD_EPC_CMD_WRITE_ | address; - smsc9420_reg_write(pd, E2P_DATA, (u32)data); - ret = smsc9420_eeprom_send_cmd(pd, op); - } - - return ret; -} - -static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev) -{ - return SMSC9420_EEPROM_SIZE; -} - -static int smsc9420_ethtool_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - u8 eeprom_data[SMSC9420_EEPROM_SIZE]; - int len, i; - - smsc9420_eeprom_enable_access(pd); - - len = min(eeprom->len, SMSC9420_EEPROM_SIZE); - for (i = 0; i < len; i++) { - int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data); - if (ret < 0) { - eeprom->len = 0; - return ret; - } - } - - memcpy(data, &eeprom_data[eeprom->offset], len); - eeprom->magic = SMSC9420_EEPROM_MAGIC; - eeprom->len = len; - return 0; -} - -static int smsc9420_ethtool_set_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - int ret; - - if (eeprom->magic != SMSC9420_EEPROM_MAGIC) - return -EINVAL; - - smsc9420_eeprom_enable_access(pd); - smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_); - ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data); - smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_); - - /* Single byte write, according to man page */ - eeprom->len = 1; - - return ret; -} - -static const struct ethtool_ops smsc9420_ethtool_ops = { - .get_settings = smsc9420_ethtool_get_settings, - .set_settings = smsc9420_ethtool_set_settings, - .get_drvinfo = smsc9420_ethtool_get_drvinfo, - .get_msglevel = smsc9420_ethtool_get_msglevel, - .set_msglevel = smsc9420_ethtool_set_msglevel, - .nway_reset = smsc9420_ethtool_nway_reset, - .get_link = ethtool_op_get_link, - .get_eeprom_len = smsc9420_ethtool_get_eeprom_len, - .get_eeprom = smsc9420_ethtool_get_eeprom, - .set_eeprom = smsc9420_ethtool_set_eeprom, - .get_regs_len = smsc9420_ethtool_getregslen, - .get_regs = smsc9420_ethtool_getregs, -}; - -/* Sets the device MAC address to dev_addr */ -static void smsc9420_set_mac_address(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - u8 *dev_addr = dev->dev_addr; - u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; - u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | - (dev_addr[1] << 8) | dev_addr[0]; - - smsc9420_reg_write(pd, ADDRH, mac_high16); - smsc9420_reg_write(pd, ADDRL, mac_low32); -} - -static void smsc9420_check_mac_address(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - - /* Check if mac address has been specified when bringing interface up */ - if (is_valid_ether_addr(dev->dev_addr)) { - smsc9420_set_mac_address(dev); - smsc_dbg(PROBE, "MAC Address is specified by configuration"); - } else { - /* Try reading mac address from device. if EEPROM is present - * it will already have been set */ - u32 mac_high16 = smsc9420_reg_read(pd, ADDRH); - u32 mac_low32 = smsc9420_reg_read(pd, ADDRL); - dev->dev_addr[0] = (u8)(mac_low32); - dev->dev_addr[1] = (u8)(mac_low32 >> 8); - dev->dev_addr[2] = (u8)(mac_low32 >> 16); - dev->dev_addr[3] = (u8)(mac_low32 >> 24); - dev->dev_addr[4] = (u8)(mac_high16); - dev->dev_addr[5] = (u8)(mac_high16 >> 8); - - if (is_valid_ether_addr(dev->dev_addr)) { - /* eeprom values are valid so use them */ - smsc_dbg(PROBE, "Mac Address is read from EEPROM"); - } else { - /* eeprom values are invalid, generate random MAC */ - eth_hw_addr_random(dev); - smsc9420_set_mac_address(dev); - smsc_dbg(PROBE, "MAC Address is set to random"); - } - } -} - -static void smsc9420_stop_tx(struct smsc9420_pdata *pd) -{ - u32 dmac_control, mac_cr, dma_intr_ena; - int timeout = 1000; - - /* disable TX DMAC */ - dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); - dmac_control &= (~DMAC_CONTROL_ST_); - smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); - - /* Wait max 10ms for transmit process to stop */ - while (--timeout) { - if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_) - break; - udelay(10); - } - - if (!timeout) - smsc_warn(IFDOWN, "TX DMAC failed to stop"); - - /* ACK Tx DMAC stop bit */ - smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_); - - /* mask TX DMAC interrupts */ - dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); - dma_intr_ena &= ~(DMAC_INTR_ENA_TX_); - smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); - smsc9420_pci_flush_write(pd); - - /* stop MAC TX */ - mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_); - smsc9420_reg_write(pd, MAC_CR, mac_cr); - smsc9420_pci_flush_write(pd); -} - -static void smsc9420_free_tx_ring(struct smsc9420_pdata *pd) -{ - int i; - - BUG_ON(!pd->tx_ring); - - if (!pd->tx_buffers) - return; - - for (i = 0; i < TX_RING_SIZE; i++) { - struct sk_buff *skb = pd->tx_buffers[i].skb; - - if (skb) { - BUG_ON(!pd->tx_buffers[i].mapping); - pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - } - - pd->tx_ring[i].status = 0; - pd->tx_ring[i].length = 0; - pd->tx_ring[i].buffer1 = 0; - pd->tx_ring[i].buffer2 = 0; - } - wmb(); - - kfree(pd->tx_buffers); - pd->tx_buffers = NULL; - - pd->tx_ring_head = 0; - pd->tx_ring_tail = 0; -} - -static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd) -{ - int i; - - BUG_ON(!pd->rx_ring); - - if (!pd->rx_buffers) - return; - - for (i = 0; i < RX_RING_SIZE; i++) { - if (pd->rx_buffers[i].skb) - dev_kfree_skb_any(pd->rx_buffers[i].skb); - - if (pd->rx_buffers[i].mapping) - pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - - pd->rx_ring[i].status = 0; - pd->rx_ring[i].length = 0; - pd->rx_ring[i].buffer1 = 0; - pd->rx_ring[i].buffer2 = 0; - } - wmb(); - - kfree(pd->rx_buffers); - pd->rx_buffers = NULL; - - pd->rx_ring_head = 0; - pd->rx_ring_tail = 0; -} - -static void smsc9420_stop_rx(struct smsc9420_pdata *pd) -{ - int timeout = 1000; - u32 mac_cr, dmac_control, dma_intr_ena; - - /* mask RX DMAC interrupts */ - dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); - dma_intr_ena &= (~DMAC_INTR_ENA_RX_); - smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); - smsc9420_pci_flush_write(pd); - - /* stop RX MAC prior to stoping DMA */ - mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_); - smsc9420_reg_write(pd, MAC_CR, mac_cr); - smsc9420_pci_flush_write(pd); - - /* stop RX DMAC */ - dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); - dmac_control &= (~DMAC_CONTROL_SR_); - smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); - smsc9420_pci_flush_write(pd); - - /* wait up to 10ms for receive to stop */ - while (--timeout) { - if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_) - break; - udelay(10); - } - - if (!timeout) - smsc_warn(IFDOWN, "RX DMAC did not stop! timeout."); - - /* ACK the Rx DMAC stop bit */ - smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_); -} - -static irqreturn_t smsc9420_isr(int irq, void *dev_id) -{ - struct smsc9420_pdata *pd = dev_id; - u32 int_cfg, int_sts, int_ctl; - irqreturn_t ret = IRQ_NONE; - ulong flags; - - BUG_ON(!pd); - BUG_ON(!pd->base_addr); - - int_cfg = smsc9420_reg_read(pd, INT_CFG); - - /* check if it's our interrupt */ - if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) != - (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) - return IRQ_NONE; - - int_sts = smsc9420_reg_read(pd, INT_STAT); - - if (likely(INT_STAT_DMAC_INT_ & int_sts)) { - u32 status = smsc9420_reg_read(pd, DMAC_STATUS); - u32 ints_to_clear = 0; - - if (status & DMAC_STS_TX_) { - ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_); - netif_wake_queue(pd->dev); - } - - if (status & DMAC_STS_RX_) { - /* mask RX DMAC interrupts */ - u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); - dma_intr_ena &= (~DMAC_INTR_ENA_RX_); - smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); - smsc9420_pci_flush_write(pd); - - ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_); - napi_schedule(&pd->napi); - } - - if (ints_to_clear) - smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear); - - ret = IRQ_HANDLED; - } - - if (unlikely(INT_STAT_SW_INT_ & int_sts)) { - /* mask software interrupt */ - spin_lock_irqsave(&pd->int_lock, flags); - int_ctl = smsc9420_reg_read(pd, INT_CTL); - int_ctl &= (~INT_CTL_SW_INT_EN_); - smsc9420_reg_write(pd, INT_CTL, int_ctl); - spin_unlock_irqrestore(&pd->int_lock, flags); - - smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_); - pd->software_irq_signal = true; - smp_wmb(); - - ret = IRQ_HANDLED; - } - - /* to ensure PCI write completion, we must perform a PCI read */ - smsc9420_pci_flush_write(pd); - - return ret; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void smsc9420_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - smsc9420_isr(0, dev); - enable_irq(dev->irq); -} -#endif /* CONFIG_NET_POLL_CONTROLLER */ - -static void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd) -{ - smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_); - smsc9420_reg_read(pd, BUS_MODE); - udelay(2); - if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_) - smsc_warn(DRV, "Software reset not cleared"); -} - -static int smsc9420_stop(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - u32 int_cfg; - ulong flags; - - BUG_ON(!pd); - BUG_ON(!pd->phy_dev); - - /* disable master interrupt */ - spin_lock_irqsave(&pd->int_lock, flags); - int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); - smsc9420_reg_write(pd, INT_CFG, int_cfg); - spin_unlock_irqrestore(&pd->int_lock, flags); - - netif_tx_disable(dev); - napi_disable(&pd->napi); - - smsc9420_stop_tx(pd); - smsc9420_free_tx_ring(pd); - - smsc9420_stop_rx(pd); - smsc9420_free_rx_ring(pd); - - free_irq(dev->irq, pd); - - smsc9420_dmac_soft_reset(pd); - - phy_stop(pd->phy_dev); - - phy_disconnect(pd->phy_dev); - pd->phy_dev = NULL; - mdiobus_unregister(pd->mii_bus); - mdiobus_free(pd->mii_bus); - - return 0; -} - -static void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status) -{ - if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) { - dev->stats.rx_errors++; - if (desc_status & RDES0_DESCRIPTOR_ERROR_) - dev->stats.rx_over_errors++; - else if (desc_status & (RDES0_FRAME_TOO_LONG_ | - RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_)) - dev->stats.rx_frame_errors++; - else if (desc_status & RDES0_CRC_ERROR_) - dev->stats.rx_crc_errors++; - } - - if (unlikely(desc_status & RDES0_LENGTH_ERROR_)) - dev->stats.rx_length_errors++; - - if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) && - (desc_status & RDES0_FIRST_DESCRIPTOR_)))) - dev->stats.rx_length_errors++; - - if (desc_status & RDES0_MULTICAST_FRAME_) - dev->stats.multicast++; -} - -static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, - const u32 status) -{ - struct net_device *dev = pd->dev; - struct sk_buff *skb; - u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_) - >> RDES0_FRAME_LENGTH_SHFT_; - - /* remove crc from packet lendth */ - packet_length -= 4; - - if (pd->rx_csum) - packet_length -= 2; - - dev->stats.rx_packets++; - dev->stats.rx_bytes += packet_length; - - pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping, - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - pd->rx_buffers[index].mapping = 0; - - skb = pd->rx_buffers[index].skb; - pd->rx_buffers[index].skb = NULL; - - if (pd->rx_csum) { - u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) + - NET_IP_ALIGN + packet_length + 4); - put_unaligned_le16(hw_csum, &skb->csum); - skb->ip_summed = CHECKSUM_COMPLETE; - } - - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, packet_length); - - skb->protocol = eth_type_trans(skb, dev); - - netif_receive_skb(skb); -} - -static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) -{ - struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ); - dma_addr_t mapping; - - BUG_ON(pd->rx_buffers[index].skb); - BUG_ON(pd->rx_buffers[index].mapping); - - if (unlikely(!skb)) { - smsc_warn(RX_ERR, "Failed to allocate new skb!"); - return -ENOMEM; - } - - mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb), - PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(pd->pdev, mapping)) { - dev_kfree_skb_any(skb); - smsc_warn(RX_ERR, "pci_map_single failed!"); - return -ENOMEM; - } - - pd->rx_buffers[index].skb = skb; - pd->rx_buffers[index].mapping = mapping; - pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN; - pd->rx_ring[index].status = RDES0_OWN_; - wmb(); - - return 0; -} - -static void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd) -{ - while (pd->rx_ring_tail != pd->rx_ring_head) { - if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail)) - break; - - pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE; - } -} - -static int smsc9420_rx_poll(struct napi_struct *napi, int budget) -{ - struct smsc9420_pdata *pd = - container_of(napi, struct smsc9420_pdata, napi); - struct net_device *dev = pd->dev; - u32 drop_frame_cnt, dma_intr_ena, status; - int work_done; - - for (work_done = 0; work_done < budget; work_done++) { - rmb(); - status = pd->rx_ring[pd->rx_ring_head].status; - - /* stop if DMAC owns this dma descriptor */ - if (status & RDES0_OWN_) - break; - - smsc9420_rx_count_stats(dev, status); - smsc9420_rx_handoff(pd, pd->rx_ring_head, status); - pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE; - smsc9420_alloc_new_rx_buffers(pd); - } - - drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR); - dev->stats.rx_dropped += - (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF); - - /* Kick RXDMA */ - smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); - smsc9420_pci_flush_write(pd); - - if (work_done < budget) { - napi_complete(&pd->napi); - - /* re-enable RX DMA interrupts */ - dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); - dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); - smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); - smsc9420_pci_flush_write(pd); - } - return work_done; -} - -static void -smsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length) -{ - if (unlikely(status & TDES0_ERROR_SUMMARY_)) { - dev->stats.tx_errors++; - if (status & (TDES0_EXCESSIVE_DEFERRAL_ | - TDES0_EXCESSIVE_COLLISIONS_)) - dev->stats.tx_aborted_errors++; - - if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_)) - dev->stats.tx_carrier_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += (length & 0x7FF); - } - - if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) { - dev->stats.collisions += 16; - } else { - dev->stats.collisions += - (status & TDES0_COLLISION_COUNT_MASK_) >> - TDES0_COLLISION_COUNT_SHFT_; - } - - if (unlikely(status & TDES0_HEARTBEAT_FAIL_)) - dev->stats.tx_heartbeat_errors++; -} - -/* Check for completed dma transfers, update stats and free skbs */ -static void smsc9420_complete_tx(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - - while (pd->tx_ring_tail != pd->tx_ring_head) { - int index = pd->tx_ring_tail; - u32 status, length; - - rmb(); - status = pd->tx_ring[index].status; - length = pd->tx_ring[index].length; - - /* Check if DMA still owns this descriptor */ - if (unlikely(TDES0_OWN_ & status)) - break; - - smsc9420_tx_update_stats(dev, status, length); - - BUG_ON(!pd->tx_buffers[index].skb); - BUG_ON(!pd->tx_buffers[index].mapping); - - pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping, - pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE); - pd->tx_buffers[index].mapping = 0; - - dev_kfree_skb_any(pd->tx_buffers[index].skb); - pd->tx_buffers[index].skb = NULL; - - pd->tx_ring[index].buffer1 = 0; - wmb(); - - pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE; - } -} - -static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - dma_addr_t mapping; - int index = pd->tx_ring_head; - u32 tmp_desc1; - bool about_to_take_last_desc = - (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail); - - smsc9420_complete_tx(dev); - - rmb(); - BUG_ON(pd->tx_ring[index].status & TDES0_OWN_); - BUG_ON(pd->tx_buffers[index].skb); - BUG_ON(pd->tx_buffers[index].mapping); - - mapping = pci_map_single(pd->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pd->pdev, mapping)) { - smsc_warn(TX_ERR, "pci_map_single failed, dropping packet"); - return NETDEV_TX_BUSY; - } - - pd->tx_buffers[index].skb = skb; - pd->tx_buffers[index].mapping = mapping; - - tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF)); - if (unlikely(about_to_take_last_desc)) { - tmp_desc1 |= TDES1_IC_; - netif_stop_queue(pd->dev); - } - - /* check if we are at the last descriptor and need to set EOR */ - if (unlikely(index == (TX_RING_SIZE - 1))) - tmp_desc1 |= TDES1_TER_; - - pd->tx_ring[index].buffer1 = mapping; - pd->tx_ring[index].length = tmp_desc1; - wmb(); - - /* increment head */ - pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE; - - /* assign ownership to DMAC */ - pd->tx_ring[index].status = TDES0_OWN_; - wmb(); - - skb_tx_timestamp(skb); - - /* kick the DMA */ - smsc9420_reg_write(pd, TX_POLL_DEMAND, 1); - smsc9420_pci_flush_write(pd); - - return NETDEV_TX_OK; -} - -static struct net_device_stats *smsc9420_get_stats(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR); - dev->stats.rx_dropped += - (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF); - return &dev->stats; -} - -static void smsc9420_set_multicast_list(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); - - if (dev->flags & IFF_PROMISC) { - smsc_dbg(HW, "Promiscuous Mode Enabled"); - mac_cr |= MAC_CR_PRMS_; - mac_cr &= (~MAC_CR_MCPAS_); - mac_cr &= (~MAC_CR_HPFILT_); - } else if (dev->flags & IFF_ALLMULTI) { - smsc_dbg(HW, "Receive all Multicast Enabled"); - mac_cr &= (~MAC_CR_PRMS_); - mac_cr |= MAC_CR_MCPAS_; - mac_cr &= (~MAC_CR_HPFILT_); - } else if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - u32 hash_lo = 0, hash_hi = 0; - - smsc_dbg(HW, "Multicast filter enabled"); - netdev_for_each_mc_addr(ha, dev) { - u32 bit_num = smsc9420_hash(ha->addr); - u32 mask = 1 << (bit_num & 0x1F); - - if (bit_num & 0x20) - hash_hi |= mask; - else - hash_lo |= mask; - - } - smsc9420_reg_write(pd, HASHH, hash_hi); - smsc9420_reg_write(pd, HASHL, hash_lo); - - mac_cr &= (~MAC_CR_PRMS_); - mac_cr &= (~MAC_CR_MCPAS_); - mac_cr |= MAC_CR_HPFILT_; - } else { - smsc_dbg(HW, "Receive own packets only."); - smsc9420_reg_write(pd, HASHH, 0); - smsc9420_reg_write(pd, HASHL, 0); - - mac_cr &= (~MAC_CR_PRMS_); - mac_cr &= (~MAC_CR_MCPAS_); - mac_cr &= (~MAC_CR_HPFILT_); - } - - smsc9420_reg_write(pd, MAC_CR, mac_cr); - smsc9420_pci_flush_write(pd); -} - -static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) -{ - struct phy_device *phy_dev = pd->phy_dev; - u32 flow; - - if (phy_dev->duplex == DUPLEX_FULL) { - u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); - u16 rmtadv = phy_read(phy_dev, MII_LPA); - u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); - - if (cap & FLOW_CTRL_RX) - flow = 0xFFFF0002; - else - flow = 0; - - smsc_info(LINK, "rx pause %s, tx pause %s", - (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), - (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); - } else { - smsc_info(LINK, "half duplex"); - flow = 0; - } - - smsc9420_reg_write(pd, FLOW, flow); -} - -/* Update link mode if anything has changed. Called periodically when the - * PHY is in polling mode, even if nothing has changed. */ -static void smsc9420_phy_adjust_link(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - struct phy_device *phy_dev = pd->phy_dev; - int carrier; - - if (phy_dev->duplex != pd->last_duplex) { - u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); - if (phy_dev->duplex) { - smsc_dbg(LINK, "full duplex mode"); - mac_cr |= MAC_CR_FDPX_; - } else { - smsc_dbg(LINK, "half duplex mode"); - mac_cr &= ~MAC_CR_FDPX_; - } - smsc9420_reg_write(pd, MAC_CR, mac_cr); - - smsc9420_phy_update_flowcontrol(pd); - pd->last_duplex = phy_dev->duplex; - } - - carrier = netif_carrier_ok(dev); - if (carrier != pd->last_carrier) { - if (carrier) - smsc_dbg(LINK, "carrier OK"); - else - smsc_dbg(LINK, "no carrier"); - pd->last_carrier = carrier; - } -} - -static int smsc9420_mii_probe(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - struct phy_device *phydev = NULL; - - BUG_ON(pd->phy_dev); - - /* Device only supports internal PHY at address 1 */ - if (!pd->mii_bus->phy_map[1]) { - pr_err("%s: no PHY found at address 1\n", dev->name); - return -ENODEV; - } - - phydev = pd->mii_bus->phy_map[1]; - smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr, - phydev->phy_id); - - phydev = phy_connect(dev, dev_name(&phydev->dev), - smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII); - - if (IS_ERR(phydev)) { - pr_err("%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(phydev); - } - - pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", - dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq); - - /* mask with MAC supported features */ - phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - phydev->advertising = phydev->supported; - - pd->phy_dev = phydev; - pd->last_duplex = -1; - pd->last_carrier = -1; - - return 0; -} - -static int smsc9420_mii_init(struct net_device *dev) -{ - struct smsc9420_pdata *pd = netdev_priv(dev); - int err = -ENXIO, i; - - pd->mii_bus = mdiobus_alloc(); - if (!pd->mii_bus) { - err = -ENOMEM; - goto err_out_1; - } - pd->mii_bus->name = DRV_MDIONAME; - snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x", - (pd->pdev->bus->number << 8) | pd->pdev->devfn); - pd->mii_bus->priv = pd; - pd->mii_bus->read = smsc9420_mii_read; - pd->mii_bus->write = smsc9420_mii_write; - pd->mii_bus->irq = pd->phy_irq; - for (i = 0; i < PHY_MAX_ADDR; ++i) - pd->mii_bus->irq[i] = PHY_POLL; - - /* Mask all PHYs except ID 1 (internal) */ - pd->mii_bus->phy_mask = ~(1 << 1); - - if (mdiobus_register(pd->mii_bus)) { - smsc_warn(PROBE, "Error registering mii bus"); - goto err_out_free_bus_2; - } - - if (smsc9420_mii_probe(dev) < 0) { - smsc_warn(PROBE, "Error probing mii bus"); - goto err_out_unregister_bus_3; - } - - return 0; - -err_out_unregister_bus_3: - mdiobus_unregister(pd->mii_bus); -err_out_free_bus_2: - mdiobus_free(pd->mii_bus); -err_out_1: - return err; -} - -static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd) -{ - int i; - - BUG_ON(!pd->tx_ring); - - pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * - TX_RING_SIZE), GFP_KERNEL); - if (!pd->tx_buffers) { - smsc_warn(IFUP, "Failed to allocated tx_buffers"); - return -ENOMEM; - } - - /* Initialize the TX Ring */ - for (i = 0; i < TX_RING_SIZE; i++) { - pd->tx_buffers[i].skb = NULL; - pd->tx_buffers[i].mapping = 0; - pd->tx_ring[i].status = 0; - pd->tx_ring[i].length = 0; - pd->tx_ring[i].buffer1 = 0; - pd->tx_ring[i].buffer2 = 0; - } - pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_; - wmb(); - - pd->tx_ring_head = 0; - pd->tx_ring_tail = 0; - - smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr); - smsc9420_pci_flush_write(pd); - - return 0; -} - -static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd) -{ - int i; - - BUG_ON(!pd->rx_ring); - - pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * - RX_RING_SIZE), GFP_KERNEL); - if (pd->rx_buffers == NULL) { - smsc_warn(IFUP, "Failed to allocated rx_buffers"); - goto out; - } - - /* initialize the rx ring */ - for (i = 0; i < RX_RING_SIZE; i++) { - pd->rx_ring[i].status = 0; - pd->rx_ring[i].length = PKT_BUF_SZ; - pd->rx_ring[i].buffer2 = 0; - pd->rx_buffers[i].skb = NULL; - pd->rx_buffers[i].mapping = 0; - } - pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_); - - /* now allocate the entire ring of skbs */ - for (i = 0; i < RX_RING_SIZE; i++) { - if (smsc9420_alloc_rx_buffer(pd, i)) { - smsc_warn(IFUP, "failed to allocate rx skb %d", i); - goto out_free_rx_skbs; - } - } - - pd->rx_ring_head = 0; - pd->rx_ring_tail = 0; - - smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q); - smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1)); - - if (pd->rx_csum) { - /* Enable RX COE */ - u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN; - smsc9420_reg_write(pd, COE_CR, coe); - smsc_dbg(IFUP, "COE_CR = 0x%08x", coe); - } - - smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr); - smsc9420_pci_flush_write(pd); - - return 0; - -out_free_rx_skbs: - smsc9420_free_rx_ring(pd); -out: - return -ENOMEM; -} - -static int smsc9420_open(struct net_device *dev) -{ - struct smsc9420_pdata *pd; - u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl; - unsigned long flags; - int result = 0, timeout; - - BUG_ON(!dev); - pd = netdev_priv(dev); - BUG_ON(!pd); - - if (!is_valid_ether_addr(dev->dev_addr)) { - smsc_warn(IFUP, "dev_addr is not a valid MAC address"); - result = -EADDRNOTAVAIL; - goto out_0; - } - - netif_carrier_off(dev); - - /* disable, mask and acknowledge all interrupts */ - spin_lock_irqsave(&pd->int_lock, flags); - int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); - smsc9420_reg_write(pd, INT_CFG, int_cfg); - smsc9420_reg_write(pd, INT_CTL, 0); - spin_unlock_irqrestore(&pd->int_lock, flags); - smsc9420_reg_write(pd, DMAC_INTR_ENA, 0); - smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF); - smsc9420_pci_flush_write(pd); - - if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED, - DRV_NAME, pd)) { - smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq); - result = -ENODEV; - goto out_0; - } - - smsc9420_dmac_soft_reset(pd); - - /* make sure MAC_CR is sane */ - smsc9420_reg_write(pd, MAC_CR, 0); - - smsc9420_set_mac_address(dev); - - /* Configure GPIO pins to drive LEDs */ - smsc9420_reg_write(pd, GPIO_CFG, - (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_)); - - bus_mode = BUS_MODE_DMA_BURST_LENGTH_16; - -#ifdef __BIG_ENDIAN - bus_mode |= BUS_MODE_DBO_; -#endif - - smsc9420_reg_write(pd, BUS_MODE, bus_mode); - - smsc9420_pci_flush_write(pd); - - /* set bus master bridge arbitration priority for Rx and TX DMA */ - smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1); - - smsc9420_reg_write(pd, DMAC_CONTROL, - (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_)); - - smsc9420_pci_flush_write(pd); - - /* test the IRQ connection to the ISR */ - smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq); - pd->software_irq_signal = false; - - spin_lock_irqsave(&pd->int_lock, flags); - /* configure interrupt deassertion timer and enable interrupts */ - int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; - int_cfg &= ~(INT_CFG_INT_DEAS_MASK); - int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK); - smsc9420_reg_write(pd, INT_CFG, int_cfg); - - /* unmask software interrupt */ - int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_; - smsc9420_reg_write(pd, INT_CTL, int_ctl); - spin_unlock_irqrestore(&pd->int_lock, flags); - smsc9420_pci_flush_write(pd); - - timeout = 1000; - while (timeout--) { - if (pd->software_irq_signal) - break; - msleep(1); - } - - /* disable interrupts */ - spin_lock_irqsave(&pd->int_lock, flags); - int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); - smsc9420_reg_write(pd, INT_CFG, int_cfg); - spin_unlock_irqrestore(&pd->int_lock, flags); - - if (!pd->software_irq_signal) { - smsc_warn(IFUP, "ISR failed signaling test"); - result = -ENODEV; - goto out_free_irq_1; - } - - smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq); - - result = smsc9420_alloc_tx_ring(pd); - if (result) { - smsc_warn(IFUP, "Failed to Initialize tx dma ring"); - result = -ENOMEM; - goto out_free_irq_1; - } - - result = smsc9420_alloc_rx_ring(pd); - if (result) { - smsc_warn(IFUP, "Failed to Initialize rx dma ring"); - result = -ENOMEM; - goto out_free_tx_ring_2; - } - - result = smsc9420_mii_init(dev); - if (result) { - smsc_warn(IFUP, "Failed to initialize Phy"); - result = -ENODEV; - goto out_free_rx_ring_3; - } - - /* Bring the PHY up */ - phy_start(pd->phy_dev); - - napi_enable(&pd->napi); - - /* start tx and rx */ - mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_; - smsc9420_reg_write(pd, MAC_CR, mac_cr); - - dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); - dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_; - smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); - smsc9420_pci_flush_write(pd); - - dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); - dma_intr_ena |= - (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); - smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); - smsc9420_pci_flush_write(pd); - - netif_wake_queue(dev); - - smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); - - /* enable interrupts */ - spin_lock_irqsave(&pd->int_lock, flags); - int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; - smsc9420_reg_write(pd, INT_CFG, int_cfg); - spin_unlock_irqrestore(&pd->int_lock, flags); - - return 0; - -out_free_rx_ring_3: - smsc9420_free_rx_ring(pd); -out_free_tx_ring_2: - smsc9420_free_tx_ring(pd); -out_free_irq_1: - free_irq(dev->irq, pd); -out_0: - return result; -} - -#ifdef CONFIG_PM - -static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct smsc9420_pdata *pd = netdev_priv(dev); - u32 int_cfg; - ulong flags; - - /* disable interrupts */ - spin_lock_irqsave(&pd->int_lock, flags); - int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); - smsc9420_reg_write(pd, INT_CFG, int_cfg); - spin_unlock_irqrestore(&pd->int_lock, flags); - - if (netif_running(dev)) { - netif_tx_disable(dev); - smsc9420_stop_tx(pd); - smsc9420_free_tx_ring(pd); - - napi_disable(&pd->napi); - smsc9420_stop_rx(pd); - smsc9420_free_rx_ring(pd); - - free_irq(dev->irq, pd); - - netif_device_detach(dev); - } - - pci_save_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -static int smsc9420_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct smsc9420_pdata *pd = netdev_priv(dev); - int err; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - err = pci_enable_device(pdev); - if (err) - return err; - - pci_set_master(pdev); - - err = pci_enable_wake(pdev, 0, 0); - if (err) - smsc_warn(IFUP, "pci_enable_wake failed: %d", err); - - if (netif_running(dev)) { - err = smsc9420_open(dev); - netif_device_attach(dev); - } - return err; -} - -#endif /* CONFIG_PM */ - -static const struct net_device_ops smsc9420_netdev_ops = { - .ndo_open = smsc9420_open, - .ndo_stop = smsc9420_stop, - .ndo_start_xmit = smsc9420_hard_start_xmit, - .ndo_get_stats = smsc9420_get_stats, - .ndo_set_rx_mode = smsc9420_set_multicast_list, - .ndo_do_ioctl = smsc9420_do_ioctl, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = smsc9420_poll_controller, -#endif /* CONFIG_NET_POLL_CONTROLLER */ -}; - -static int __devinit -smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct net_device *dev; - struct smsc9420_pdata *pd; - void __iomem *virt_addr; - int result = 0; - u32 id_rev; - - printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n"); - - /* First do the PCI initialisation */ - result = pci_enable_device(pdev); - if (unlikely(result)) { - printk(KERN_ERR "Cannot enable smsc9420\n"); - goto out_0; - } - - pci_set_master(pdev); - - dev = alloc_etherdev(sizeof(*pd)); - if (!dev) - goto out_disable_pci_device_1; - - SET_NETDEV_DEV(dev, &pdev->dev); - - if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) { - printk(KERN_ERR "Cannot find PCI device base address\n"); - goto out_free_netdev_2; - } - - if ((pci_request_regions(pdev, DRV_NAME))) { - printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); - goto out_free_netdev_2; - } - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_ERR "No usable DMA configuration, aborting.\n"); - goto out_free_regions_3; - } - - virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR), - pci_resource_len(pdev, SMSC_BAR)); - if (!virt_addr) { - printk(KERN_ERR "Cannot map device registers, aborting.\n"); - goto out_free_regions_3; - } - - /* registers are double mapped with 0 offset for LE and 0x200 for BE */ - virt_addr += LAN9420_CPSR_ENDIAN_OFFSET; - - dev->base_addr = (ulong)virt_addr; - - pd = netdev_priv(dev); - - /* pci descriptors are created in the PCI consistent area */ - pd->rx_ring = pci_alloc_consistent(pdev, - sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE + - sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE, - &pd->rx_dma_addr); - - if (!pd->rx_ring) - goto out_free_io_4; - - /* descriptors are aligned due to the nature of pci_alloc_consistent */ - pd->tx_ring = (struct smsc9420_dma_desc *) - (pd->rx_ring + RX_RING_SIZE); - pd->tx_dma_addr = pd->rx_dma_addr + - sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE; - - pd->pdev = pdev; - pd->dev = dev; - pd->base_addr = virt_addr; - pd->msg_enable = smsc_debug; - pd->rx_csum = true; - - smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr); - - id_rev = smsc9420_reg_read(pd, ID_REV); - switch (id_rev & 0xFFFF0000) { - case 0x94200000: - smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev); - break; - default: - smsc_warn(PROBE, "LAN9420 NOT identified"); - smsc_warn(PROBE, "ID_REV=0x%08X", id_rev); - goto out_free_dmadesc_5; - } - - smsc9420_dmac_soft_reset(pd); - smsc9420_eeprom_reload(pd); - smsc9420_check_mac_address(dev); - - dev->netdev_ops = &smsc9420_netdev_ops; - dev->ethtool_ops = &smsc9420_ethtool_ops; - dev->irq = pdev->irq; - - netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT); - - result = register_netdev(dev); - if (result) { - smsc_warn(PROBE, "error %i registering device", result); - goto out_free_dmadesc_5; - } - - pci_set_drvdata(pdev, dev); - - spin_lock_init(&pd->int_lock); - spin_lock_init(&pd->phy_lock); - - dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); - - return 0; - -out_free_dmadesc_5: - pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * - (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); -out_free_io_4: - iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET); -out_free_regions_3: - pci_release_regions(pdev); -out_free_netdev_2: - free_netdev(dev); -out_disable_pci_device_1: - pci_disable_device(pdev); -out_0: - return -ENODEV; -} - -static void __devexit smsc9420_remove(struct pci_dev *pdev) -{ - struct net_device *dev; - struct smsc9420_pdata *pd; - - dev = pci_get_drvdata(pdev); - if (!dev) - return; - - pci_set_drvdata(pdev, NULL); - - pd = netdev_priv(dev); - unregister_netdev(dev); - - /* tx_buffers and rx_buffers are freed in stop */ - BUG_ON(pd->tx_buffers); - BUG_ON(pd->rx_buffers); - - BUG_ON(!pd->tx_ring); - BUG_ON(!pd->rx_ring); - - pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * - (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); - - iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET); - pci_release_regions(pdev); - free_netdev(dev); - pci_disable_device(pdev); -} - -static struct pci_driver smsc9420_driver = { - .name = DRV_NAME, - .id_table = smsc9420_id_table, - .probe = smsc9420_probe, - .remove = __devexit_p(smsc9420_remove), -#ifdef CONFIG_PM - .suspend = smsc9420_suspend, - .resume = smsc9420_resume, -#endif /* CONFIG_PM */ -}; - -static int __init smsc9420_init_module(void) -{ - smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT); - - return pci_register_driver(&smsc9420_driver); -} - -static void __exit smsc9420_exit_module(void) -{ - pci_unregister_driver(&smsc9420_driver); -} - -module_init(smsc9420_init_module); -module_exit(smsc9420_exit_module); diff --git a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.h b/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.h deleted file mode 100644 index e441402f..00000000 --- a/ANDROID_3.4.5/drivers/net/ethernet/smsc/smsc9420.h +++ /dev/null @@ -1,276 +0,0 @@ - /*************************************************************************** - * - * Copyright (C) 2007,2008 SMSC - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - *************************************************************************** - */ - -#ifndef _SMSC9420_H -#define _SMSC9420_H - -#define TX_RING_SIZE (32) -#define RX_RING_SIZE (128) - -/* interrupt deassertion in multiples of 10us */ -#define INT_DEAS_TIME (50) - -#define NAPI_WEIGHT (64) -#define SMSC_BAR (3) - -#ifdef __BIG_ENDIAN -/* Register set is duplicated for BE at an offset of 0x200 */ -#define LAN9420_CPSR_ENDIAN_OFFSET (0x200) -#else -#define LAN9420_CPSR_ENDIAN_OFFSET (0) -#endif - -#define PCI_VENDOR_ID_9420 (0x1055) -#define PCI_DEVICE_ID_9420 (0xE420) - -#define LAN_REGISTER_EXTENT (0x400) - -#define SMSC9420_EEPROM_SIZE ((u32)11) -#define SMSC9420_EEPROM_MAGIC (0x9420) - -#define PKT_BUF_SZ (VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4) - -/***********************************************/ -/* DMA Controller Control and Status Registers */ -/***********************************************/ -#define BUS_MODE (0x00) -#define BUS_MODE_SWR_ (BIT(0)) -#define BUS_MODE_DMA_BURST_LENGTH_1 (BIT(8)) -#define BUS_MODE_DMA_BURST_LENGTH_2 (BIT(9)) -#define BUS_MODE_DMA_BURST_LENGTH_4 (BIT(10)) -#define BUS_MODE_DMA_BURST_LENGTH_8 (BIT(11)) -#define BUS_MODE_DMA_BURST_LENGTH_16 (BIT(12)) -#define BUS_MODE_DMA_BURST_LENGTH_32 (BIT(13)) -#define BUS_MODE_DBO_ (BIT(20)) - -#define TX_POLL_DEMAND (0x04) - -#define RX_POLL_DEMAND (0x08) - -#define RX_BASE_ADDR (0x0C) - -#define TX_BASE_ADDR (0x10) - -#define DMAC_STATUS (0x14) -#define DMAC_STS_TS_ (7 << 20) -#define DMAC_STS_RS_ (7 << 17) -#define DMAC_STS_NIS_ (BIT(16)) -#define DMAC_STS_AIS_ (BIT(15)) -#define DMAC_STS_RWT_ (BIT(9)) -#define DMAC_STS_RXPS_ (BIT(8)) -#define DMAC_STS_RXBU_ (BIT(7)) -#define DMAC_STS_RX_ (BIT(6)) -#define DMAC_STS_TXUNF_ (BIT(5)) -#define DMAC_STS_TXBU_ (BIT(2)) -#define DMAC_STS_TXPS_ (BIT(1)) -#define DMAC_STS_TX_ (BIT(0)) - -#define DMAC_CONTROL (0x18) -#define DMAC_CONTROL_TTM_ (BIT(22)) -#define DMAC_CONTROL_SF_ (BIT(21)) -#define DMAC_CONTROL_ST_ (BIT(13)) -#define DMAC_CONTROL_OSF_ (BIT(2)) -#define DMAC_CONTROL_SR_ (BIT(1)) - -#define DMAC_INTR_ENA (0x1C) -#define DMAC_INTR_ENA_NIS_ (BIT(16)) -#define DMAC_INTR_ENA_AIS_ (BIT(15)) -#define DMAC_INTR_ENA_RWT_ (BIT(9)) -#define DMAC_INTR_ENA_RXPS_ (BIT(8)) -#define DMAC_INTR_ENA_RXBU_ (BIT(7)) -#define DMAC_INTR_ENA_RX_ (BIT(6)) -#define DMAC_INTR_ENA_TXBU_ (BIT(2)) -#define DMAC_INTR_ENA_TXPS_ (BIT(1)) -#define DMAC_INTR_ENA_TX_ (BIT(0)) - -#define MISS_FRAME_CNTR (0x20) - -#define TX_BUFF_ADDR (0x50) - -#define RX_BUFF_ADDR (0x54) - -/* Transmit Descriptor Bit Defs */ -#define TDES0_OWN_ (0x80000000) -#define TDES0_ERROR_SUMMARY_ (0x00008000) -#define TDES0_LOSS_OF_CARRIER_ (0x00000800) -#define TDES0_NO_CARRIER_ (0x00000400) -#define TDES0_LATE_COLLISION_ (0x00000200) -#define TDES0_EXCESSIVE_COLLISIONS_ (0x00000100) -#define TDES0_HEARTBEAT_FAIL_ (0x00000080) -#define TDES0_COLLISION_COUNT_MASK_ (0x00000078) -#define TDES0_COLLISION_COUNT_SHFT_ (3) -#define TDES0_EXCESSIVE_DEFERRAL_ (0x00000004) -#define TDES0_DEFERRED_ (0x00000001) - -#define TDES1_IC_ 0x80000000 -#define TDES1_LS_ 0x40000000 -#define TDES1_FS_ 0x20000000 -#define TDES1_TXCSEN_ 0x08000000 -#define TDES1_TER_ (BIT(25)) -#define TDES1_TCH_ 0x01000000 - -/* Receive Descriptor 0 Bit Defs */ -#define RDES0_OWN_ (0x80000000) -#define RDES0_FRAME_LENGTH_MASK_ (0x07FF0000) -#define RDES0_FRAME_LENGTH_SHFT_ (16) -#define RDES0_ERROR_SUMMARY_ (0x00008000) -#define RDES0_DESCRIPTOR_ERROR_ (0x00004000) -#define RDES0_LENGTH_ERROR_ (0x00001000) -#define RDES0_RUNT_FRAME_ (0x00000800) -#define RDES0_MULTICAST_FRAME_ (0x00000400) -#define RDES0_FIRST_DESCRIPTOR_ (0x00000200) -#define RDES0_LAST_DESCRIPTOR_ (0x00000100) -#define RDES0_FRAME_TOO_LONG_ (0x00000080) -#define RDES0_COLLISION_SEEN_ (0x00000040) -#define RDES0_FRAME_TYPE_ (0x00000020) -#define RDES0_WATCHDOG_TIMEOUT_ (0x00000010) -#define RDES0_MII_ERROR_ (0x00000008) -#define RDES0_DRIBBLING_BIT_ (0x00000004) -#define RDES0_CRC_ERROR_ (0x00000002) - -/* Receive Descriptor 1 Bit Defs */ -#define RDES1_RER_ (0x02000000) - -/***********************************************/ -/* MAC Control and Status Registers */ -/***********************************************/ -#define MAC_CR (0x80) -#define MAC_CR_RXALL_ (0x80000000) -#define MAC_CR_DIS_RXOWN_ (0x00800000) -#define MAC_CR_LOOPBK_ (0x00200000) -#define MAC_CR_FDPX_ (0x00100000) -#define MAC_CR_MCPAS_ (0x00080000) -#define MAC_CR_PRMS_ (0x00040000) -#define MAC_CR_INVFILT_ (0x00020000) -#define MAC_CR_PASSBAD_ (0x00010000) -#define MAC_CR_HFILT_ (0x00008000) -#define MAC_CR_HPFILT_ (0x00002000) -#define MAC_CR_LCOLL_ (0x00001000) -#define MAC_CR_DIS_BCAST_ (0x00000800) -#define MAC_CR_DIS_RTRY_ (0x00000400) -#define MAC_CR_PADSTR_ (0x00000100) -#define MAC_CR_BOLMT_MSK (0x000000C0) -#define MAC_CR_MFCHK_ (0x00000020) -#define MAC_CR_TXEN_ (0x00000008) -#define MAC_CR_RXEN_ (0x00000004) - -#define ADDRH (0x84) - -#define ADDRL (0x88) - -#define HASHH (0x8C) - -#define HASHL (0x90) - -#define MII_ACCESS (0x94) -#define MII_ACCESS_MII_BUSY_ (0x00000001) -#define MII_ACCESS_MII_WRITE_ (0x00000002) -#define MII_ACCESS_MII_READ_ (0x00000000) -#define MII_ACCESS_INDX_MSK_ (0x000007C0) -#define MII_ACCESS_PHYADDR_MSK_ (0x0000F8C0) -#define MII_ACCESS_INDX_SHFT_CNT (6) -#define MII_ACCESS_PHYADDR_SHFT_CNT (11) - -#define MII_DATA (0x98) - -#define FLOW (0x9C) - -#define VLAN1 (0xA0) - -#define VLAN2 (0xA4) - -#define WUFF (0xA8) - -#define WUCSR (0xAC) - -#define COE_CR (0xB0) -#define TX_COE_EN (0x00010000) -#define RX_COE_MODE (0x00000002) -#define RX_COE_EN (0x00000001) - -/***********************************************/ -/* System Control and Status Registers */ -/***********************************************/ -#define ID_REV (0xC0) - -#define INT_CTL (0xC4) -#define INT_CTL_SW_INT_EN_ (0x00008000) -#define INT_CTL_SBERR_INT_EN_ (1 << 12) -#define INT_CTL_MBERR_INT_EN_ (1 << 13) -#define INT_CTL_GPT_INT_EN_ (0x00000008) -#define INT_CTL_PHY_INT_EN_ (0x00000004) -#define INT_CTL_WAKE_INT_EN_ (0x00000002) - -#define INT_STAT (0xC8) -#define INT_STAT_SW_INT_ (1 << 15) -#define INT_STAT_MBERR_INT_ (1 << 13) -#define INT_STAT_SBERR_INT_ (1 << 12) -#define INT_STAT_GPT_INT_ (1 << 3) -#define INT_STAT_PHY_INT_ (0x00000004) -#define INT_STAT_WAKE_INT_ (0x00000002) -#define INT_STAT_DMAC_INT_ (0x00000001) - -#define INT_CFG (0xCC) -#define INT_CFG_IRQ_INT_ (0x00080000) -#define INT_CFG_IRQ_EN_ (0x00040000) -#define INT_CFG_INT_DEAS_CLR_ (0x00000200) -#define INT_CFG_INT_DEAS_MASK (0x000000FF) - -#define GPIO_CFG (0xD0) -#define GPIO_CFG_LED_3_ (0x40000000) -#define GPIO_CFG_LED_2_ (0x20000000) -#define GPIO_CFG_LED_1_ (0x10000000) -#define GPIO_CFG_EEPR_EN_ (0x00700000) - -#define GPT_CFG (0xD4) -#define GPT_CFG_TIMER_EN_ (0x20000000) - -#define GPT_CNT (0xD8) - -#define BUS_CFG (0xDC) -#define BUS_CFG_RXTXWEIGHT_1_1 (0 << 25) -#define BUS_CFG_RXTXWEIGHT_2_1 (1 << 25) -#define BUS_CFG_RXTXWEIGHT_3_1 (2 << 25) -#define BUS_CFG_RXTXWEIGHT_4_1 (3 << 25) - -#define PMT_CTRL (0xE0) - -#define FREE_RUN (0xF4) - -#define E2P_CMD (0xF8) -#define E2P_CMD_EPC_BUSY_ (0x80000000) -#define E2P_CMD_EPC_CMD_ (0x70000000) -#define E2P_CMD_EPC_CMD_READ_ (0x00000000) -#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) -#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) -#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) -#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) -#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) -#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) -#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) -#define E2P_CMD_EPC_TIMEOUT_ (0x00000200) -#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100) -#define E2P_CMD_EPC_ADDR_ (0x000000FF) - -#define E2P_DATA (0xFC) -#define E2P_DATA_EEPROM_DATA_ (0x000000FF) - -#endif /* _SMSC9420_H */ |