diff options
Diffstat (limited to 'drivers/net/arm')
-rw-r--r-- | drivers/net/arm/Kconfig | 74 | ||||
-rw-r--r-- | drivers/net/arm/Makefile | 14 | ||||
-rw-r--r-- | drivers/net/arm/am79c961a.c | 770 | ||||
-rw-r--r-- | drivers/net/arm/am79c961a.h | 145 | ||||
-rw-r--r-- | drivers/net/arm/at91_ether.c | 1254 | ||||
-rw-r--r-- | drivers/net/arm/at91_ether.h | 109 | ||||
-rw-r--r-- | drivers/net/arm/ep93xx_eth.c | 904 | ||||
-rw-r--r-- | drivers/net/arm/ether1.c | 1094 | ||||
-rw-r--r-- | drivers/net/arm/ether1.h | 280 | ||||
-rw-r--r-- | drivers/net/arm/ether3.c | 918 | ||||
-rw-r--r-- | drivers/net/arm/ether3.h | 176 | ||||
-rw-r--r-- | drivers/net/arm/etherh.c | 866 | ||||
-rw-r--r-- | drivers/net/arm/ixp4xx_eth.c | 1489 | ||||
-rw-r--r-- | drivers/net/arm/ks8695net.c | 1656 | ||||
-rw-r--r-- | drivers/net/arm/ks8695net.h | 107 | ||||
-rw-r--r-- | drivers/net/arm/w90p910_ether.c | 1123 |
16 files changed, 0 insertions, 10979 deletions
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig deleted file mode 100644 index 39e1c0d3947..00000000000 --- a/drivers/net/arm/Kconfig +++ /dev/null @@ -1,74 +0,0 @@ -# -# Acorn Network device configuration -# These are for Acorn's Expansion card network interfaces -# -config ARM_AM79C961A - bool "ARM EBSA110 AM79C961A support" - depends on ARM && ARCH_EBSA110 - select CRC32 - help - If you wish to compile a kernel for the EBSA-110, then you should - always answer Y to this. - -config ARM_ETHER1 - tristate "Acorn Ether1 support" - depends on ARM && ARCH_ACORN - help - If you have an Acorn system with one of these (AKA25) network cards, - you should say Y to this option if you wish to use it with Linux. - -config ARM_ETHER3 - tristate "Acorn/ANT Ether3 support" - depends on ARM && ARCH_ACORN - help - If you have an Acorn system with one of these network cards, you - should say Y to this option if you wish to use it with Linux. - -config ARM_ETHERH - tristate "I-cubed EtherH/ANT EtherM support" - depends on ARM && ARCH_ACORN - select CRC32 - help - If you have an Acorn system with one of these network cards, you - should say Y to this option if you wish to use it with Linux. - -config ARM_AT91_ETHER - tristate "AT91RM9200 Ethernet support" - depends on ARM && ARCH_AT91RM9200 - select MII - help - If you wish to compile a kernel for the AT91RM9200 and enable - ethernet support, then you should always answer Y to this. - -config ARM_KS8695_ETHER - tristate "KS8695 Ethernet support" - depends on ARM && ARCH_KS8695 - select MII - help - If you wish to compile a kernel for the KS8695 and want to - use the internal ethernet then you should answer Y to this. - -config EP93XX_ETH - tristate "EP93xx Ethernet support" - depends on ARM && ARCH_EP93XX - select MII - help - This is a driver for the ethernet hardware included in EP93xx CPUs. - Say Y if you are building a kernel for EP93xx based devices. - -config IXP4XX_ETH - tristate "Intel IXP4xx Ethernet support" - depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR - select PHYLIB - help - Say Y here if you want to use built-in Ethernet ports - on IXP4xx processor. - -config W90P910_ETH - tristate "Nuvoton w90p910 Ethernet support" - depends on ARM && ARCH_W90X900 - select PHYLIB - select MII - help - Say Y here if you want to use built-in Ethernet ports - on w90p910 processor. diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile deleted file mode 100644 index 303171f589e..00000000000 --- a/drivers/net/arm/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# File: drivers/net/arm/Makefile -# -# Makefile for the ARM network device drivers -# - -obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o -obj-$(CONFIG_ARM_ETHERH) += etherh.o -obj-$(CONFIG_ARM_ETHER3) += ether3.o -obj-$(CONFIG_ARM_ETHER1) += ether1.o -obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o -obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o -obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o -obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o -obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c deleted file mode 100644 index 3b1416e3d21..00000000000 --- a/drivers/net/arm/am79c961a.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * linux/drivers/net/am79c961.c - * - * by Russell King <rmk@arm.linux.org.uk> 1995-2001. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Derived from various things including skeleton.c - * - * This is a special driver for the am79c961A Lance chip used in the - * Intel (formally Digital Equipment Corp) EBSA110 platform. Please - * note that this can not be built as a module (it doesn't make sense). - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/crc32.h> -#include <linux/bitops.h> -#include <linux/platform_device.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/system.h> - -#define TX_BUFFERS 15 -#define RX_BUFFERS 25 - -#include "am79c961a.h" - -static irqreturn_t -am79c961_interrupt (int irq, void *dev_id); - -static unsigned int net_debug = NET_DEBUG; - -static const char version[] = - "am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n"; - -/* --------------------------------------------------------------------------- */ - -#ifdef __arm__ -static void write_rreg(u_long base, u_int reg, u_int val) -{ - asm volatile( - "str%?h %1, [%2] @ NET_RAP\n\t" - "str%?h %0, [%2, #-4] @ NET_RDP" - : - : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); -} - -static inline unsigned short read_rreg(u_long base_addr, u_int reg) -{ - unsigned short v; - asm volatile( - "str%?h %1, [%2] @ NET_RAP\n\t" - "ldr%?h %0, [%2, #-4] @ NET_RDP" - : "=r" (v) - : "r" (reg), "r" (ISAIO_BASE + 0x0464)); - return v; -} - -static inline void write_ireg(u_long base, u_int reg, u_int val) -{ - asm volatile( - "str%?h %1, [%2] @ NET_RAP\n\t" - "str%?h %0, [%2, #8] @ NET_IDP" - : - : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); -} - -static inline unsigned short read_ireg(u_long base_addr, u_int reg) -{ - u_short v; - asm volatile( - "str%?h %1, [%2] @ NAT_RAP\n\t" - "ldr%?h %0, [%2, #8] @ NET_IDP\n\t" - : "=r" (v) - : "r" (reg), "r" (ISAIO_BASE + 0x0464)); - return v; -} - -#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1)) -#define am_readword(dev,off) __raw_readw(ISAMEM_BASE + ((off) << 1)) - -static void -am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) -{ - offset = ISAMEM_BASE + (offset << 1); - length = (length + 1) & ~1; - if ((int)buf & 2) { - asm volatile("str%?h %2, [%0], #4" - : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); - buf += 2; - length -= 2; - } - while (length > 8) { - register unsigned int tmp asm("r2"), tmp2 asm("r3"); - asm volatile( - "ldm%?ia %0!, {%1, %2}" - : "+r" (buf), "=&r" (tmp), "=&r" (tmp2)); - length -= 8; - asm volatile( - "str%?h %1, [%0], #4\n\t" - "mov%? %1, %1, lsr #16\n\t" - "str%?h %1, [%0], #4\n\t" - "str%?h %2, [%0], #4\n\t" - "mov%? %2, %2, lsr #16\n\t" - "str%?h %2, [%0], #4" - : "+r" (offset), "=&r" (tmp), "=&r" (tmp2)); - } - while (length > 0) { - asm volatile("str%?h %2, [%0], #4" - : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); - buf += 2; - length -= 2; - } -} - -static void -am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length) -{ - offset = ISAMEM_BASE + (offset << 1); - length = (length + 1) & ~1; - if ((int)buf & 2) { - unsigned int tmp; - asm volatile( - "ldr%?h %2, [%0], #4\n\t" - "str%?b %2, [%1], #1\n\t" - "mov%? %2, %2, lsr #8\n\t" - "str%?b %2, [%1], #1" - : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); - length -= 2; - } - while (length > 8) { - register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3; - asm volatile( - "ldr%?h %2, [%0], #4\n\t" - "ldr%?h %4, [%0], #4\n\t" - "ldr%?h %3, [%0], #4\n\t" - "orr%? %2, %2, %4, lsl #16\n\t" - "ldr%?h %4, [%0], #4\n\t" - "orr%? %3, %3, %4, lsl #16\n\t" - "stm%?ia %1!, {%2, %3}" - : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) - : "0" (offset), "1" (buf)); - length -= 8; - } - while (length > 0) { - unsigned int tmp; - asm volatile( - "ldr%?h %2, [%0], #4\n\t" - "str%?b %2, [%1], #1\n\t" - "mov%? %2, %2, lsr #8\n\t" - "str%?b %2, [%1], #1" - : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); - length -= 2; - } -} -#else -#error Not compatible -#endif - -static int -am79c961_ramtest(struct net_device *dev, unsigned int val) -{ - unsigned char *buffer = kmalloc (65536, GFP_KERNEL); - int i, error = 0, errorcount = 0; - - if (!buffer) - return 0; - memset (buffer, val, 65536); - am_writebuffer(dev, 0, buffer, 65536); - memset (buffer, val ^ 255, 65536); - am_readbuffer(dev, 0, buffer, 65536); - for (i = 0; i < 65536; i++) { - if (buffer[i] != val && !error) { - printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i); - error = 1; - errorcount ++; - } else if (error && buffer[i] == val) { - printk ("%05X\n", i); - error = 0; - } - } - if (error) - printk ("10000\n"); - kfree (buffer); - return errorcount; -} - -static void am79c961_mc_hash(char *addr, u16 *hash) -{ - int idx, bit; - u32 crc; - - crc = ether_crc_le(ETH_ALEN, addr); - - idx = crc >> 30; - bit = (crc >> 26) & 15; - - hash[idx] |= 1 << bit; -} - -static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash) -{ - unsigned int mode = MODE_PORT_10BT; - - if (dev->flags & IFF_PROMISC) { - mode |= MODE_PROMISC; - memset(hash, 0xff, 4 * sizeof(*hash)); - } else if (dev->flags & IFF_ALLMULTI) { - memset(hash, 0xff, 4 * sizeof(*hash)); - } else { - struct netdev_hw_addr *ha; - - memset(hash, 0, 4 * sizeof(*hash)); - - netdev_for_each_mc_addr(ha, dev) - am79c961_mc_hash(ha->addr, hash); - } - - return mode; -} - -static void -am79c961_init_for_open(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - unsigned long flags; - unsigned char *p; - u_int hdr_addr, first_free_addr; - u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash); - int i; - - /* - * Stop the chip. - */ - spin_lock_irqsave(&priv->chip_lock, flags); - write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP); - spin_unlock_irqrestore(&priv->chip_lock, flags); - - write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */ - write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */ - write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */ - write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ - - for (i = LADRL; i <= LADRH; i++) - write_rreg (dev->base_addr, i, multi_hash[i - LADRL]); - - for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) - write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); - - write_rreg (dev->base_addr, MODE, mode); - write_rreg (dev->base_addr, POLLINT, 0); - write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); - write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); - - first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16; - hdr_addr = 0; - - priv->rxhead = 0; - priv->rxtail = 0; - priv->rxhdr = hdr_addr; - - for (i = 0; i < RX_BUFFERS; i++) { - priv->rxbuffer[i] = first_free_addr; - am_writeword (dev, hdr_addr, first_free_addr); - am_writeword (dev, hdr_addr + 2, RMD_OWN); - am_writeword (dev, hdr_addr + 4, (-1600)); - am_writeword (dev, hdr_addr + 6, 0); - first_free_addr += 1600; - hdr_addr += 8; - } - priv->txhead = 0; - priv->txtail = 0; - priv->txhdr = hdr_addr; - for (i = 0; i < TX_BUFFERS; i++) { - priv->txbuffer[i] = first_free_addr; - am_writeword (dev, hdr_addr, first_free_addr); - am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP); - am_writeword (dev, hdr_addr + 4, 0xf000); - am_writeword (dev, hdr_addr + 6, 0); - first_free_addr += 1600; - hdr_addr += 8; - } - - write_rreg (dev->base_addr, BASERXL, priv->rxhdr); - write_rreg (dev->base_addr, BASERXH, 0); - write_rreg (dev->base_addr, BASETXL, priv->txhdr); - write_rreg (dev->base_addr, BASERXH, 0); - write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); - write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM); - write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); -} - -static void am79c961_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct dev_priv *priv = netdev_priv(dev); - unsigned int lnkstat, carrier; - unsigned long flags; - - spin_lock_irqsave(&priv->chip_lock, flags); - lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; - spin_unlock_irqrestore(&priv->chip_lock, flags); - carrier = netif_carrier_ok(dev); - - if (lnkstat && !carrier) { - netif_carrier_on(dev); - printk("%s: link up\n", dev->name); - } else if (!lnkstat && carrier) { - netif_carrier_off(dev); - printk("%s: link down\n", dev->name); - } - - mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500)); -} - -/* - * Open/initialize the board. - */ -static int -am79c961_open(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - int ret; - - ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev); - if (ret) - return ret; - - am79c961_init_for_open(dev); - - netif_carrier_off(dev); - - priv->timer.expires = jiffies; - add_timer(&priv->timer); - - netif_start_queue(dev); - - return 0; -} - -/* - * The inverse routine to am79c961_open(). - */ -static int -am79c961_close(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - unsigned long flags; - - del_timer_sync(&priv->timer); - - netif_stop_queue(dev); - netif_carrier_off(dev); - - spin_lock_irqsave(&priv->chip_lock, flags); - write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); - spin_unlock_irqrestore(&priv->chip_lock, flags); - - free_irq (dev->irq, dev); - - return 0; -} - -/* - * Set or clear promiscuous/multicast mode filter for this adapter. - */ -static void am79c961_setmulticastlist (struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - unsigned long flags; - u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash); - int i, stopped; - - spin_lock_irqsave(&priv->chip_lock, flags); - - stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; - - if (!stopped) { - /* - * Put the chip into suspend mode - */ - write_rreg(dev->base_addr, CTRL1, CTRL1_SPND); - - /* - * Spin waiting for chip to report suspend mode - */ - while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) { - spin_unlock_irqrestore(&priv->chip_lock, flags); - nop(); - spin_lock_irqsave(&priv->chip_lock, flags); - } - } - - /* - * Update the multicast hash table - */ - for (i = 0; i < ARRAY_SIZE(multi_hash); i++) - write_rreg(dev->base_addr, i + LADRL, multi_hash[i]); - - /* - * Write the mode register - */ - write_rreg(dev->base_addr, MODE, mode); - - if (!stopped) { - /* - * Put the chip back into running mode - */ - write_rreg(dev->base_addr, CTRL1, 0); - } - - spin_unlock_irqrestore(&priv->chip_lock, flags); -} - -static void am79c961_timeout(struct net_device *dev) -{ - printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n", - dev->name); - - /* - * ought to do some setup of the tx side here - */ - - netif_wake_queue(dev); -} - -/* - * Transmit a packet - */ -static int -am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - unsigned int hdraddr, bufaddr; - unsigned int head; - unsigned long flags; - - head = priv->txhead; - hdraddr = priv->txhdr + (head << 3); - bufaddr = priv->txbuffer[head]; - head += 1; - if (head >= TX_BUFFERS) - head = 0; - - am_writebuffer (dev, bufaddr, skb->data, skb->len); - am_writeword (dev, hdraddr + 4, -skb->len); - am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); - priv->txhead = head; - - spin_lock_irqsave(&priv->chip_lock, flags); - write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); - spin_unlock_irqrestore(&priv->chip_lock, flags); - - /* - * If the next packet is owned by the ethernet device, - * then the tx ring is full and we can't add another - * packet. - */ - if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) - netif_stop_queue(dev); - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/* - * If we have a good packet(s), get it/them out of the buffers. - */ -static void -am79c961_rx(struct net_device *dev, struct dev_priv *priv) -{ - do { - struct sk_buff *skb; - u_int hdraddr; - u_int pktaddr; - u_int status; - int len; - - hdraddr = priv->rxhdr + (priv->rxtail << 3); - pktaddr = priv->rxbuffer[priv->rxtail]; - - status = am_readword (dev, hdraddr + 2); - if (status & RMD_OWN) /* do we own it? */ - break; - - priv->rxtail ++; - if (priv->rxtail >= RX_BUFFERS) - priv->rxtail = 0; - - if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) { - am_writeword (dev, hdraddr + 2, RMD_OWN); - dev->stats.rx_errors++; - if (status & RMD_ERR) { - if (status & RMD_FRAM) - dev->stats.rx_frame_errors++; - if (status & RMD_CRC) - dev->stats.rx_crc_errors++; - } else if (status & RMD_STP) - dev->stats.rx_length_errors++; - continue; - } - - len = am_readword(dev, hdraddr + 6); - skb = dev_alloc_skb(len + 2); - - if (skb) { - skb_reserve(skb, 2); - - am_readbuffer(dev, pktaddr, skb_put(skb, len), len); - am_writeword(dev, hdraddr + 2, RMD_OWN); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_bytes += len; - dev->stats.rx_packets++; - } else { - am_writeword (dev, hdraddr + 2, RMD_OWN); - printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; - break; - } - } while (1); -} - -/* - * Update stats for the transmitted packet - */ -static void -am79c961_tx(struct net_device *dev, struct dev_priv *priv) -{ - do { - short len; - u_int hdraddr; - u_int status; - - hdraddr = priv->txhdr + (priv->txtail << 3); - status = am_readword (dev, hdraddr + 2); - if (status & TMD_OWN) - break; - - priv->txtail ++; - if (priv->txtail >= TX_BUFFERS) - priv->txtail = 0; - - if (status & TMD_ERR) { - u_int status2; - - dev->stats.tx_errors++; - - status2 = am_readword (dev, hdraddr + 6); - - /* - * Clear the error byte - */ - am_writeword (dev, hdraddr + 6, 0); - - if (status2 & TST_RTRY) - dev->stats.collisions += 16; - if (status2 & TST_LCOL) - dev->stats.tx_window_errors++; - if (status2 & TST_LCAR) - dev->stats.tx_carrier_errors++; - if (status2 & TST_UFLO) - dev->stats.tx_fifo_errors++; - continue; - } - dev->stats.tx_packets++; - len = am_readword (dev, hdraddr + 4); - dev->stats.tx_bytes += -len; - } while (priv->txtail != priv->txhead); - - netif_wake_queue(dev); -} - -static irqreturn_t -am79c961_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct dev_priv *priv = netdev_priv(dev); - u_int status, n = 100; - int handled = 0; - - do { - status = read_rreg(dev->base_addr, CSR0); - write_rreg(dev->base_addr, CSR0, status & - (CSR0_IENA|CSR0_TINT|CSR0_RINT| - CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL)); - - if (status & CSR0_RINT) { - handled = 1; - am79c961_rx(dev, priv); - } - if (status & CSR0_TINT) { - handled = 1; - am79c961_tx(dev, priv); - } - if (status & CSR0_MISS) { - handled = 1; - dev->stats.rx_dropped++; - } - if (status & CSR0_CERR) { - handled = 1; - mod_timer(&priv->timer, jiffies); - } - } while (--n && status & (CSR0_RINT | CSR0_TINT)); - - return IRQ_RETVAL(handled); -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void am79c961_poll_controller(struct net_device *dev) -{ - unsigned long flags; - local_irq_save(flags); - am79c961_interrupt(dev->irq, dev); - local_irq_restore(flags); -} -#endif - -/* - * Initialise the chip. Note that we always expect - * to be entered with interrupts enabled. - */ -static int -am79c961_hw_init(struct net_device *dev) -{ - struct dev_priv *priv = netdev_priv(dev); - - spin_lock_irq(&priv->chip_lock); - write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); - spin_unlock_irq(&priv->chip_lock); - - am79c961_ramtest(dev, 0x66); - am79c961_ramtest(dev, 0x99); - - return 0; -} - -static void __init am79c961_banner(void) -{ - static unsigned version_printed; - - if (net_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); -} -static const struct net_device_ops am79c961_netdev_ops = { - .ndo_open = am79c961_open, - .ndo_stop = am79c961_close, - .ndo_start_xmit = am79c961_sendpacket, - .ndo_set_multicast_list = am79c961_setmulticastlist, - .ndo_tx_timeout = am79c961_timeout, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = am79c961_poll_controller, -#endif -}; - -static int __devinit am79c961_probe(struct platform_device *pdev) -{ - struct resource *res; - struct net_device *dev; - struct dev_priv *priv; - int i, ret; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!res) - return -ENODEV; - - dev = alloc_etherdev(sizeof(struct dev_priv)); - ret = -ENOMEM; - if (!dev) - goto out; - - SET_NETDEV_DEV(dev, &pdev->dev); - - priv = netdev_priv(dev); - - /* - * Fixed address and IRQ lines here. - * The PNP initialisation should have been - * done by the ether bootp loader. - */ - dev->base_addr = res->start; - ret = platform_get_irq(pdev, 0); - - if (ret < 0) { - ret = -ENODEV; - goto nodev; - } - dev->irq = ret; - - ret = -ENODEV; - if (!request_region(dev->base_addr, 0x18, dev->name)) - goto nodev; - - /* - * Reset the device. - */ - inb(dev->base_addr + NET_RESET); - udelay(5); - - /* - * Check the manufacturer part of the - * ether address. - */ - if (inb(dev->base_addr) != 0x08 || - inb(dev->base_addr + 2) != 0x00 || - inb(dev->base_addr + 4) != 0x2b) - goto release; - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff; - - am79c961_banner(); - - spin_lock_init(&priv->chip_lock); - init_timer(&priv->timer); - priv->timer.data = (unsigned long)dev; - priv->timer.function = am79c961_timer; - - if (am79c961_hw_init(dev)) - goto release; - - dev->netdev_ops = &am79c961_netdev_ops; - - ret = register_netdev(dev); - if (ret == 0) { - printk(KERN_INFO "%s: ether address %pM\n", - dev->name, dev->dev_addr); - return 0; - } - -release: - release_region(dev->base_addr, 0x18); -nodev: - free_netdev(dev); -out: - return ret; -} - -static struct platform_driver am79c961_driver = { - .probe = am79c961_probe, - .driver = { - .name = "am79c961", - }, -}; - -static int __init am79c961_init(void) -{ - return platform_driver_register(&am79c961_driver); -} - -__initcall(am79c961_init); diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h deleted file mode 100644 index fd634d32756..00000000000 --- a/drivers/net/arm/am79c961a.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * linux/drivers/net/arm/am79c961a.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _LINUX_am79c961a_H -#define _LINUX_am79c961a_H - -/* use 0 for production, 1 for verification, >2 for debug. debug flags: */ -#define DEBUG_TX 2 -#define DEBUG_RX 4 -#define DEBUG_INT 8 -#define DEBUG_IC 16 -#ifndef NET_DEBUG -#define NET_DEBUG 0 -#endif - -#define NET_UID 0 -#define NET_RDP 0x10 -#define NET_RAP 0x12 -#define NET_RESET 0x14 -#define NET_IDP 0x16 - -/* - * RAP registers - */ -#define CSR0 0 -#define CSR0_INIT 0x0001 -#define CSR0_STRT 0x0002 -#define CSR0_STOP 0x0004 -#define CSR0_TDMD 0x0008 -#define CSR0_TXON 0x0010 -#define CSR0_RXON 0x0020 -#define CSR0_IENA 0x0040 -#define CSR0_INTR 0x0080 -#define CSR0_IDON 0x0100 -#define CSR0_TINT 0x0200 -#define CSR0_RINT 0x0400 -#define CSR0_MERR 0x0800 -#define CSR0_MISS 0x1000 -#define CSR0_CERR 0x2000 -#define CSR0_BABL 0x4000 -#define CSR0_ERR 0x8000 - -#define CSR3 3 -#define CSR3_EMBA 0x0008 -#define CSR3_DXMT2PD 0x0010 -#define CSR3_LAPPEN 0x0020 -#define CSR3_DXSUFLO 0x0040 -#define CSR3_IDONM 0x0100 -#define CSR3_TINTM 0x0200 -#define CSR3_RINTM 0x0400 -#define CSR3_MERRM 0x0800 -#define CSR3_MISSM 0x1000 -#define CSR3_BABLM 0x4000 -#define CSR3_MASKALL 0x5F00 - -#define CSR4 4 -#define CSR4_JABM 0x0001 -#define CSR4_JAB 0x0002 -#define CSR4_TXSTRTM 0x0004 -#define CSR4_TXSTRT 0x0008 -#define CSR4_RCVCCOM 0x0010 -#define CSR4_RCVCCO 0x0020 -#define CSR4_MFCOM 0x0100 -#define CSR4_MFCO 0x0200 -#define CSR4_ASTRP_RCV 0x0400 -#define CSR4_APAD_XMIT 0x0800 - -#define CTRL1 5 -#define CTRL1_SPND 0x0001 - -#define LADRL 8 -#define LADRM1 9 -#define LADRM2 10 -#define LADRH 11 -#define PADRL 12 -#define PADRM 13 -#define PADRH 14 - -#define MODE 15 -#define MODE_DISRX 0x0001 -#define MODE_DISTX 0x0002 -#define MODE_LOOP 0x0004 -#define MODE_DTCRC 0x0008 -#define MODE_COLL 0x0010 -#define MODE_DRETRY 0x0020 -#define MODE_INTLOOP 0x0040 -#define MODE_PORT_AUI 0x0000 -#define MODE_PORT_10BT 0x0080 -#define MODE_DRXPA 0x2000 -#define MODE_DRXBA 0x4000 -#define MODE_PROMISC 0x8000 - -#define BASERXL 24 -#define BASERXH 25 -#define BASETXL 30 -#define BASETXH 31 - -#define POLLINT 47 - -#define SIZERXR 76 -#define SIZETXR 78 - -#define CSR_MFC 112 - -#define RMD_ENP 0x0100 -#define RMD_STP 0x0200 -#define RMD_CRC 0x0800 -#define RMD_FRAM 0x2000 -#define RMD_ERR 0x4000 -#define RMD_OWN 0x8000 - -#define TMD_ENP 0x0100 -#define TMD_STP 0x0200 -#define TMD_MORE 0x1000 -#define TMD_ERR 0x4000 -#define TMD_OWN 0x8000 - -#define TST_RTRY 0x0400 -#define TST_LCAR 0x0800 -#define TST_LCOL 0x1000 -#define TST_UFLO 0x4000 -#define TST_BUFF 0x8000 - -#define ISALED0 0x0004 -#define ISALED0_LNKST 0x8000 - -struct dev_priv { - unsigned long rxbuffer[RX_BUFFERS]; - unsigned long txbuffer[TX_BUFFERS]; - unsigned char txhead; - unsigned char txtail; - unsigned char rxhead; - unsigned char rxtail; - unsigned long rxhdr; - unsigned long txhdr; - spinlock_t chip_lock; - struct timer_list timer; -}; - -#endif diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c deleted file mode 100644 index 29dc43523ce..00000000000 --- a/drivers/net/arm/at91_ether.c +++ /dev/null @@ -1,1254 +0,0 @@ -/* - * Ethernet driver for the Atmel AT91RM9200 (Thunder) - * - * Copyright (C) 2003 SAN People (Pty) Ltd - * - * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc. - * Initial version by Rick Bronson 01/11/2003 - * - * Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker - * (Polaroid Corporation) - * - * Realtek RTL8201(B)L PHY support by Roman Avramenko <roman@imsystems.ru> - * - * 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. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/mii.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/dma-mapping.h> -#include <linux/ethtool.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/gfp.h> - -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/mach-types.h> - -#include <mach/at91rm9200_emac.h> -#include <mach/gpio.h> -#include <mach/board.h> - -#include "at91_ether.h" - -#define DRV_NAME "at91_ether" -#define DRV_VERSION "1.0" - -#define LINK_POLL_INTERVAL (HZ) - -/* ..................................................................... */ - -/* - * Read from a EMAC register. - */ -static inline unsigned long at91_emac_read(unsigned int reg) -{ - void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC; - - return __raw_readl(emac_base + reg); -} - -/* - * Write to a EMAC register. - */ -static inline void at91_emac_write(unsigned int reg, unsigned long value) -{ - void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC; - - __raw_writel(value, emac_base + reg); -} - -/* ........................... PHY INTERFACE ........................... */ - -/* - * Enable the MDIO bit in MAC control register - * When not called from an interrupt-handler, access to the PHY must be - * protected by a spinlock. - */ -static void enable_mdi(void) -{ - unsigned long ctl; - - ctl = at91_emac_read(AT91_EMAC_CTL); - at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */ -} - -/* - * Disable the MDIO bit in the MAC control register - */ -static void disable_mdi(void) -{ - unsigned long ctl; - - ctl = at91_emac_read(AT91_EMAC_CTL); - at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */ -} - -/* - * Wait until the PHY operation is complete. - */ -static inline void at91_phy_wait(void) { - unsigned long timeout = jiffies + 2; - - while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) { - if (time_after(jiffies, timeout)) { - printk("at91_ether: MIO timeout\n"); - break; - } - cpu_relax(); - } -} - -/* - * Write value to the a PHY register - * Note: MDI interface is assumed to already have been enabled. - */ -static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value) -{ - at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W - | ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA)); - - /* Wait until IDLE bit in Network Status register is cleared */ - at91_phy_wait(); -} - -/* - * Read value stored in a PHY register. - * Note: MDI interface is assumed to already have been enabled. - */ -static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value) -{ - at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R - | ((phy_addr & 0x1f) << 23) | (address << 18)); - - /* Wait until IDLE bit in Network Status register is cleared */ - at91_phy_wait(); - - *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA; -} - -/* ........................... PHY MANAGEMENT .......................... */ - -/* - * Access the PHY to determine the current link speed and mode, and update the - * MAC accordingly. - * If no link or auto-negotiation is busy, then no changes are made. - */ -static void update_linkspeed(struct net_device *dev, int silent) -{ - struct at91_private *lp = netdev_priv(dev); - unsigned int bmsr, bmcr, lpa, mac_cfg; - unsigned int speed, duplex; - - if (!mii_link_ok(&lp->mii)) { /* no link */ - netif_carrier_off(dev); - if (!silent) - printk(KERN_INFO "%s: Link down.\n", dev->name); - return; - } - - /* Link up, or auto-negotiation still in progress */ - read_phy(lp->phy_address, MII_BMSR, &bmsr); - read_phy(lp->phy_address, MII_BMCR, &bmcr); - if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */ - if (!(bmsr & BMSR_ANEGCOMPLETE)) - return; /* Do nothing - another interrupt generated when negotiation complete */ - - read_phy(lp->phy_address, MII_LPA, &lpa); - if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100; - else speed = SPEED_10; - if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL; - else duplex = DUPLEX_HALF; - } else { - speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; - duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; - } - - /* Update the MAC */ - mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD); - if (speed == SPEED_100) { - if (duplex == DUPLEX_FULL) /* 100 Full Duplex */ - mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD; - else /* 100 Half Duplex */ - mac_cfg |= AT91_EMAC_SPD; - } else { - if (duplex == DUPLEX_FULL) /* 10 Full Duplex */ - mac_cfg |= AT91_EMAC_FD; - else {} /* 10 Half Duplex */ - } - at91_emac_write(AT91_EMAC_CFG, mac_cfg); - - if (!silent) - printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); - netif_carrier_on(dev); -} - -/* - * Handle interrupts from the PHY - */ -static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct at91_private *lp = netdev_priv(dev); - unsigned int phy; - - /* - * This hander is triggered on both edges, but the PHY chips expect - * level-triggering. We therefore have to check if the PHY actually has - * an IRQ pending. - */ - enable_mdi(); - if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { - read_phy(lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */ - if (!(phy & (1 << 0))) - goto done; - } - else if (lp->phy_type == MII_LXT971A_ID) { - read_phy(lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */ - if (!(phy & (1 << 2))) - goto done; - } - else if (lp->phy_type == MII_BCM5221_ID) { - read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */ - if (!(phy & (1 << 0))) - goto done; - } - else if (lp->phy_type == MII_KS8721_ID) { - read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */ - if (!(phy & ((1 << 2) | 1))) - goto done; - } - else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */ - read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy); - if (!(phy & ((1 << 2) | 1))) - goto done; - } - else if (lp->phy_type == MII_DP83848_ID) { - read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */ - if (!(phy & (1 << 7))) - goto done; - } - - update_linkspeed(dev, 0); - -done: - disable_mdi(); - - return IRQ_HANDLED; -} - -/* - * Initialize and enable the PHY interrupt for link-state changes - */ -static void enable_phyirq(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - unsigned int dsintr, irq_number; - int status; - - irq_number = lp->board_data.phy_irq_pin; - if (!irq_number) { - /* - * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L), - * or board does not have it connected. - */ - mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); - return; - } - - status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); - if (status) { - printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); - return; - } - - spin_lock_irq(&lp->lock); - enable_mdi(); - - if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ - read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); - dsintr = dsintr & ~0xf00; /* clear bits 8..11 */ - write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); - } - else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ - read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); - dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */ - write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); - } - else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ - dsintr = (1 << 15) | ( 1 << 14); - write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); - } - else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ - dsintr = (1 << 10) | ( 1 << 8); - write_phy(lp->phy_address, MII_TPISTATUS, dsintr); - } - else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */ - read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); - dsintr = dsintr | 0x500; /* set bits 8, 10 */ - write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); - } - else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */ - read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); - dsintr = dsintr | 0x3c; /* set bits 2..5 */ - write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); - read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); - dsintr = dsintr | 0x3; /* set bits 0,1 */ - write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); - } - - disable_mdi(); - spin_unlock_irq(&lp->lock); -} - -/* - * Disable the PHY interrupt - */ -static void disable_phyirq(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - unsigned int dsintr; - unsigned int irq_number; - - irq_number = lp->board_data.phy_irq_pin; - if (!irq_number) { - del_timer_sync(&lp->check_timer); - return; - } - - spin_lock_irq(&lp->lock); - enable_mdi(); - - if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ - read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); - dsintr = dsintr | 0xf00; /* set bits 8..11 */ - write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); - } - else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ - read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); - dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */ - write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); - } - else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ - read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr); - dsintr = ~(1 << 14); - write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); - } - else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ - read_phy(lp->phy_address, MII_TPISTATUS, &dsintr); - dsintr = ~((1 << 10) | (1 << 8)); - write_phy(lp->phy_address, MII_TPISTATUS, dsintr); - } - else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */ - read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr); - dsintr = dsintr & ~0x500; /* clear bits 8, 10 */ - write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr); - } - else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */ - read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr); - dsintr = dsintr & ~0x3; /* clear bits 0, 1 */ - write_phy(lp->phy_address, MII_DPMICR_REG, dsintr); - read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr); - dsintr = dsintr & ~0x3c; /* clear bits 2..5 */ - write_phy(lp->phy_address, MII_DPMISR_REG, dsintr); - } - - disable_mdi(); - spin_unlock_irq(&lp->lock); - - free_irq(irq_number, dev); /* Free interrupt handler */ -} - -/* - * Perform a software reset of the PHY. - */ -#if 0 -static void reset_phy(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - unsigned int bmcr; - - spin_lock_irq(&lp->lock); - enable_mdi(); - - /* Perform PHY reset */ - write_phy(lp->phy_address, MII_BMCR, BMCR_RESET); - - /* Wait until PHY reset is complete */ - do { - read_phy(lp->phy_address, MII_BMCR, &bmcr); - } while (!(bmcr & BMCR_RESET)); - - disable_mdi(); - spin_unlock_irq(&lp->lock); -} -#endif - -static void at91ether_check_link(unsigned long dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct at91_private *lp = netdev_priv(dev); - - enable_mdi(); - update_linkspeed(dev, 1); - disable_mdi(); - - mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL); -} - -/* ......................... ADDRESS MANAGEMENT ........................ */ - -/* - * NOTE: Your bootloader must always set the MAC address correctly before - * booting into Linux. - * - * - It must always set the MAC address after reset, even if it doesn't - * happen to access the Ethernet while it's booting. Some versions of - * U-Boot on the AT91RM9200-DK do not do this. - * - * - Likewise it must store the addresses in the correct byte order. - * MicroMonitor (uMon) on the CSB337 does this incorrectly (and - * continues to do so, for bug-compatibility). - */ - -static short __init unpack_mac_address(struct net_device *dev, unsigned int hi, unsigned int lo) -{ - char addr[6]; - - if (machine_is_csb337()) { - addr[5] = (lo & 0xff); /* The CSB337 bootloader stores the MAC the wrong-way around */ - addr[4] = (lo & 0xff00) >> 8; - addr[3] = (lo & 0xff0000) >> 16; - addr[2] = (lo & 0xff000000) >> 24; - addr[1] = (hi & 0xff); - addr[0] = (hi & 0xff00) >> 8; - } - else { - addr[0] = (lo & 0xff); - addr[1] = (lo & 0xff00) >> 8; - addr[2] = (lo & 0xff0000) >> 16; - addr[3] = (lo & 0xff000000) >> 24; - addr[4] = (hi & 0xff); - addr[5] = (hi & 0xff00) >> 8; - } - - if (is_valid_ether_addr(addr)) { - memcpy(dev->dev_addr, &addr, 6); - return 1; - } - return 0; -} - -/* - * Set the ethernet MAC address in dev->dev_addr - */ -static void __init get_mac_address(struct net_device *dev) -{ - /* Check Specific-Address 1 */ - if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L))) - return; - /* Check Specific-Address 2 */ - if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L))) - return; - /* Check Specific-Address 3 */ - if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L))) - return; - /* Check Specific-Address 4 */ - if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L))) - return; - - printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n"); -} - -/* - * Program the hardware MAC address from dev->dev_addr. - */ -static void update_mac_address(struct net_device *dev) -{ - at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0])); - at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4])); - - at91_emac_write(AT91_EMAC_SA2L, 0); - at91_emac_write(AT91_EMAC_SA2H, 0); -} - -/* - * Store the new hardware address in dev->dev_addr, and update the MAC. - */ -static int set_mac_address(struct net_device *dev, void* addr) -{ - struct sockaddr *address = addr; - - if (!is_valid_ether_addr(address->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(dev->dev_addr, address->sa_data, dev->addr_len); - update_mac_address(dev); - - printk("%s: Setting MAC address to %pM\n", dev->name, - dev->dev_addr); - - return 0; -} - -static int inline hash_bit_value(int bitnr, __u8 *addr) -{ - if (addr[bitnr / 8] & (1 << (bitnr % 8))) - return 1; - return 0; -} - -/* - * The hash address register is 64 bits long and takes up two locations in the memory map. - * The least significant bits are stored in EMAC_HSL and the most significant - * bits in EMAC_HSH. - * - * The unicast hash enable and the multicast hash enable bits in the network configuration - * register enable the reception of hash matched frames. The destination address is - * reduced to a 6 bit index into the 64 bit hash register using the following hash function. - * The hash function is an exclusive or of every sixth bit of the destination address. - * hash_index[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] - * hash_index[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] - * hash_index[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] - * hash_index[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] - * hash_index[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] - * hash_index[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] - * da[0] represents the least significant bit of the first byte received, that is, the multicast/ - * unicast indicator, and da[47] represents the most significant bit of the last byte - * received. - * If the hash index points to a bit that is set in the hash register then the frame will be - * matched according to whether the frame is multicast or unicast. - * A multicast match will be signalled if the multicast hash enable bit is set, da[0] is 1 and - * the hash index points to a bit set in the hash register. - * A unicast match will be signalled if the unicast hash enable bit is set, da[0] is 0 and the - * hash index points to a bit set in the hash register. - * To receive all multicast frames, the hash register should be set with all ones and the - * multicast hash enable bit should be set in the network configuration register. - */ - -/* - * Return the hash index value for the specified address. - */ -static int hash_get_index(__u8 *addr) -{ - int i, j, bitval; - int hash_index = 0; - - for (j = 0; j < 6; j++) { - for (i = 0, bitval = 0; i < 8; i++) - bitval ^= hash_bit_value(i*6 + j, addr); - - hash_index |= (bitval << j); - } - - return hash_index; -} - -/* - * Add multicast addresses to the internal multicast-hash table. - */ -static void at91ether_sethashtable(struct net_device *dev) -{ - struct netdev_hw_addr *ha; - unsigned long mc_filter[2]; - unsigned int bitnr; - - mc_filter[0] = mc_filter[1] = 0; - - netdev_for_each_mc_addr(ha, dev) { - bitnr = hash_get_index(ha->addr); - mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); - } - - at91_emac_write(AT91_EMAC_HSL, mc_filter[0]); - at91_emac_write(AT91_EMAC_HSH, mc_filter[1]); -} - -/* - * Enable/Disable promiscuous and multicast modes. - */ -static void at91ether_set_multicast_list(struct net_device *dev) -{ - unsigned long cfg; - - cfg = at91_emac_read(AT91_EMAC_CFG); - - if (dev->flags & IFF_PROMISC) /* Enable promiscuous mode */ - cfg |= AT91_EMAC_CAF; - else if (dev->flags & (~IFF_PROMISC)) /* Disable promiscuous mode */ - cfg &= ~AT91_EMAC_CAF; - - if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */ - at91_emac_write(AT91_EMAC_HSH, -1); - at91_emac_write(AT91_EMAC_HSL, -1); - cfg |= AT91_EMAC_MTI; - } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */ - at91ether_sethashtable(dev); - cfg |= AT91_EMAC_MTI; - } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ - at91_emac_write(AT91_EMAC_HSH, 0); - at91_emac_write(AT91_EMAC_HSL, 0); - cfg &= ~AT91_EMAC_MTI; - } - - at91_emac_write(AT91_EMAC_CFG, cfg); -} - -/* ......................... ETHTOOL SUPPORT ........................... */ - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - unsigned int value; - - read_phy(phy_id, location, &value); - return value; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - write_phy(phy_id, location, value); -} - -static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct at91_private *lp = netdev_priv(dev); - int ret; - - spin_lock_irq(&lp->lock); - enable_mdi(); - - ret = mii_ethtool_gset(&lp->mii, cmd); - - disable_mdi(); - spin_unlock_irq(&lp->lock); - - if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */ - cmd->supported = SUPPORTED_FIBRE; - cmd->port = PORT_FIBRE; - } - - return ret; -} - -static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct at91_private *lp = netdev_priv(dev); - int ret; - - spin_lock_irq(&lp->lock); - enable_mdi(); - - ret = mii_ethtool_sset(&lp->mii, cmd); - - disable_mdi(); - spin_unlock_irq(&lp->lock); - - return ret; -} - -static int at91ether_nwayreset(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - int ret; - - spin_lock_irq(&lp->lock); - enable_mdi(); - - ret = mii_nway_restart(&lp->mii); - - disable_mdi(); - spin_unlock_irq(&lp->lock); - - return ret; -} - -static void at91ether_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)); - strlcpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info)); -} - -static const struct ethtool_ops at91ether_ethtool_ops = { - .get_settings = at91ether_get_settings, - .set_settings = at91ether_set_settings, - .get_drvinfo = at91ether_get_drvinfo, - .nway_reset = at91ether_nwayreset, - .get_link = ethtool_op_get_link, -}; - -static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct at91_private *lp = netdev_priv(dev); - int res; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irq(&lp->lock); - enable_mdi(); - res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL); - disable_mdi(); - spin_unlock_irq(&lp->lock); - - return res; -} - -/* ................................ MAC ................................ */ - -/* - * Initialize and start the Receiver and Transmit subsystems - */ -static void at91ether_start(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - struct recv_desc_bufs *dlist, *dlist_phys; - int i; - unsigned long ctl; - - dlist = lp->dlist; - dlist_phys = lp->dlist_phys; - - for (i = 0; i < MAX_RX_DESCR; i++) { - dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0]; - dlist->descriptors[i].size = 0; - } - - /* Set the Wrap bit on the last descriptor */ - dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP; - - /* Reset buffer index */ - lp->rxBuffIndex = 0; - - /* Program address of descriptor list in Rx Buffer Queue register */ - at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys); - - /* Enable Receive and Transmit */ - ctl = at91_emac_read(AT91_EMAC_CTL); - at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE); -} - -/* - * Open the ethernet interface - */ -static int at91ether_open(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - unsigned long ctl; - - if (!is_valid_ether_addr(dev->dev_addr)) - return -EADDRNOTAVAIL; - - clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */ - - /* Clear internal statistics */ - ctl = at91_emac_read(AT91_EMAC_CTL); - at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR); - - /* Update the MAC address (incase user has changed it) */ - update_mac_address(dev); - - /* Enable PHY interrupt */ - enable_phyirq(dev); - - /* Enable MAC interrupts */ - at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA - | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM - | AT91_EMAC_ROVR | AT91_EMAC_ABT); - - /* Determine current link speed */ - spin_lock_irq(&lp->lock); - enable_mdi(); - update_linkspeed(dev, 0); - disable_mdi(); - spin_unlock_irq(&lp->lock); - - at91ether_start(dev); - netif_start_queue(dev); - return 0; -} - -/* - * Close the interface - */ -static int at91ether_close(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - unsigned long ctl; - - /* Disable Receiver and Transmitter */ - ctl = at91_emac_read(AT91_EMAC_CTL); - at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE)); - - /* Disable PHY interrupt */ - disable_phyirq(dev); - - /* Disable MAC interrupts */ - at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA - | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM - | AT91_EMAC_ROVR | AT91_EMAC_ABT); - - netif_stop_queue(dev); - - clk_disable(lp->ether_clk); /* Disable Peripheral clock */ - - return 0; -} - -/* - * Transmit packet. - */ -static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - - if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) { - netif_stop_queue(dev); - - /* Store packet information (to free when Tx completed) */ - lp->skb = skb; - lp->skb_length = skb->len; - lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); - dev->stats.tx_bytes += skb->len; - - /* Set address of the data in the Transmit Address register */ - at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr); - /* Set length of the packet in the Transmit Control register */ - at91_emac_write(AT91_EMAC_TCR, skb->len); - - } else { - printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n"); - return NETDEV_TX_BUSY; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) - on this skb, he also reports -ENETDOWN and printk's, so either - we free and return(0) or don't free and return 1 */ - } - - return NETDEV_TX_OK; -} - -/* - * Update the current statistics from the internal statistics registers. - */ -static struct net_device_stats *at91ether_stats(struct net_device *dev) -{ - int ale, lenerr, seqe, lcol, ecol; - - if (netif_running(dev)) { - dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */ - ale = at91_emac_read(AT91_EMAC_ALE); - dev->stats.rx_frame_errors += ale; /* Alignment errors */ - lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF); - dev->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */ - seqe = at91_emac_read(AT91_EMAC_SEQE); - dev->stats.rx_crc_errors += seqe; /* CRC error */ - dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */ - dev->stats.rx_errors += (ale + lenerr + seqe - + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB)); - - dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */ - dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */ - dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */ - dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */ - - lcol = at91_emac_read(AT91_EMAC_LCOL); - ecol = at91_emac_read(AT91_EMAC_ECOL); - dev->stats.tx_window_errors += lcol; /* Late collisions */ - dev->stats.tx_aborted_errors += ecol; /* 16 collisions */ - - dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol); - } - return &dev->stats; -} - -/* - * Extract received frame from buffer descriptors and sent to upper layers. - * (Called from interrupt context) - */ -static void at91ether_rx(struct net_device *dev) -{ - struct at91_private *lp = netdev_priv(dev); - struct recv_desc_bufs *dlist; - unsigned char *p_recv; - struct sk_buff *skb; - unsigned int pktlen; - - dlist = lp->dlist; - while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) { - p_recv = dlist->recv_buf[lp->rxBuffIndex]; - pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff; /* Length of frame including FCS */ - skb = dev_alloc_skb(pktlen + 2); - if (skb != NULL) { - skb_reserve(skb, 2); - memcpy(skb_put(skb, pktlen), p_recv, pktlen); - - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_bytes += pktlen; - netif_rx(skb); - } - else { - dev->stats.rx_dropped += 1; - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - } - - if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST) - dev->stats.multicast++; - - dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE; /* reset ownership bit */ - if (lp->rxBuffIndex == MAX_RX_DESCR-1) /* wrap after last buffer */ - lp->rxBuffIndex = 0; - else - lp->rxBuffIndex++; - } -} - -/* - * MAC interrupt handler - */ -static irqreturn_t at91ether_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct at91_private *lp = netdev_priv(dev); - unsigned long intstatus, ctl; - - /* MAC Interrupt Status register indicates what interrupts are pending. - It is automatically cleared once read. */ - intstatus = at91_emac_read(AT91_EMAC_ISR); - - if (intstatus & AT91_EMAC_RCOM) /* Receive complete */ - at91ether_rx(dev); - - if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */ - /* The TCOM bit is set even if the transmission failed. */ - if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY)) - dev->stats.tx_errors += 1; - - if (lp->skb) { - dev_kfree_skb_irq(lp->skb); - lp->skb = NULL; - dma_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, DMA_TO_DEVICE); - } - netif_wake_queue(dev); - } - - /* Work-around for Errata #11 */ - if (intstatus & AT91_EMAC_RBNA) { - ctl = at91_emac_read(AT91_EMAC_CTL); - at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE); - at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE); - } - - if (intstatus & AT91_EMAC_ROVR) - printk("%s: ROVR error\n", dev->name); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void at91ether_poll_controller(struct net_device *dev) -{ - unsigned long flags; - - local_irq_save(flags); - at91ether_interrupt(dev->irq, dev); - local_irq_restore(flags); -} -#endif - -static const struct net_device_ops at91ether_netdev_ops = { - .ndo_open = at91ether_open, - .ndo_stop = at91ether_close, - .ndo_start_xmit = at91ether_start_xmit, - .ndo_get_stats = at91ether_stats, - .ndo_set_multicast_list = at91ether_set_multicast_list, - .ndo_set_mac_address = set_mac_address, - .ndo_do_ioctl = at91ether_ioctl, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = at91ether_poll_controller, -#endif -}; - -/* - * Initialize the ethernet interface - */ -static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, - struct platform_device *pdev, struct clk *ether_clk) -{ - struct at91_eth_data *board_data = pdev->dev.platform_data; - struct net_device *dev; - struct at91_private *lp; - unsigned int val; - int res; - - dev = alloc_etherdev(sizeof(struct at91_private)); - if (!dev) - return -ENOMEM; - - dev->base_addr = AT91_VA_BASE_EMAC; - dev->irq = AT91RM9200_ID_EMAC; - - /* Install the interrupt handler */ - if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) { - free_netdev(dev); - return -EBUSY; - } - - /* Allocate memory for DMA Receive descriptors */ - lp = netdev_priv(dev); - lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL); - if (lp->dlist == NULL) { - free_irq(dev->irq, dev); - free_netdev(dev); - return -ENOMEM; - } - lp->board_data = *board_data; - lp->ether_clk = ether_clk; - platform_set_drvdata(pdev, dev); - - spin_lock_init(&lp->lock); - - ether_setup(dev); - dev->netdev_ops = &at91ether_netdev_ops; - dev->ethtool_ops = &at91ether_ethtool_ops; - - SET_NETDEV_DEV(dev, &pdev->dev); - - get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */ - update_mac_address(dev); /* Program ethernet address into MAC */ - - at91_emac_write(AT91_EMAC_CTL, 0); - - if (lp->board_data.is_rmii) - at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII); - else - at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG); - - /* Perform PHY-specific initialization */ - spin_lock_irq(&lp->lock); - enable_mdi(); - if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { - read_phy(phy_address, MII_DSCR_REG, &val); - if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */ - lp->phy_media = PORT_FIBRE; - } else if (machine_is_csb337()) { - /* mix link activity status into LED2 link state */ - write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22); - } else if (machine_is_ecbat91()) - write_phy(phy_address, MII_LEDCTRL_REG, 0x156A); - - disable_mdi(); - spin_unlock_irq(&lp->lock); - - lp->mii.dev = dev; /* Support for ethtool */ - lp->mii.mdio_read = mdio_read; - lp->mii.mdio_write = mdio_write; - lp->mii.phy_id = phy_address; - lp->mii.phy_id_mask = 0x1f; - lp->mii.reg_num_mask = 0x1f; - - lp->phy_type = phy_type; /* Type of PHY connected */ - lp->phy_address = phy_address; /* MDI address of PHY */ - - /* Register the network interface */ - res = register_netdev(dev); - if (res) { - free_irq(dev->irq, dev); - free_netdev(dev); - dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); - return res; - } - - /* Determine current link speed */ - spin_lock_irq(&lp->lock); - enable_mdi(); - update_linkspeed(dev, 0); - disable_mdi(); - spin_unlock_irq(&lp->lock); - netif_carrier_off(dev); /* will be enabled in open() */ - - /* If board has no PHY IRQ, use a timer to poll the PHY */ - if (!lp->board_data.phy_irq_pin) { - init_timer(&lp->check_timer); - lp->check_timer.data = (unsigned long)dev; - lp->check_timer.function = at91ether_check_link; - } else if (lp->board_data.phy_irq_pin >= 32) - gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy"); - - /* Display ethernet banner */ - printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n", - dev->name, (uint) dev->base_addr, dev->irq, - at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", - at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", - dev->dev_addr); - if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) - printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); - else if (phy_type == MII_LXT971A_ID) - printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name); - else if (phy_type == MII_RTL8201_ID) - printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name); - else if (phy_type == MII_BCM5221_ID) - printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name); - else if (phy_type == MII_DP83847_ID) - printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name); - else if (phy_type == MII_DP83848_ID) - printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name); - else if (phy_type == MII_AC101L_ID) - printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name); - else if (phy_type == MII_KS8721_ID) - printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name); - else if (phy_type == MII_T78Q21x3_ID) - printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name); - else if (phy_type == MII_LAN83C185_ID) - printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name); - - return 0; -} - -/* - * Detect MAC and PHY and perform initialization - */ -static int __init at91ether_probe(struct platform_device *pdev) -{ - unsigned int phyid1, phyid2; - int detected = -1; - unsigned long phy_id; - unsigned short phy_address = 0; - struct clk *ether_clk; - - ether_clk = clk_get(&pdev->dev, "ether_clk"); - if (IS_ERR(ether_clk)) { - printk(KERN_ERR "at91_ether: no clock defined\n"); - return -ENODEV; - } - clk_enable(ether_clk); /* Enable Peripheral clock */ - - while ((detected != 0) && (phy_address < 32)) { - /* Read the PHY ID registers */ - enable_mdi(); - read_phy(phy_address, MII_PHYSID1, &phyid1); - read_phy(phy_address, MII_PHYSID2, &phyid2); - disable_mdi(); - - phy_id = (phyid1 << 16) | (phyid2 & 0xfff0); - switch (phy_id) { - case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */ - case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */ - case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */ - case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */ - case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */ - case MII_DP83847_ID: /* National Semiconductor DP83847: */ - case MII_DP83848_ID: /* National Semiconductor DP83848: */ - case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ - case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ - case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */ - case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */ - detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk); - break; - } - - phy_address++; - } - - clk_disable(ether_clk); /* Disable Peripheral clock */ - - return detected; -} - -static int __devexit at91ether_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct at91_private *lp = netdev_priv(dev); - - if (lp->board_data.phy_irq_pin >= 32) - gpio_free(lp->board_data.phy_irq_pin); - - unregister_netdev(dev); - free_irq(dev->irq, dev); - dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); - clk_put(lp->ether_clk); - - platform_set_drvdata(pdev, NULL); - free_netdev(dev); - return 0; -} - -#ifdef CONFIG_PM - -static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - struct net_device *net_dev = platform_get_drvdata(pdev); - struct at91_private *lp = netdev_priv(net_dev); - int phy_irq = lp->board_data.phy_irq_pin; - - if (netif_running(net_dev)) { - if (phy_irq) - disable_irq(phy_irq); - - netif_stop_queue(net_dev); - netif_device_detach(net_dev); - - clk_disable(lp->ether_clk); - } - return 0; -} - -static int at91ether_resume(struct platform_device *pdev) -{ - struct net_device *net_dev = platform_get_drvdata(pdev); - struct at91_private *lp = netdev_priv(net_dev); - int phy_irq = lp->board_data.phy_irq_pin; - - if (netif_running(net_dev)) { - clk_enable(lp->ether_clk); - - netif_device_attach(net_dev); - netif_start_queue(net_dev); - - if (phy_irq) - enable_irq(phy_irq); - } - return 0; -} - -#else -#define at91ether_suspend NULL -#define at91ether_resume NULL -#endif - -static struct platform_driver at91ether_driver = { - .remove = __devexit_p(at91ether_remove), - .suspend = at91ether_suspend, - .resume = at91ether_resume, - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init at91ether_init(void) -{ - return platform_driver_probe(&at91ether_driver, at91ether_probe); -} - -static void __exit at91ether_exit(void) -{ - platform_driver_unregister(&at91ether_driver); -} - -module_init(at91ether_init) -module_exit(at91ether_exit) - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver"); -MODULE_AUTHOR("Andrew Victor"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h deleted file mode 100644 index 353f4dab62b..00000000000 --- a/drivers/net/arm/at91_ether.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Ethernet driver for the Atmel AT91RM9200 (Thunder) - * - * Copyright (C) SAN People (Pty) Ltd - * - * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc. - * Initial version by Rick Bronson. - * - * 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. - */ - -#ifndef AT91_ETHERNET -#define AT91_ETHERNET - - -/* Davicom 9161 PHY */ -#define MII_DM9161_ID 0x0181b880 -#define MII_DM9161A_ID 0x0181b8a0 -#define MII_DSCR_REG 16 -#define MII_DSCSR_REG 17 -#define MII_DSINTR_REG 21 - -/* Intel LXT971A PHY */ -#define MII_LXT971A_ID 0x001378E0 -#define MII_ISINTE_REG 18 -#define MII_ISINTS_REG 19 -#define MII_LEDCTRL_REG 20 - -/* Realtek RTL8201 PHY */ -#define MII_RTL8201_ID 0x00008200 - -/* Broadcom BCM5221 PHY */ -#define MII_BCM5221_ID 0x004061e0 -#define MII_BCMINTR_REG 26 - -/* National Semiconductor DP83847 */ -#define MII_DP83847_ID 0x20005c30 - -/* National Semiconductor DP83848 */ -#define MII_DP83848_ID 0x20005c90 -#define MII_DPPHYSTS_REG 16 -#define MII_DPMICR_REG 17 -#define MII_DPMISR_REG 18 - -/* Altima AC101L PHY */ -#define MII_AC101L_ID 0x00225520 - -/* Micrel KS8721 PHY */ -#define MII_KS8721_ID 0x00221610 - -/* Teridian 78Q2123/78Q2133 */ -#define MII_T78Q21x3_ID 0x000e7230 -#define MII_T78Q21INT_REG 17 - -/* SMSC LAN83C185 */ -#define MII_LAN83C185_ID 0x0007C0A0 - -/* ........................................................................ */ - -#define MAX_RBUFF_SZ 0x600 /* 1518 rounded up */ -#define MAX_RX_DESCR 9 /* max number of receive buffers */ - -#define EMAC_DESC_DONE 0x00000001 /* bit for if DMA is done */ -#define EMAC_DESC_WRAP 0x00000002 /* bit for wrap */ - -#define EMAC_BROADCAST 0x80000000 /* broadcast address */ -#define EMAC_MULTICAST 0x40000000 /* multicast address */ -#define EMAC_UNICAST 0x20000000 /* unicast address */ - -struct rbf_t -{ - unsigned int addr; - unsigned long size; -}; - -struct recv_desc_bufs -{ - struct rbf_t descriptors[MAX_RX_DESCR]; /* must be on sizeof (rbf_t) boundary */ - char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ]; /* must be on long boundary */ -}; - -struct at91_private -{ - struct mii_if_info mii; /* ethtool support */ - struct at91_eth_data board_data; /* board-specific configuration */ - struct clk *ether_clk; /* clock */ - - /* PHY */ - unsigned long phy_type; /* type of PHY (PHY_ID) */ - spinlock_t lock; /* lock for MDI interface */ - short phy_media; /* media interface type */ - unsigned short phy_address; /* 5-bit MDI address of PHY (0..31) */ - struct timer_list check_timer; /* Poll link status */ - - /* Transmit */ - struct sk_buff *skb; /* holds skb until xmit interrupt completes */ - dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ - int skb_length; /* saved skb length for pci_unmap_single */ - - /* Receive */ - int rxBuffIndex; /* index into receive descriptor list */ - struct recv_desc_bufs *dlist; /* descriptor list address */ - struct recv_desc_bufs *dlist_phys; /* descriptor list physical address */ -}; - -#endif diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c deleted file mode 100644 index 4317af8d2f0..00000000000 --- a/drivers/net/arm/ep93xx_eth.c +++ /dev/null @@ -1,904 +0,0 @@ -/* - * EP93xx ethernet network device driver - * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> - * Dedicated to Marija Kulikova. - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include <linux/dma-mapping.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/mii.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/moduleparam.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <mach/hardware.h> - -#define DRV_MODULE_NAME "ep93xx-eth" -#define DRV_MODULE_VERSION "0.1" - -#define RX_QUEUE_ENTRIES 64 -#define TX_QUEUE_ENTRIES 8 - -#define MAX_PKT_SIZE 2044 -#define PKT_BUF_SIZE 2048 - -#define REG_RXCTL 0x0000 -#define REG_RXCTL_DEFAULT 0x00073800 -#define REG_TXCTL 0x0004 -#define REG_TXCTL_ENABLE 0x00000001 -#define REG_MIICMD 0x0010 -#define REG_MIICMD_READ 0x00008000 -#define REG_MIICMD_WRITE 0x00004000 -#define REG_MIIDATA 0x0014 -#define REG_MIISTS 0x0018 -#define REG_MIISTS_BUSY 0x00000001 -#define REG_SELFCTL 0x0020 -#define REG_SELFCTL_RESET 0x00000001 -#define REG_INTEN 0x0024 -#define REG_INTEN_TX 0x00000008 -#define REG_INTEN_RX 0x00000007 -#define REG_INTSTSP 0x0028 -#define REG_INTSTS_TX 0x00000008 -#define REG_INTSTS_RX 0x00000004 -#define REG_INTSTSC 0x002c -#define REG_AFP 0x004c -#define REG_INDAD0 0x0050 -#define REG_INDAD1 0x0051 -#define REG_INDAD2 0x0052 -#define REG_INDAD3 0x0053 -#define REG_INDAD4 0x0054 -#define REG_INDAD5 0x0055 -#define REG_GIINTMSK 0x0064 -#define REG_GIINTMSK_ENABLE 0x00008000 -#define REG_BMCTL 0x0080 -#define REG_BMCTL_ENABLE_TX 0x00000100 -#define REG_BMCTL_ENABLE_RX 0x00000001 -#define REG_BMSTS 0x0084 -#define REG_BMSTS_RX_ACTIVE 0x00000008 -#define REG_RXDQBADD 0x0090 -#define REG_RXDQBLEN 0x0094 -#define REG_RXDCURADD 0x0098 -#define REG_RXDENQ 0x009c -#define REG_RXSTSQBADD 0x00a0 -#define REG_RXSTSQBLEN 0x00a4 -#define REG_RXSTSQCURADD 0x00a8 -#define REG_RXSTSENQ 0x00ac -#define REG_TXDQBADD 0x00b0 -#define REG_TXDQBLEN 0x00b4 -#define REG_TXDQCURADD 0x00b8 -#define REG_TXDENQ 0x00bc -#define REG_TXSTSQBADD 0x00c0 -#define REG_TXSTSQBLEN 0x00c4 -#define REG_TXSTSQCURADD 0x00c8 -#define REG_MAXFRMLEN 0x00e8 - -struct ep93xx_rdesc -{ - u32 buf_addr; - u32 rdesc1; -}; - -#define RDESC1_NSOF 0x80000000 -#define RDESC1_BUFFER_INDEX 0x7fff0000 -#define RDESC1_BUFFER_LENGTH 0x0000ffff - -struct ep93xx_rstat -{ - u32 rstat0; - u32 rstat1; -}; - -#define RSTAT0_RFP 0x80000000 -#define RSTAT0_RWE 0x40000000 -#define RSTAT0_EOF 0x20000000 -#define RSTAT0_EOB 0x10000000 -#define RSTAT0_AM 0x00c00000 -#define RSTAT0_RX_ERR 0x00200000 -#define RSTAT0_OE 0x00100000 -#define RSTAT0_FE 0x00080000 -#define RSTAT0_RUNT 0x00040000 -#define RSTAT0_EDATA 0x00020000 -#define RSTAT0_CRCE 0x00010000 -#define RSTAT0_CRCI 0x00008000 -#define RSTAT0_HTI 0x00003f00 -#define RSTAT1_RFP 0x80000000 -#define RSTAT1_BUFFER_INDEX 0x7fff0000 -#define RSTAT1_FRAME_LENGTH 0x0000ffff - -struct ep93xx_tdesc -{ - u32 buf_addr; - u32 tdesc1; -}; - -#define TDESC1_EOF 0x80000000 -#define TDESC1_BUFFER_INDEX 0x7fff0000 -#define TDESC1_BUFFER_ABORT 0x00008000 -#define TDESC1_BUFFER_LENGTH 0x00000fff - -struct ep93xx_tstat -{ - u32 tstat0; -}; - -#define TSTAT0_TXFP 0x80000000 -#define TSTAT0_TXWE 0x40000000 -#define TSTAT0_FA 0x20000000 -#define TSTAT0_LCRS 0x10000000 -#define TSTAT0_OW 0x04000000 -#define TSTAT0_TXU 0x02000000 -#define TSTAT0_ECOLL 0x01000000 -#define TSTAT0_NCOLL 0x001f0000 -#define TSTAT0_BUFFER_INDEX 0x00007fff - -struct ep93xx_descs -{ - struct ep93xx_rdesc rdesc[RX_QUEUE_ENTRIES]; - struct ep93xx_tdesc tdesc[TX_QUEUE_ENTRIES]; - struct ep93xx_rstat rstat[RX_QUEUE_ENTRIES]; - struct ep93xx_tstat tstat[TX_QUEUE_ENTRIES]; -}; - -struct ep93xx_priv -{ - struct resource *res; - void __iomem *base_addr; - int irq; - - struct ep93xx_descs *descs; - dma_addr_t descs_dma_addr; - - void *rx_buf[RX_QUEUE_ENTRIES]; - void *tx_buf[TX_QUEUE_ENTRIES]; - - spinlock_t rx_lock; - unsigned int rx_pointer; - unsigned int tx_clean_pointer; - unsigned int tx_pointer; - spinlock_t tx_pending_lock; - unsigned int tx_pending; - - struct net_device *dev; - struct napi_struct napi; - - struct mii_if_info mii; - u8 mdc_divisor; -}; - -#define rdb(ep, off) __raw_readb((ep)->base_addr + (off)) -#define rdw(ep, off) __raw_readw((ep)->base_addr + (off)) -#define rdl(ep, off) __raw_readl((ep)->base_addr + (off)) -#define wrb(ep, off, val) __raw_writeb((val), (ep)->base_addr + (off)) -#define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off)) -#define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off)) - -static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int data; - int i; - - wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg); - - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) - break; - msleep(1); - } - - if (i == 10) { - pr_info("mdio read timed out\n"); - data = 0xffff; - } else { - data = rdl(ep, REG_MIIDATA); - } - - return data; -} - -static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int i; - - wrl(ep, REG_MIIDATA, data); - wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg); - - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0) - break; - msleep(1); - } - - if (i == 10) - pr_info("mdio write timed out\n"); -} - -static int ep93xx_rx(struct net_device *dev, int processed, int budget) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - - while (processed < budget) { - int entry; - struct ep93xx_rstat *rstat; - u32 rstat0; - u32 rstat1; - int length; - struct sk_buff *skb; - - entry = ep->rx_pointer; - rstat = ep->descs->rstat + entry; - - rstat0 = rstat->rstat0; - rstat1 = rstat->rstat1; - if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) - break; - - rstat->rstat0 = 0; - rstat->rstat1 = 0; - - if (!(rstat0 & RSTAT0_EOF)) - pr_crit("not end-of-frame %.8x %.8x\n", rstat0, rstat1); - if (!(rstat0 & RSTAT0_EOB)) - pr_crit("not end-of-buffer %.8x %.8x\n", rstat0, rstat1); - if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) - pr_crit("entry mismatch %.8x %.8x\n", rstat0, rstat1); - - if (!(rstat0 & RSTAT0_RWE)) { - dev->stats.rx_errors++; - if (rstat0 & RSTAT0_OE) - dev->stats.rx_fifo_errors++; - if (rstat0 & RSTAT0_FE) - dev->stats.rx_frame_errors++; - if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA)) - dev->stats.rx_length_errors++; - if (rstat0 & RSTAT0_CRCE) - dev->stats.rx_crc_errors++; - goto err; - } - - length = rstat1 & RSTAT1_FRAME_LENGTH; - if (length > MAX_PKT_SIZE) { - pr_notice("invalid length %.8x %.8x\n", rstat0, rstat1); - goto err; - } - - /* Strip FCS. */ - if (rstat0 & RSTAT0_CRCI) - length -= 4; - - skb = dev_alloc_skb(length + 2); - if (likely(skb != NULL)) { - struct ep93xx_rdesc *rxd = &ep->descs->rdesc[entry]; - skb_reserve(skb, 2); - dma_sync_single_for_cpu(dev->dev.parent, rxd->buf_addr, - length, DMA_FROM_DEVICE); - skb_copy_to_linear_data(skb, ep->rx_buf[entry], length); - dma_sync_single_for_device(dev->dev.parent, - rxd->buf_addr, length, - DMA_FROM_DEVICE); - skb_put(skb, length); - skb->protocol = eth_type_trans(skb, dev); - - netif_receive_skb(skb); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += length; - } else { - dev->stats.rx_dropped++; - } - -err: - ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1); - processed++; - } - - return processed; -} - -static int ep93xx_have_more_rx(struct ep93xx_priv *ep) -{ - struct ep93xx_rstat *rstat = ep->descs->rstat + ep->rx_pointer; - return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP)); -} - -static int ep93xx_poll(struct napi_struct *napi, int budget) -{ - struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi); - struct net_device *dev = ep->dev; - int rx = 0; - -poll_some_more: - rx = ep93xx_rx(dev, rx, budget); - if (rx < budget) { - int more = 0; - - spin_lock_irq(&ep->rx_lock); - __napi_complete(napi); - wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); - if (ep93xx_have_more_rx(ep)) { - wrl(ep, REG_INTEN, REG_INTEN_TX); - wrl(ep, REG_INTSTSP, REG_INTSTS_RX); - more = 1; - } - spin_unlock_irq(&ep->rx_lock); - - if (more && napi_reschedule(napi)) - goto poll_some_more; - } - - if (rx) { - wrw(ep, REG_RXDENQ, rx); - wrw(ep, REG_RXSTSENQ, rx); - } - - return rx; -} - -static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - struct ep93xx_tdesc *txd; - int entry; - - if (unlikely(skb->len > MAX_PKT_SIZE)) { - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - entry = ep->tx_pointer; - ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1); - - txd = &ep->descs->tdesc[entry]; - - txd->tdesc1 = TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); - dma_sync_single_for_cpu(dev->dev.parent, txd->buf_addr, skb->len, - DMA_TO_DEVICE); - skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); - dma_sync_single_for_device(dev->dev.parent, txd->buf_addr, skb->len, - DMA_TO_DEVICE); - dev_kfree_skb(skb); - - spin_lock_irq(&ep->tx_pending_lock); - ep->tx_pending++; - if (ep->tx_pending == TX_QUEUE_ENTRIES) - netif_stop_queue(dev); - spin_unlock_irq(&ep->tx_pending_lock); - - wrl(ep, REG_TXDENQ, 1); - - return NETDEV_TX_OK; -} - -static void ep93xx_tx_complete(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int wake; - - wake = 0; - - spin_lock(&ep->tx_pending_lock); - while (1) { - int entry; - struct ep93xx_tstat *tstat; - u32 tstat0; - - entry = ep->tx_clean_pointer; - tstat = ep->descs->tstat + entry; - - tstat0 = tstat->tstat0; - if (!(tstat0 & TSTAT0_TXFP)) - break; - - tstat->tstat0 = 0; - - if (tstat0 & TSTAT0_FA) - pr_crit("frame aborted %.8x\n", tstat0); - if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry) - pr_crit("entry mismatch %.8x\n", tstat0); - - if (tstat0 & TSTAT0_TXWE) { - int length = ep->descs->tdesc[entry].tdesc1 & 0xfff; - - dev->stats.tx_packets++; - dev->stats.tx_bytes += length; - } else { - dev->stats.tx_errors++; - } - - if (tstat0 & TSTAT0_OW) - dev->stats.tx_window_errors++; - if (tstat0 & TSTAT0_TXU) - dev->stats.tx_fifo_errors++; - dev->stats.collisions += (tstat0 >> 16) & 0x1f; - - ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1); - if (ep->tx_pending == TX_QUEUE_ENTRIES) - wake = 1; - ep->tx_pending--; - } - spin_unlock(&ep->tx_pending_lock); - - if (wake) - netif_wake_queue(dev); -} - -static irqreturn_t ep93xx_irq(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct ep93xx_priv *ep = netdev_priv(dev); - u32 status; - - status = rdl(ep, REG_INTSTSC); - if (status == 0) - return IRQ_NONE; - - if (status & REG_INTSTS_RX) { - spin_lock(&ep->rx_lock); - if (likely(napi_schedule_prep(&ep->napi))) { - wrl(ep, REG_INTEN, REG_INTEN_TX); - __napi_schedule(&ep->napi); - } - spin_unlock(&ep->rx_lock); - } - - if (status & REG_INTSTS_TX) - ep93xx_tx_complete(dev); - - return IRQ_HANDLED; -} - -static void ep93xx_free_buffers(struct ep93xx_priv *ep) -{ - struct device *dev = ep->dev->dev.parent; - int i; - - for (i = 0; i < RX_QUEUE_ENTRIES; i++) { - dma_addr_t d; - - d = ep->descs->rdesc[i].buf_addr; - if (d) - dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE); - - if (ep->rx_buf[i] != NULL) - kfree(ep->rx_buf[i]); - } - - for (i = 0; i < TX_QUEUE_ENTRIES; i++) { - dma_addr_t d; - - d = ep->descs->tdesc[i].buf_addr; - if (d) - dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE); - - if (ep->tx_buf[i] != NULL) - kfree(ep->tx_buf[i]); - } - - dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs, - ep->descs_dma_addr); -} - -static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) -{ - struct device *dev = ep->dev->dev.parent; - int i; - - ep->descs = dma_alloc_coherent(dev, sizeof(struct ep93xx_descs), - &ep->descs_dma_addr, GFP_KERNEL); - if (ep->descs == NULL) - return 1; - - for (i = 0; i < RX_QUEUE_ENTRIES; i++) { - void *buf; - dma_addr_t d; - - buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL); - if (buf == NULL) - goto err; - - d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, d)) { - kfree(buf); - goto err; - } - - ep->rx_buf[i] = buf; - ep->descs->rdesc[i].buf_addr = d; - ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE; - } - - for (i = 0; i < TX_QUEUE_ENTRIES; i++) { - void *buf; - dma_addr_t d; - - buf = kmalloc(PKT_BUF_SIZE, GFP_KERNEL); - if (buf == NULL) - goto err; - - d = dma_map_single(dev, buf, PKT_BUF_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, d)) { - kfree(buf); - goto err; - } - - ep->tx_buf[i] = buf; - ep->descs->tdesc[i].buf_addr = d; - } - - return 0; - -err: - ep93xx_free_buffers(ep); - return 1; -} - -static int ep93xx_start_hw(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - unsigned long addr; - int i; - - wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) - break; - msleep(1); - } - - if (i == 10) { - pr_crit("hw failed to reset\n"); - return 1; - } - - wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9)); - - /* Does the PHY support preamble suppress? */ - if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0) - wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8)); - - /* Receive descriptor ring. */ - addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc); - wrl(ep, REG_RXDQBADD, addr); - wrl(ep, REG_RXDCURADD, addr); - wrw(ep, REG_RXDQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc)); - - /* Receive status ring. */ - addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat); - wrl(ep, REG_RXSTSQBADD, addr); - wrl(ep, REG_RXSTSQCURADD, addr); - wrw(ep, REG_RXSTSQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat)); - - /* Transmit descriptor ring. */ - addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc); - wrl(ep, REG_TXDQBADD, addr); - wrl(ep, REG_TXDQCURADD, addr); - wrw(ep, REG_TXDQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc)); - - /* Transmit status ring. */ - addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat); - wrl(ep, REG_TXSTSQBADD, addr); - wrl(ep, REG_TXSTSQCURADD, addr); - wrw(ep, REG_TXSTSQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat)); - - wrl(ep, REG_BMCTL, REG_BMCTL_ENABLE_TX | REG_BMCTL_ENABLE_RX); - wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); - wrl(ep, REG_GIINTMSK, 0); - - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_BMSTS) & REG_BMSTS_RX_ACTIVE) != 0) - break; - msleep(1); - } - - if (i == 10) { - pr_crit("hw failed to start\n"); - return 1; - } - - wrl(ep, REG_RXDENQ, RX_QUEUE_ENTRIES); - wrl(ep, REG_RXSTSENQ, RX_QUEUE_ENTRIES); - - wrb(ep, REG_INDAD0, dev->dev_addr[0]); - wrb(ep, REG_INDAD1, dev->dev_addr[1]); - wrb(ep, REG_INDAD2, dev->dev_addr[2]); - wrb(ep, REG_INDAD3, dev->dev_addr[3]); - wrb(ep, REG_INDAD4, dev->dev_addr[4]); - wrb(ep, REG_INDAD5, dev->dev_addr[5]); - wrl(ep, REG_AFP, 0); - - wrl(ep, REG_MAXFRMLEN, (MAX_PKT_SIZE << 16) | MAX_PKT_SIZE); - - wrl(ep, REG_RXCTL, REG_RXCTL_DEFAULT); - wrl(ep, REG_TXCTL, REG_TXCTL_ENABLE); - - return 0; -} - -static void ep93xx_stop_hw(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int i; - - wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET); - for (i = 0; i < 10; i++) { - if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0) - break; - msleep(1); - } - - if (i == 10) - pr_crit("hw failed to reset\n"); -} - -static int ep93xx_open(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - int err; - - if (ep93xx_alloc_buffers(ep)) - return -ENOMEM; - - napi_enable(&ep->napi); - - if (ep93xx_start_hw(dev)) { - napi_disable(&ep->napi); - ep93xx_free_buffers(ep); - return -EIO; - } - - spin_lock_init(&ep->rx_lock); - ep->rx_pointer = 0; - ep->tx_clean_pointer = 0; - ep->tx_pointer = 0; - spin_lock_init(&ep->tx_pending_lock); - ep->tx_pending = 0; - - err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev); - if (err) { - napi_disable(&ep->napi); - ep93xx_stop_hw(dev); - ep93xx_free_buffers(ep); - return err; - } - - wrl(ep, REG_GIINTMSK, REG_GIINTMSK_ENABLE); - - netif_start_queue(dev); - - return 0; -} - -static int ep93xx_close(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - - napi_disable(&ep->napi); - netif_stop_queue(dev); - - wrl(ep, REG_GIINTMSK, 0); - free_irq(ep->irq, dev); - ep93xx_stop_hw(dev); - ep93xx_free_buffers(ep); - - return 0; -} - -static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(ifr); - - return generic_mii_ioctl(&ep->mii, data, cmd, NULL); -} - -static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); -} - -static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_gset(&ep->mii, cmd); -} - -static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_sset(&ep->mii, cmd); -} - -static int ep93xx_nway_reset(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - return mii_nway_restart(&ep->mii); -} - -static u32 ep93xx_get_link(struct net_device *dev) -{ - struct ep93xx_priv *ep = netdev_priv(dev); - return mii_link_ok(&ep->mii); -} - -static const struct ethtool_ops ep93xx_ethtool_ops = { - .get_drvinfo = ep93xx_get_drvinfo, - .get_settings = ep93xx_get_settings, - .set_settings = ep93xx_set_settings, - .nway_reset = ep93xx_nway_reset, - .get_link = ep93xx_get_link, -}; - -static const struct net_device_ops ep93xx_netdev_ops = { - .ndo_open = ep93xx_open, - .ndo_stop = ep93xx_close, - .ndo_start_xmit = ep93xx_xmit, - .ndo_do_ioctl = ep93xx_ioctl, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -}; - -static struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) -{ - struct net_device *dev; - - dev = alloc_etherdev(sizeof(struct ep93xx_priv)); - if (dev == NULL) - return NULL; - - memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN); - - dev->ethtool_ops = &ep93xx_ethtool_ops; - dev->netdev_ops = &ep93xx_netdev_ops; - - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - - return dev; -} - - -static int ep93xx_eth_remove(struct platform_device *pdev) -{ - struct net_device *dev; - struct ep93xx_priv *ep; - - dev = platform_get_drvdata(pdev); - if (dev == NULL) - return 0; - platform_set_drvdata(pdev, NULL); - - ep = netdev_priv(dev); - - /* @@@ Force down. */ - unregister_netdev(dev); - ep93xx_free_buffers(ep); - - if (ep->base_addr != NULL) - iounmap(ep->base_addr); - - if (ep->res != NULL) { - release_resource(ep->res); - kfree(ep->res); - } - - free_netdev(dev); - - return 0; -} - -static int ep93xx_eth_probe(struct platform_device *pdev) -{ - struct ep93xx_eth_data *data; - struct net_device *dev; - struct ep93xx_priv *ep; - struct resource *mem; - int irq; - int err; - - if (pdev == NULL) - return -ENODEV; - data = pdev->dev.platform_data; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!mem || irq < 0) - return -ENXIO; - - dev = ep93xx_dev_alloc(data); - if (dev == NULL) { - err = -ENOMEM; - goto err_out; - } - ep = netdev_priv(dev); - ep->dev = dev; - SET_NETDEV_DEV(dev, &pdev->dev); - netif_napi_add(dev, &ep->napi, ep93xx_poll, 64); - - platform_set_drvdata(pdev, dev); - - ep->res = request_mem_region(mem->start, resource_size(mem), - dev_name(&pdev->dev)); - if (ep->res == NULL) { - dev_err(&pdev->dev, "Could not reserve memory region\n"); - err = -ENOMEM; - goto err_out; - } - - ep->base_addr = ioremap(mem->start, resource_size(mem)); - if (ep->base_addr == NULL) { - dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); - err = -EIO; - goto err_out; - } - ep->irq = irq; - - ep->mii.phy_id = data->phy_id; - ep->mii.phy_id_mask = 0x1f; - ep->mii.reg_num_mask = 0x1f; - ep->mii.dev = dev; - ep->mii.mdio_read = ep93xx_mdio_read; - ep->mii.mdio_write = ep93xx_mdio_write; - ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ - - if (is_zero_ether_addr(dev->dev_addr)) - random_ether_addr(dev->dev_addr); - - err = register_netdev(dev); - if (err) { - dev_err(&pdev->dev, "Failed to register netdev\n"); - goto err_out; - } - - printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, %pM\n", - dev->name, ep->irq, dev->dev_addr); - - return 0; - -err_out: - ep93xx_eth_remove(pdev); - return err; -} - - -static struct platform_driver ep93xx_eth_driver = { - .probe = ep93xx_eth_probe, - .remove = ep93xx_eth_remove, - .driver = { - .name = "ep93xx-eth", - .owner = THIS_MODULE, - }, -}; - -static int __init ep93xx_eth_init_module(void) -{ - printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n"); - return platform_driver_register(&ep93xx_eth_driver); -} - -static void __exit ep93xx_eth_cleanup_module(void) -{ - platform_driver_unregister(&ep93xx_eth_driver); -} - -module_init(ep93xx_eth_init_module); -module_exit(ep93xx_eth_cleanup_module); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ep93xx-eth"); diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c deleted file mode 100644 index b00781c02d5..00000000000 --- a/drivers/net/arm/ether1.c +++ /dev/null @@ -1,1094 +0,0 @@ -/* - * linux/drivers/acorn/net/ether1.c - * - * Copyright (C) 1996-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Acorn ether1 driver (82586 chip) for Acorn machines - * - * We basically keep two queues in the cards memory - one for transmit - * and one for receive. Each has a head and a tail. The head is where - * we/the chip adds packets to be transmitted/received, and the tail - * is where the transmitter has got to/where the receiver will stop. - * Both of these queues are circular, and since the chip is running - * all the time, we have to be careful when we modify the pointers etc - * so that the buffer memory contents is valid all the time. - * - * Change log: - * 1.00 RMK Released - * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now. - * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready - * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt. - * Should prevent lockup. - * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong. - * TDR now only reports failure when chip reports non-zero - * TDR time-distance. - * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1 - * 1.06 RMK 10/02/2000 Updated for 2.3.43 - * 1.07 RMK 13/05/2000 Updated for 2.3.99-pre8 - */ - -#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/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/device.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/bitops.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/ecard.h> - -#define __ETHER1_C -#include "ether1.h" - -static unsigned int net_debug = NET_DEBUG; - -#define BUFFER_SIZE 0x10000 -#define TX_AREA_START 0x00100 -#define TX_AREA_END 0x05000 -#define RX_AREA_START 0x05000 -#define RX_AREA_END 0x0fc00 - -static int ether1_open(struct net_device *dev); -static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t ether1_interrupt(int irq, void *dev_id); -static int ether1_close(struct net_device *dev); -static void ether1_setmulticastlist(struct net_device *dev); -static void ether1_timeout(struct net_device *dev); - -/* ------------------------------------------------------------------------- */ - -static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n"; - -#define BUS_16 16 -#define BUS_8 8 - -/* ------------------------------------------------------------------------- */ - -#define DISABLEIRQS 1 -#define NORMALIRQS 0 - -#define ether1_readw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs) -#define ether1_writew(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs) - -static inline unsigned short -ether1_inw_p (struct net_device *dev, int addr, int svflgs) -{ - unsigned long flags; - unsigned short ret; - - if (svflgs) - local_irq_save (flags); - - writeb(addr >> 12, REG_PAGE); - ret = readw(ETHER1_RAM + ((addr & 4095) << 1)); - if (svflgs) - local_irq_restore (flags); - return ret; -} - -static inline void -ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs) -{ - unsigned long flags; - - if (svflgs) - local_irq_save (flags); - - writeb(addr >> 12, REG_PAGE); - writew(val, ETHER1_RAM + ((addr & 4095) << 1)); - if (svflgs) - local_irq_restore (flags); -} - -/* - * Some inline assembler to allow fast transfers on to/off of the card. - * Since this driver depends on some features presented by the ARM - * specific architecture, and that you can't configure this driver - * without specifiing ARM mode, this is not a problem. - * - * This routine is essentially an optimised memcpy from the card's - * onboard RAM to kernel memory. - */ -static void -ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length) -{ - unsigned int page, thislen, offset; - void __iomem *addr; - - offset = start & 4095; - page = start >> 12; - addr = ETHER1_RAM + (offset << 1); - - if (offset + length > 4096) - thislen = 4096 - offset; - else - thislen = length; - - do { - int used; - - writeb(page, REG_PAGE); - length -= thislen; - - __asm__ __volatile__( - "subs %3, %3, #2\n\ - bmi 2f\n\ -1: ldr %0, [%1], #2\n\ - mov %0, %0, lsl #16\n\ - orr %0, %0, %0, lsr #16\n\ - str %0, [%2], #4\n\ - subs %3, %3, #2\n\ - bmi 2f\n\ - ldr %0, [%1], #2\n\ - mov %0, %0, lsl #16\n\ - orr %0, %0, %0, lsr #16\n\ - str %0, [%2], #4\n\ - subs %3, %3, #2\n\ - bmi 2f\n\ - ldr %0, [%1], #2\n\ - mov %0, %0, lsl #16\n\ - orr %0, %0, %0, lsr #16\n\ - str %0, [%2], #4\n\ - subs %3, %3, #2\n\ - bmi 2f\n\ - ldr %0, [%1], #2\n\ - mov %0, %0, lsl #16\n\ - orr %0, %0, %0, lsr #16\n\ - str %0, [%2], #4\n\ - subs %3, %3, #2\n\ - bpl 1b\n\ -2: adds %3, %3, #1\n\ - ldreqb %0, [%1]\n\ - streqb %0, [%2]" - : "=&r" (used), "=&r" (data) - : "r" (addr), "r" (thislen), "1" (data)); - - addr = ETHER1_RAM; - - thislen = length; - if (thislen > 4096) - thislen = 4096; - page++; - } while (thislen); -} - -static void -ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length) -{ - unsigned int page, thislen, offset; - void __iomem *addr; - - offset = start & 4095; - page = start >> 12; - addr = ETHER1_RAM + (offset << 1); - - if (offset + length > 4096) - thislen = 4096 - offset; - else - thislen = length; - - do { - int used; - - writeb(page, REG_PAGE); - length -= thislen; - - __asm__ __volatile__( - "subs %3, %3, #2\n\ - bmi 2f\n\ -1: ldr %0, [%2], #4\n\ - strb %0, [%1], #1\n\ - mov %0, %0, lsr #8\n\ - strb %0, [%1], #1\n\ - subs %3, %3, #2\n\ - bmi 2f\n\ - ldr %0, [%2], #4\n\ - strb %0, [%1], #1\n\ - mov %0, %0, lsr #8\n\ - strb %0, [%1], #1\n\ - subs %3, %3, #2\n\ - bmi 2f\n\ - ldr %0, [%2], #4\n\ - strb %0, [%1], #1\n\ - mov %0, %0, lsr #8\n\ - strb %0, [%1], #1\n\ - subs %3, %3, #2\n\ - bmi 2f\n\ - ldr %0, [%2], #4\n\ - strb %0, [%1], #1\n\ - mov %0, %0, lsr #8\n\ - strb %0, [%1], #1\n\ - subs %3, %3, #2\n\ - bpl 1b\n\ -2: adds %3, %3, #1\n\ - ldreqb %0, [%2]\n\ - streqb %0, [%1]" - : "=&r" (used), "=&r" (data) - : "r" (addr), "r" (thislen), "1" (data)); - - addr = ETHER1_RAM; - - thislen = length; - if (thislen > 4096) - thislen = 4096; - page++; - } while (thislen); -} - -static int __devinit -ether1_ramtest(struct net_device *dev, unsigned char byte) -{ - unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); - int i, ret = BUFFER_SIZE; - int max_errors = 15; - int bad = -1; - int bad_start = 0; - - if (!buffer) - return 1; - - memset (buffer, byte, BUFFER_SIZE); - ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE); - memset (buffer, byte ^ 0xff, BUFFER_SIZE); - ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE); - - for (i = 0; i < BUFFER_SIZE; i++) { - if (buffer[i] != byte) { - if (max_errors >= 0 && bad != buffer[i]) { - if (bad != -1) - printk ("\n"); - printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X", - dev->name, buffer[i], byte, i); - ret = -ENODEV; - max_errors --; - bad = buffer[i]; - bad_start = i; - } - } else { - if (bad != -1) { - if (bad_start == i - 1) - printk ("\n"); - else - printk (" - 0x%04X\n", i - 1); - bad = -1; - } - } - } - - if (bad != -1) - printk (" - 0x%04X\n", BUFFER_SIZE); - kfree (buffer); - - return ret; -} - -static int -ether1_reset (struct net_device *dev) -{ - writeb(CTRL_RST|CTRL_ACK, REG_CONTROL); - return BUS_16; -} - -static int __devinit -ether1_init_2(struct net_device *dev) -{ - int i; - dev->mem_start = 0; - - i = ether1_ramtest (dev, 0x5a); - - if (i > 0) - i = ether1_ramtest (dev, 0x1e); - - if (i <= 0) - return -ENODEV; - - dev->mem_end = i; - return 0; -} - -/* - * These are the structures that are loaded into the ether RAM card to - * initialise the 82586 - */ - -/* at 0x0100 */ -#define NOP_ADDR (TX_AREA_START) -#define NOP_SIZE (0x06) -static nop_t init_nop = { - 0, - CMD_NOP, - NOP_ADDR -}; - -/* at 0x003a */ -#define TDR_ADDR (0x003a) -#define TDR_SIZE (0x08) -static tdr_t init_tdr = { - 0, - CMD_TDR | CMD_INTR, - NOP_ADDR, - 0 -}; - -/* at 0x002e */ -#define MC_ADDR (0x002e) -#define MC_SIZE (0x0c) -static mc_t init_mc = { - 0, - CMD_SETMULTICAST, - TDR_ADDR, - 0, - { { 0, } } -}; - -/* at 0x0022 */ -#define SA_ADDR (0x0022) -#define SA_SIZE (0x0c) -static sa_t init_sa = { - 0, - CMD_SETADDRESS, - MC_ADDR, - { 0, } -}; - -/* at 0x0010 */ -#define CFG_ADDR (0x0010) -#define CFG_SIZE (0x12) -static cfg_t init_cfg = { - 0, - CMD_CONFIG, - SA_ADDR, - 8, - 8, - CFG8_SRDY, - CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6), - 0, - 0x60, - 0, - CFG13_RETRY(15) | CFG13_SLOTH(2), - 0, -}; - -/* at 0x0000 */ -#define SCB_ADDR (0x0000) -#define SCB_SIZE (0x10) -static scb_t init_scb = { - 0, - SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX, - CFG_ADDR, - RX_AREA_START, - 0, - 0, - 0, - 0 -}; - -/* at 0xffee */ -#define ISCP_ADDR (0xffee) -#define ISCP_SIZE (0x08) -static iscp_t init_iscp = { - 1, - SCB_ADDR, - 0x0000, - 0x0000 -}; - -/* at 0xfff6 */ -#define SCP_ADDR (0xfff6) -#define SCP_SIZE (0x0a) -static scp_t init_scp = { - SCP_SY_16BBUS, - { 0, 0 }, - ISCP_ADDR, - 0 -}; - -#define RFD_SIZE (0x16) -static rfd_t init_rfd = { - 0, - 0, - 0, - 0, - { 0, }, - { 0, }, - 0 -}; - -#define RBD_SIZE (0x0a) -static rbd_t init_rbd = { - 0, - 0, - 0, - 0, - ETH_FRAME_LEN + 8 -}; - -#define TX_SIZE (0x08) -#define TBD_SIZE (0x08) - -static int -ether1_init_for_open (struct net_device *dev) -{ - int i, status, addr, next, next2; - int failures = 0; - unsigned long timeout; - - writeb(CTRL_RST|CTRL_ACK, REG_CONTROL); - - for (i = 0; i < 6; i++) - init_sa.sa_addr[i] = dev->dev_addr[i]; - - /* load data structures into ether1 RAM */ - ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE); - ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE); - ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE); - ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE); - ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE); - ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE); - ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE); - ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE); - - if (ether1_readw(dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) { - printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n", - dev->name); - return 1; - } - - /* - * setup circularly linked list of { rfd, rbd, buffer }, with - * all rfds circularly linked, rbds circularly linked. - * First rfd is linked to scp, first rbd is linked to first - * rfd. Last rbd has a suspend command. - */ - addr = RX_AREA_START; - do { - next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; - next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; - - if (next2 >= RX_AREA_END) { - next = RX_AREA_START; - init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND; - priv(dev)->rx_tail = addr; - } else - init_rfd.rfd_command = 0; - if (addr == RX_AREA_START) - init_rfd.rfd_rbdoffset = addr + RFD_SIZE; - else - init_rfd.rfd_rbdoffset = 0; - init_rfd.rfd_link = next; - init_rbd.rbd_link = next + RFD_SIZE; - init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE; - - ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE); - ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE); - addr = next; - } while (next2 < RX_AREA_END); - - priv(dev)->tx_link = NOP_ADDR; - priv(dev)->tx_head = NOP_ADDR + NOP_SIZE; - priv(dev)->tx_tail = TDR_ADDR; - priv(dev)->rx_head = RX_AREA_START; - - /* release reset & give 586 a prod */ - priv(dev)->resetting = 1; - priv(dev)->initialising = 1; - writeb(CTRL_RST, REG_CONTROL); - writeb(0, REG_CONTROL); - writeb(CTRL_CA, REG_CONTROL); - - /* 586 should now unset iscp.busy */ - timeout = jiffies + HZ/2; - while (ether1_readw(dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) { - if (time_after(jiffies, timeout)) { - printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name); - return 1; - } - } - - /* check status of commands that we issued */ - timeout += HZ/10; - while (((status = ether1_readw(dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) - & STAT_COMPLETE) == 0) { - if (time_after(jiffies, timeout)) - break; - } - - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { - printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status); - printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, - ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); - failures += 1; - } - - timeout += HZ/10; - while (((status = ether1_readw(dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) - & STAT_COMPLETE) == 0) { - if (time_after(jiffies, timeout)) - break; - } - - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { - printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status); - printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, - ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); - failures += 1; - } - - timeout += HZ/10; - while (((status = ether1_readw(dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) - & STAT_COMPLETE) == 0) { - if (time_after(jiffies, timeout)) - break; - } - - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { - printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status); - printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, - ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); - failures += 1; - } - - timeout += HZ; - while (((status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) - & STAT_COMPLETE) == 0) { - if (time_after(jiffies, timeout)) - break; - } - - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { - printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name); - printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, - ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), - ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); - } else { - status = ether1_readw(dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS); - if (status & TDR_XCVRPROB) - printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name); - else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) { -#ifdef FANCY - printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name, - status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10, - (status & TDR_TIME) % 10); -#else - printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name, - status & TDR_SHORT ? "short" : "open", (status & TDR_TIME)); -#endif - } - } - - if (failures) - ether1_reset (dev); - return failures ? 1 : 0; -} - -/* ------------------------------------------------------------------------- */ - -static int -ether1_txalloc (struct net_device *dev, int size) -{ - int start, tail; - - size = (size + 1) & ~1; - tail = priv(dev)->tx_tail; - - if (priv(dev)->tx_head + size > TX_AREA_END) { - if (tail > priv(dev)->tx_head) - return -1; - start = TX_AREA_START; - if (start + size > tail) - return -1; - priv(dev)->tx_head = start + size; - } else { - if (priv(dev)->tx_head < tail && (priv(dev)->tx_head + size) > tail) - return -1; - start = priv(dev)->tx_head; - priv(dev)->tx_head += size; - } - - return start; -} - -static int -ether1_open (struct net_device *dev) -{ - if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_WARNING "%s: invalid ethernet MAC address\n", - dev->name); - return -EINVAL; - } - - if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) - return -EAGAIN; - - if (ether1_init_for_open (dev)) { - free_irq (dev->irq, dev); - return -EAGAIN; - } - - netif_start_queue(dev); - - return 0; -} - -static void -ether1_timeout(struct net_device *dev) -{ - printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n", - dev->name); - printk(KERN_WARNING "%s: resetting device\n", dev->name); - - ether1_reset (dev); - - if (ether1_init_for_open (dev)) - printk (KERN_ERR "%s: unable to restart interface\n", dev->name); - - dev->stats.tx_errors++; - netif_wake_queue(dev); -} - -static int -ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) -{ - int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; - unsigned long flags; - tx_t tx; - tbd_t tbd; - nop_t nop; - - if (priv(dev)->restart) { - printk(KERN_WARNING "%s: resetting device\n", dev->name); - - ether1_reset(dev); - - if (ether1_init_for_open(dev)) - printk(KERN_ERR "%s: unable to restart interface\n", dev->name); - else - priv(dev)->restart = 0; - } - - if (skb->len < ETH_ZLEN) { - if (skb_padto(skb, ETH_ZLEN)) - goto out; - } - - /* - * insert packet followed by a nop - */ - txaddr = ether1_txalloc (dev, TX_SIZE); - tbdaddr = ether1_txalloc (dev, TBD_SIZE); - dataddr = ether1_txalloc (dev, skb->len); - nopaddr = ether1_txalloc (dev, NOP_SIZE); - - tx.tx_status = 0; - tx.tx_command = CMD_TX | CMD_INTR; - tx.tx_link = nopaddr; - tx.tx_tbdoffset = tbdaddr; - tbd.tbd_opts = TBD_EOL | skb->len; - tbd.tbd_link = I82586_NULL; - tbd.tbd_bufl = dataddr; - tbd.tbd_bufh = 0; - nop.nop_status = 0; - nop.nop_command = CMD_NOP; - nop.nop_link = nopaddr; - - local_irq_save(flags); - ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); - ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); - ether1_writebuffer (dev, skb->data, dataddr, skb->len); - ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); - tmp = priv(dev)->tx_link; - priv(dev)->tx_link = nopaddr; - - /* now reset the previous nop pointer */ - ether1_writew(dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); - - local_irq_restore(flags); - - /* handle transmit */ - - /* check to see if we have room for a full sized ether frame */ - tmp = priv(dev)->tx_head; - tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); - priv(dev)->tx_head = tmp; - dev_kfree_skb (skb); - - if (tst == -1) - netif_stop_queue(dev); - - out: - return NETDEV_TX_OK; -} - -static void -ether1_xmit_done (struct net_device *dev) -{ - nop_t nop; - int caddr, tst; - - caddr = priv(dev)->tx_tail; - -again: - ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); - - switch (nop.nop_command & CMD_MASK) { - case CMD_TDR: - /* special case */ - if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) - != (unsigned short)I82586_NULL) { - ether1_writew(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, - scb_command, NORMALIRQS); - writeb(CTRL_CA, REG_CONTROL); - } - priv(dev)->tx_tail = NOP_ADDR; - return; - - case CMD_NOP: - if (nop.nop_link == caddr) { - if (priv(dev)->initialising == 0) - printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name); - else - priv(dev)->initialising = 0; - return; - } - if (caddr == nop.nop_link) - return; - caddr = nop.nop_link; - goto again; - - case CMD_TX: - if (nop.nop_status & STAT_COMPLETE) - break; - printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name); - priv(dev)->restart = 1; - return; - - default: - printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name, - nop.nop_command & CMD_MASK, caddr); - priv(dev)->restart = 1; - return; - } - - while (nop.nop_status & STAT_COMPLETE) { - if (nop.nop_status & STAT_OK) { - dev->stats.tx_packets++; - dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS); - } else { - dev->stats.tx_errors++; - - if (nop.nop_status & STAT_COLLAFTERTX) - dev->stats.collisions++; - if (nop.nop_status & STAT_NOCARRIER) - dev->stats.tx_carrier_errors++; - if (nop.nop_status & STAT_TXLOSTCTS) - printk (KERN_WARNING "%s: cts lost\n", dev->name); - if (nop.nop_status & STAT_TXSLOWDMA) - dev->stats.tx_fifo_errors++; - if (nop.nop_status & STAT_COLLEXCESSIVE) - dev->stats.collisions += 16; - } - - if (nop.nop_link == caddr) { - printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name); - break; - } - - caddr = nop.nop_link; - ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); - if ((nop.nop_command & CMD_MASK) != CMD_NOP) { - printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name); - break; - } - - if (caddr == nop.nop_link) - break; - - caddr = nop.nop_link; - ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); - if ((nop.nop_command & CMD_MASK) != CMD_TX) { - printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name); - break; - } - } - priv(dev)->tx_tail = caddr; - - caddr = priv(dev)->tx_head; - tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); - priv(dev)->tx_head = caddr; - if (tst != -1) - netif_wake_queue(dev); -} - -static void -ether1_recv_done (struct net_device *dev) -{ - int status; - int nexttail, rbdaddr; - rbd_t rbd; - - do { - status = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_status, NORMALIRQS); - if ((status & RFD_COMPLETE) == 0) - break; - - rbdaddr = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS); - ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE); - - if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) { - int length = rbd.rbd_status & RBD_ACNT; - struct sk_buff *skb; - - length = (length + 1) & ~1; - skb = dev_alloc_skb (length + 2); - - if (skb) { - skb_reserve (skb, 2); - - ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length); - - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); - dev->stats.rx_packets++; - } else - dev->stats.rx_dropped++; - } else { - printk(KERN_WARNING "%s: %s\n", dev->name, - (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid"); - dev->stats.rx_dropped++; - } - - nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS); - /* nexttail should be rx_head */ - if (nexttail != priv(dev)->rx_head) - printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n", - dev->name, nexttail, priv(dev)->rx_head); - ether1_writew(dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS); - ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_command, NORMALIRQS); - ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_status, NORMALIRQS); - ether1_writew(dev, 0, priv(dev)->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS); - - priv(dev)->rx_tail = nexttail; - priv(dev)->rx_head = ether1_readw(dev, priv(dev)->rx_head, rfd_t, rfd_link, NORMALIRQS); - } while (1); -} - -static irqreturn_t -ether1_interrupt (int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - int status; - - status = ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); - - if (status) { - ether1_writew(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX), - SCB_ADDR, scb_t, scb_command, NORMALIRQS); - writeb(CTRL_CA | CTRL_ACK, REG_CONTROL); - if (status & SCB_STCX) { - ether1_xmit_done (dev); - } - if (status & SCB_STCNA) { - if (priv(dev)->resetting == 0) - printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name); - else - priv(dev)->resetting += 1; - if (ether1_readw(dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) - != (unsigned short)I82586_NULL) { - ether1_writew(dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS); - writeb(CTRL_CA, REG_CONTROL); - } - if (priv(dev)->resetting == 2) - priv(dev)->resetting = 0; - } - if (status & SCB_STFR) { - ether1_recv_done (dev); - } - if (status & SCB_STRNR) { - if (ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) { - printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name); - ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS); - writeb(CTRL_CA, REG_CONTROL); - dev->stats.rx_dropped++; /* we suspended due to lack of buffer space */ - } else - printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name, - ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS)); - printk (KERN_WARNING "RU ptr = %04X\n", ether1_readw(dev, SCB_ADDR, scb_t, scb_rfa_offset, - NORMALIRQS)); - } - } else - writeb(CTRL_ACK, REG_CONTROL); - - return IRQ_HANDLED; -} - -static int -ether1_close (struct net_device *dev) -{ - ether1_reset (dev); - - free_irq(dev->irq, dev); - - return 0; -} - -/* - * Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets. - * num_addrs == 0 Normal mode, clear multicast list. - * num_addrs > 0 Multicast mode, receive normal and MC packets, and do - * best-effort filtering. - */ -static void -ether1_setmulticastlist (struct net_device *dev) -{ -} - -/* ------------------------------------------------------------------------- */ - -static void __devinit ether1_banner(void) -{ - static unsigned int version_printed = 0; - - if (net_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); -} - -static const struct net_device_ops ether1_netdev_ops = { - .ndo_open = ether1_open, - .ndo_stop = ether1_close, - .ndo_start_xmit = ether1_sendpacket, - .ndo_set_multicast_list = ether1_setmulticastlist, - .ndo_tx_timeout = ether1_timeout, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -}; - -static int __devinit -ether1_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct net_device *dev; - int i, ret = 0; - - ether1_banner(); - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - dev = alloc_etherdev(sizeof(struct ether1_priv)); - if (!dev) { - ret = -ENOMEM; - goto release; - } - - SET_NETDEV_DEV(dev, &ec->dev); - - dev->irq = ec->irq; - priv(dev)->base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); - if (!priv(dev)->base) { - ret = -ENOMEM; - goto free; - } - - if ((priv(dev)->bus_type = ether1_reset(dev)) == 0) { - ret = -ENODEV; - goto free; - } - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2)); - - if (ether1_init_2(dev)) { - ret = -ENODEV; - goto free; - } - - dev->netdev_ops = ðer1_netdev_ops; - dev->watchdog_timeo = 5 * HZ / 100; - - ret = register_netdev(dev); - if (ret) - goto free; - - printk(KERN_INFO "%s: ether1 in slot %d, %pM\n", - dev->name, ec->slot_no, dev->dev_addr); - - ecard_set_drvdata(ec, dev); - return 0; - - free: - free_netdev(dev); - release: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit ether1_remove(struct expansion_card *ec) -{ - struct net_device *dev = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - - unregister_netdev(dev); - free_netdev(dev); - ecard_release_resources(ec); -} - -static const struct ecard_id ether1_ids[] = { - { MANU_ACORN, PROD_ACORN_ETHER1 }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver ether1_driver = { - .probe = ether1_probe, - .remove = __devexit_p(ether1_remove), - .id_table = ether1_ids, - .drv = { - .name = "ether1", - }, -}; - -static int __init ether1_init(void) -{ - return ecard_register_driver(ðer1_driver); -} - -static void __exit ether1_exit(void) -{ - ecard_remove_driver(ðer1_driver); -} - -module_init(ether1_init); -module_exit(ether1_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h deleted file mode 100644 index 3a5830ab3dc..00000000000 --- a/drivers/net/arm/ether1.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * linux/drivers/acorn/net/ether1.h - * - * Copyright (C) 1996 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Network driver for Acorn Ether1 cards. - */ - -#ifndef _LINUX_ether1_H -#define _LINUX_ether1_H - -#ifdef __ETHER1_C -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 0 -#endif - -#define priv(dev) ((struct ether1_priv *)netdev_priv(dev)) - -/* Page register */ -#define REG_PAGE (priv(dev)->base + 0x0000) - -/* Control register */ -#define REG_CONTROL (priv(dev)->base + 0x0004) -#define CTRL_RST 0x01 -#define CTRL_LOOPBACK 0x02 -#define CTRL_CA 0x04 -#define CTRL_ACK 0x08 - -#define ETHER1_RAM (priv(dev)->base + 0x2000) - -/* HW address */ -#define IDPROM_ADDRESS (priv(dev)->base + 0x0024) - -struct ether1_priv { - void __iomem *base; - unsigned int tx_link; - unsigned int tx_head; - volatile unsigned int tx_tail; - volatile unsigned int rx_head; - volatile unsigned int rx_tail; - unsigned char bus_type; - unsigned char resetting; - unsigned char initialising : 1; - unsigned char restart : 1; -}; - -#define I82586_NULL (-1) - -typedef struct { /* tdr */ - unsigned short tdr_status; - unsigned short tdr_command; - unsigned short tdr_link; - unsigned short tdr_result; -#define TDR_TIME (0x7ff) -#define TDR_SHORT (1 << 12) -#define TDR_OPEN (1 << 13) -#define TDR_XCVRPROB (1 << 14) -#define TDR_LNKOK (1 << 15) -} tdr_t; - -typedef struct { /* transmit */ - unsigned short tx_status; - unsigned short tx_command; - unsigned short tx_link; - unsigned short tx_tbdoffset; -} tx_t; - -typedef struct { /* tbd */ - unsigned short tbd_opts; -#define TBD_CNT (0x3fff) -#define TBD_EOL (1 << 15) - unsigned short tbd_link; - unsigned short tbd_bufl; - unsigned short tbd_bufh; -} tbd_t; - -typedef struct { /* rfd */ - unsigned short rfd_status; -#define RFD_NOEOF (1 << 6) -#define RFD_FRAMESHORT (1 << 7) -#define RFD_DMAOVRN (1 << 8) -#define RFD_NORESOURCES (1 << 9) -#define RFD_ALIGNERROR (1 << 10) -#define RFD_CRCERROR (1 << 11) -#define RFD_OK (1 << 13) -#define RFD_FDCONSUMED (1 << 14) -#define RFD_COMPLETE (1 << 15) - unsigned short rfd_command; -#define RFD_CMDSUSPEND (1 << 14) -#define RFD_CMDEL (1 << 15) - unsigned short rfd_link; - unsigned short rfd_rbdoffset; - unsigned char rfd_dest[6]; - unsigned char rfd_src[6]; - unsigned short rfd_len; -} rfd_t; - -typedef struct { /* rbd */ - unsigned short rbd_status; -#define RBD_ACNT (0x3fff) -#define RBD_ACNTVALID (1 << 14) -#define RBD_EOF (1 << 15) - unsigned short rbd_link; - unsigned short rbd_bufl; - unsigned short rbd_bufh; - unsigned short rbd_len; -} rbd_t; - -typedef struct { /* nop */ - unsigned short nop_status; - unsigned short nop_command; - unsigned short nop_link; -} nop_t; - -typedef struct { /* set multicast */ - unsigned short mc_status; - unsigned short mc_command; - unsigned short mc_link; - unsigned short mc_cnt; - unsigned char mc_addrs[1][6]; -} mc_t; - -typedef struct { /* set address */ - unsigned short sa_status; - unsigned short sa_command; - unsigned short sa_link; - unsigned char sa_addr[6]; -} sa_t; - -typedef struct { /* config command */ - unsigned short cfg_status; - unsigned short cfg_command; - unsigned short cfg_link; - unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */ - unsigned char cfg_fifolim; /* FIFO threshold */ - unsigned char cfg_byte8; -#define CFG8_SRDY (1 << 6) -#define CFG8_SAVEBADF (1 << 7) - unsigned char cfg_byte9; -#define CFG9_ADDRLEN(x) (x) -#define CFG9_ADDRLENBUF (1 << 3) -#define CFG9_PREAMB2 (0 << 4) -#define CFG9_PREAMB4 (1 << 4) -#define CFG9_PREAMB8 (2 << 4) -#define CFG9_PREAMB16 (3 << 4) -#define CFG9_ILOOPBACK (1 << 6) -#define CFG9_ELOOPBACK (1 << 7) - unsigned char cfg_byte10; -#define CFG10_LINPRI(x) (x) -#define CFG10_ACR(x) (x << 4) -#define CFG10_BOFMET (1 << 7) - unsigned char cfg_ifs; - unsigned char cfg_slotl; - unsigned char cfg_byte13; -#define CFG13_SLOTH(x) (x) -#define CFG13_RETRY(x) (x << 4) - unsigned char cfg_byte14; -#define CFG14_PROMISC (1 << 0) -#define CFG14_DISBRD (1 << 1) -#define CFG14_MANCH (1 << 2) -#define CFG14_TNCRS (1 << 3) -#define CFG14_NOCRC (1 << 4) -#define CFG14_CRC16 (1 << 5) -#define CFG14_BTSTF (1 << 6) -#define CFG14_FLGPAD (1 << 7) - unsigned char cfg_byte15; -#define CFG15_CSTF(x) (x) -#define CFG15_ICSS (1 << 3) -#define CFG15_CDTF(x) (x << 4) -#define CFG15_ICDS (1 << 7) - unsigned short cfg_minfrmlen; -} cfg_t; - -typedef struct { /* scb */ - unsigned short scb_status; /* status of 82586 */ -#define SCB_STRXMASK (7 << 4) /* Receive unit status */ -#define SCB_STRXIDLE (0 << 4) /* Idle */ -#define SCB_STRXSUSP (1 << 4) /* Suspended */ -#define SCB_STRXNRES (2 << 4) /* No resources */ -#define SCB_STRXRDY (4 << 4) /* Ready */ -#define SCB_STCUMASK (7 << 8) /* Command unit status */ -#define SCB_STCUIDLE (0 << 8) /* Idle */ -#define SCB_STCUSUSP (1 << 8) /* Suspended */ -#define SCB_STCUACTV (2 << 8) /* Active */ -#define SCB_STRNR (1 << 12) /* Receive unit not ready */ -#define SCB_STCNA (1 << 13) /* Command unit not ready */ -#define SCB_STFR (1 << 14) /* Frame received */ -#define SCB_STCX (1 << 15) /* Command completed */ - unsigned short scb_command; /* Next command */ -#define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */ -#define SCB_CMDRXRESUME (2 << 4) /* Resume reception */ -#define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */ -#define SCB_CMDRXABORT (4 << 4) /* Abort reception */ -#define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */ -#define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */ -#define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */ -#define SCB_CMDCUCABORT (4 << 8) /* Abort execution */ -#define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */ -#define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */ -#define SCB_CMDACKFR (1 << 14) /* Ack Frame received */ -#define SCB_CMDACKCX (1 << 15) /* Ack Command complete */ - unsigned short scb_cbl_offset; /* Offset of first command unit */ - unsigned short scb_rfa_offset; /* Offset of first receive frame area */ - unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/ - unsigned short scb_aln_errors; /* Misaligned frames */ - unsigned short scb_rsc_errors; /* Frames lost due to no space */ - unsigned short scb_ovn_errors; /* Frames lost due to slow bus */ -} scb_t; - -typedef struct { /* iscp */ - unsigned short iscp_busy; /* set by CPU before CA */ - unsigned short iscp_offset; /* offset of SCB */ - unsigned short iscp_basel; /* base of SCB */ - unsigned short iscp_baseh; -} iscp_t; - - /* this address must be 0xfff6 */ -typedef struct { /* scp */ - unsigned short scp_sysbus; /* bus size */ -#define SCP_SY_16BBUS 0x00 -#define SCP_SY_8BBUS 0x01 - unsigned short scp_junk[2]; /* junk */ - unsigned short scp_iscpl; /* lower 16 bits of iscp */ - unsigned short scp_iscph; /* upper 16 bits of iscp */ -} scp_t; - -/* commands */ -#define CMD_NOP 0 -#define CMD_SETADDRESS 1 -#define CMD_CONFIG 2 -#define CMD_SETMULTICAST 3 -#define CMD_TX 4 -#define CMD_TDR 5 -#define CMD_DUMP 6 -#define CMD_DIAGNOSE 7 - -#define CMD_MASK 7 - -#define CMD_INTR (1 << 13) -#define CMD_SUSP (1 << 14) -#define CMD_EOL (1 << 15) - -#define STAT_COLLISIONS (15) -#define STAT_COLLEXCESSIVE (1 << 5) -#define STAT_COLLAFTERTX (1 << 6) -#define STAT_TXDEFERRED (1 << 7) -#define STAT_TXSLOWDMA (1 << 8) -#define STAT_TXLOSTCTS (1 << 9) -#define STAT_NOCARRIER (1 << 10) -#define STAT_FAIL (1 << 11) -#define STAT_ABORTED (1 << 12) -#define STAT_OK (1 << 13) -#define STAT_BUSY (1 << 14) -#define STAT_COMPLETE (1 << 15) -#endif -#endif - -/* - * Ether1 card definitions: - * - * FAST accesses: - * +0 Page register - * 16 pages - * +4 Control - * '1' = reset - * '2' = loopback - * '4' = CA - * '8' = int ack - * - * RAM at address + 0x2000 - * Pod. Prod id = 3 - * Words after ID block [base + 8 words] - * +0 pcb issue (0x0c and 0xf3 invalid) - * +1 - +6 eth hw address - */ diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c deleted file mode 100644 index 44a8746f401..00000000000 --- a/drivers/net/arm/ether3.c +++ /dev/null @@ -1,918 +0,0 @@ -/* - * linux/drivers/acorn/net/ether3.c - * - * Copyright (C) 1995-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card - * for Acorn machines - * - * By Russell King, with some suggestions from borris@ant.co.uk - * - * Changelog: - * 1.04 RMK 29/02/1996 Won't pass packets that are from our ethernet - * address up to the higher levels - they're - * silently ignored. I/F can now be put into - * multicast mode. Receiver routine optimised. - * 1.05 RMK 30/02/1996 Now claims interrupt at open when part of - * the kernel rather than when a module. - * 1.06 RMK 02/03/1996 Various code cleanups - * 1.07 RMK 13/10/1996 Optimised interrupt routine and transmit - * routines. - * 1.08 RMK 14/10/1996 Fixed problem with too many packets, - * prevented the kernel message about dropped - * packets appearing too many times a second. - * Now does not disable all IRQs, only the IRQ - * used by this card. - * 1.09 RMK 10/11/1996 Only enables TX irq when buffer space is low, - * but we still service the TX queue if we get a - * RX interrupt. - * 1.10 RMK 15/07/1997 Fixed autoprobing of NQ8004. - * 1.11 RMK 16/11/1997 Fixed autoprobing of NQ8005A. - * 1.12 RMK 31/12/1997 Removed reference to dev_tint for Linux 2.1. - * RMK 27/06/1998 Changed asm/delay.h to linux/delay.h. - * 1.13 RMK 29/06/1998 Fixed problem with transmission of packets. - * Chip seems to have a bug in, whereby if the - * packet starts two bytes from the end of the - * buffer, it corrupts the receiver chain, and - * never updates the transmit status correctly. - * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing. - * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy - * hardware. - * 1.16 RMK 10/02/2000 Updated for 2.3.43 - * 1.17 RMK 13/05/2000 Updated for 2.3.99-pre8 - */ - -#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/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/device.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/bitops.h> - -#include <asm/system.h> -#include <asm/ecard.h> -#include <asm/io.h> - -static char version[] __devinitdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n"; - -#include "ether3.h" - -static unsigned int net_debug = NET_DEBUG; - -static void ether3_setmulticastlist(struct net_device *dev); -static int ether3_rx(struct net_device *dev, unsigned int maxcnt); -static void ether3_tx(struct net_device *dev); -static int ether3_open (struct net_device *dev); -static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); -static irqreturn_t ether3_interrupt (int irq, void *dev_id); -static int ether3_close (struct net_device *dev); -static void ether3_setmulticastlist (struct net_device *dev); -static void ether3_timeout(struct net_device *dev); - -#define BUS_16 2 -#define BUS_8 1 -#define BUS_UNKNOWN 0 - -/* --------------------------------------------------------------------------- */ - -typedef enum { - buffer_write, - buffer_read -} buffer_rw_t; - -/* - * ether3 read/write. Slow things down a bit... - * The SEEQ8005 doesn't like us writing to its registers - * too quickly. - */ -static inline void ether3_outb(int v, const void __iomem *r) -{ - writeb(v, r); - udelay(1); -} - -static inline void ether3_outw(int v, const void __iomem *r) -{ - writew(v, r); - udelay(1); -} -#define ether3_inb(r) ({ unsigned int __v = readb((r)); udelay(1); __v; }) -#define ether3_inw(r) ({ unsigned int __v = readw((r)); udelay(1); __v; }) - -static int -ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start) -{ - int timeout = 1000; - - ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); - ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND); - - while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) { - if (!timeout--) { - printk("%s: setbuffer broken\n", dev->name); - priv(dev)->broken = 1; - return 1; - } - udelay(1); - } - - if (read == buffer_read) { - ether3_outw(start, REG_DMAADDR); - ether3_outw(priv(dev)->regs.command | CMD_FIFOREAD, REG_COMMAND); - } else { - ether3_outw(priv(dev)->regs.command | CMD_FIFOWRITE, REG_COMMAND); - ether3_outw(start, REG_DMAADDR); - } - return 0; -} - -/* - * write data to the buffer memory - */ -#define ether3_writebuffer(dev,data,length) \ - writesw(REG_BUFWIN, (data), (length) >> 1) - -#define ether3_writeword(dev,data) \ - writew((data), REG_BUFWIN) - -#define ether3_writelong(dev,data) { \ - void __iomem *reg_bufwin = REG_BUFWIN; \ - writew((data), reg_bufwin); \ - writew((data) >> 16, reg_bufwin); \ -} - -/* - * read data from the buffer memory - */ -#define ether3_readbuffer(dev,data,length) \ - readsw(REG_BUFWIN, (data), (length) >> 1) - -#define ether3_readword(dev) \ - readw(REG_BUFWIN) - -#define ether3_readlong(dev) \ - readw(REG_BUFWIN) | (readw(REG_BUFWIN) << 16) - -/* - * Switch LED off... - */ -static void ether3_ledoff(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - ether3_outw(priv(dev)->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); -} - -/* - * switch LED on... - */ -static inline void ether3_ledon(struct net_device *dev) -{ - del_timer(&priv(dev)->timer); - priv(dev)->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */ - priv(dev)->timer.data = (unsigned long)dev; - priv(dev)->timer.function = ether3_ledoff; - add_timer(&priv(dev)->timer); - if (priv(dev)->regs.config2 & CFG2_CTRLO) - ether3_outw(priv(dev)->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2); -} - -/* - * Read the ethernet address string from the on board rom. - * This is an ascii string!!! - */ -static int __devinit -ether3_addr(char *addr, struct expansion_card *ec) -{ - struct in_chunk_dir cd; - char *s; - - if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { - int i; - for (i = 0; i<6; i++) { - addr[i] = simple_strtoul(s + 1, &s, 0x10); - if (*s != (i==5?')' : ':' )) - break; - } - if (i == 6) - return 0; - } - /* I wonder if we should even let the user continue in this case - * - no, it would be better to disable the device - */ - printk(KERN_ERR "ether3: Couldn't read a valid MAC address from card.\n"); - return -ENODEV; -} - -/* --------------------------------------------------------------------------- */ - -static int __devinit -ether3_ramtest(struct net_device *dev, unsigned char byte) -{ - unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); - int i,ret = 0; - int max_errors = 4; - int bad = -1; - - if (!buffer) - return 1; - - memset(buffer, byte, RX_END); - ether3_setbuffer(dev, buffer_write, 0); - ether3_writebuffer(dev, buffer, TX_END); - ether3_setbuffer(dev, buffer_write, RX_START); - ether3_writebuffer(dev, buffer + RX_START, RX_LEN); - memset(buffer, byte ^ 0xff, RX_END); - ether3_setbuffer(dev, buffer_read, 0); - ether3_readbuffer(dev, buffer, TX_END); - ether3_setbuffer(dev, buffer_read, RX_START); - ether3_readbuffer(dev, buffer + RX_START, RX_LEN); - - for (i = 0; i < RX_END; i++) { - if (buffer[i] != byte) { - if (max_errors > 0 && bad != buffer[i]) { - printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X", - dev->name, buffer[i], byte, i); - ret = 2; - max_errors--; - bad = i; - } - } else { - if (bad != -1) { - if (bad != i - 1) - printk(" - 0x%04X\n", i - 1); - printk("\n"); - bad = -1; - } - } - } - if (bad != -1) - printk(" - 0xffff\n"); - kfree(buffer); - - return ret; -} - -/* ------------------------------------------------------------------------------- */ - -static int __devinit ether3_init_2(struct net_device *dev) -{ - int i; - - priv(dev)->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8; - priv(dev)->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC; - priv(dev)->regs.command = 0; - - /* - * Set up our hardware address - */ - ether3_outw(priv(dev)->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); - for (i = 0; i < 6; i++) - ether3_outb(dev->dev_addr[i], REG_BUFWIN); - - if (dev->flags & IFF_PROMISC) - priv(dev)->regs.config1 |= CFG1_RECVPROMISC; - else if (dev->flags & IFF_MULTICAST) - priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; - else - priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; - - /* - * There is a problem with the NQ8005 in that it occasionally loses the - * last two bytes. To get round this problem, we receive the CRC as - * well. That way, if we do lose the last two, then it doesn't matter. - */ - ether3_outw(priv(dev)->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); - ether3_outw((TX_END>>8) - 1, REG_BUFWIN); - ether3_outw(priv(dev)->rx_head, REG_RECVPTR); - ether3_outw(0, REG_TRANSMITPTR); - ether3_outw(priv(dev)->rx_head >> 8, REG_RECVEND); - ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); - ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); - ether3_outw(priv(dev)->regs.command, REG_COMMAND); - - i = ether3_ramtest(dev, 0x5A); - if(i) - return i; - i = ether3_ramtest(dev, 0x1E); - if(i) - return i; - - ether3_setbuffer(dev, buffer_write, 0); - ether3_writelong(dev, 0); - return 0; -} - -static void -ether3_init_for_open(struct net_device *dev) -{ - int i; - - /* Reset the chip */ - ether3_outw(CFG2_RESET, REG_CONFIG2); - udelay(4); - - priv(dev)->regs.command = 0; - ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); - while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)) - barrier(); - - ether3_outw(priv(dev)->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); - for (i = 0; i < 6; i++) - ether3_outb(dev->dev_addr[i], REG_BUFWIN); - - priv(dev)->tx_head = 0; - priv(dev)->tx_tail = 0; - priv(dev)->regs.config2 |= CFG2_CTRLO; - priv(dev)->rx_head = RX_START; - - ether3_outw(priv(dev)->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); - ether3_outw((TX_END>>8) - 1, REG_BUFWIN); - ether3_outw(priv(dev)->rx_head, REG_RECVPTR); - ether3_outw(priv(dev)->rx_head >> 8, REG_RECVEND); - ether3_outw(0, REG_TRANSMITPTR); - ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); - ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); - - ether3_setbuffer(dev, buffer_write, 0); - ether3_writelong(dev, 0); - - priv(dev)->regs.command = CMD_ENINTRX | CMD_ENINTTX; - ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND); -} - -static inline int -ether3_probe_bus_8(struct net_device *dev, int val) -{ - int write_low, write_high, read_low, read_high; - - write_low = val & 255; - write_high = val >> 8; - - printk(KERN_DEBUG "ether3_probe: write8 [%02X:%02X]", write_high, write_low); - - ether3_outb(write_low, REG_RECVPTR); - ether3_outb(write_high, REG_RECVPTR + 4); - - read_low = ether3_inb(REG_RECVPTR); - read_high = ether3_inb(REG_RECVPTR + 4); - - printk(", read8 [%02X:%02X]\n", read_high, read_low); - - return read_low == write_low && read_high == write_high; -} - -static inline int -ether3_probe_bus_16(struct net_device *dev, int val) -{ - int read_val; - - ether3_outw(val, REG_RECVPTR); - read_val = ether3_inw(REG_RECVPTR); - - printk(KERN_DEBUG "ether3_probe: write16 [%04X], read16 [%04X]\n", val, read_val); - - return read_val == val; -} - -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -static int -ether3_open(struct net_device *dev) -{ - if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_WARNING "%s: invalid ethernet MAC address\n", - dev->name); - return -EINVAL; - } - - if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) - return -EAGAIN; - - ether3_init_for_open(dev); - - netif_start_queue(dev); - - return 0; -} - -/* - * The inverse routine to ether3_open(). - */ -static int -ether3_close(struct net_device *dev) -{ - netif_stop_queue(dev); - - disable_irq(dev->irq); - - ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); - priv(dev)->regs.command = 0; - while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON)) - barrier(); - ether3_outb(0x80, REG_CONFIG2 + 4); - ether3_outw(0, REG_COMMAND); - - free_irq(dev->irq, dev); - - return 0; -} - -/* - * Set or clear promiscuous/multicast mode filter for this adaptor. - * - * We don't attempt any packet filtering. The card may have a SEEQ 8004 - * in which does not have the other ethernet address registers present... - */ -static void ether3_setmulticastlist(struct net_device *dev) -{ - priv(dev)->regs.config1 &= ~CFG1_RECVPROMISC; - - if (dev->flags & IFF_PROMISC) { - /* promiscuous mode */ - priv(dev)->regs.config1 |= CFG1_RECVPROMISC; - } else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) { - priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI; - } else - priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD; - - ether3_outw(priv(dev)->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); -} - -static void ether3_timeout(struct net_device *dev) -{ - unsigned long flags; - - del_timer(&priv(dev)->timer); - - local_irq_save(flags); - printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); - printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, - ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); - printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, - ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); - printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, - priv(dev)->tx_head, priv(dev)->tx_tail); - ether3_setbuffer(dev, buffer_read, priv(dev)->tx_tail); - printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); - local_irq_restore(flags); - - priv(dev)->regs.config2 |= CFG2_CTRLO; - dev->stats.tx_errors += 1; - ether3_outw(priv(dev)->regs.config2, REG_CONFIG2); - priv(dev)->tx_head = priv(dev)->tx_tail = 0; - - netif_wake_queue(dev); -} - -/* - * Transmit a packet - */ -static int -ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) -{ - unsigned long flags; - unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned int ptr, next_ptr; - - if (priv(dev)->broken) { - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - netif_start_queue(dev); - return NETDEV_TX_OK; - } - - length = (length + 1) & ~1; - if (length != skb->len) { - if (skb_padto(skb, length)) - goto out; - } - - next_ptr = (priv(dev)->tx_head + 1) & 15; - - local_irq_save(flags); - - if (priv(dev)->tx_tail == next_ptr) { - local_irq_restore(flags); - return NETDEV_TX_BUSY; /* unable to queue */ - } - - ptr = 0x600 * priv(dev)->tx_head; - priv(dev)->tx_head = next_ptr; - next_ptr *= 0x600; - -#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) - - ether3_setbuffer(dev, buffer_write, next_ptr); - ether3_writelong(dev, 0); - ether3_setbuffer(dev, buffer_write, ptr); - ether3_writelong(dev, 0); - ether3_writebuffer(dev, skb->data, length); - ether3_writeword(dev, htons(next_ptr)); - ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); - ether3_setbuffer(dev, buffer_write, ptr); - ether3_writeword(dev, htons((ptr + length + 4))); - ether3_writeword(dev, TXHDR_FLAGS >> 16); - ether3_ledon(dev); - - if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { - ether3_outw(ptr, REG_TRANSMITPTR); - ether3_outw(priv(dev)->regs.command | CMD_TXON, REG_COMMAND); - } - - next_ptr = (priv(dev)->tx_head + 1) & 15; - local_irq_restore(flags); - - dev_kfree_skb(skb); - - if (priv(dev)->tx_tail == next_ptr) - netif_stop_queue(dev); - - out: - return NETDEV_TX_OK; -} - -static irqreturn_t -ether3_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned int status, handled = IRQ_NONE; - -#if NET_DEBUG > 1 - if(net_debug & DEBUG_INT) - printk("eth3irq: %d ", irq); -#endif - - status = ether3_inw(REG_STATUS); - - if (status & STAT_INTRX) { - ether3_outw(CMD_ACKINTRX | priv(dev)->regs.command, REG_COMMAND); - ether3_rx(dev, 12); - handled = IRQ_HANDLED; - } - - if (status & STAT_INTTX) { - ether3_outw(CMD_ACKINTTX | priv(dev)->regs.command, REG_COMMAND); - ether3_tx(dev); - handled = IRQ_HANDLED; - } - -#if NET_DEBUG > 1 - if(net_debug & DEBUG_INT) - printk("done\n"); -#endif - return handled; -} - -/* - * If we have a good packet(s), get it/them out of the buffers. - */ -static int ether3_rx(struct net_device *dev, unsigned int maxcnt) -{ - unsigned int next_ptr = priv(dev)->rx_head, received = 0; - - ether3_ledon(dev); - - do { - unsigned int this_ptr, status; - unsigned char addrs[16]; - - /* - * read the first 16 bytes from the buffer. - * This contains the status bytes etc and ethernet addresses, - * and we also check the source ethernet address to see if - * it originated from us. - */ - { - unsigned int temp_ptr; - ether3_setbuffer(dev, buffer_read, next_ptr); - temp_ptr = ether3_readword(dev); - status = ether3_readword(dev); - if ((status & (RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE)) != - (RXSTAT_DONE | RXHDR_CHAINCONTINUE) || !temp_ptr) - break; - - this_ptr = next_ptr + 4; - next_ptr = ntohs(temp_ptr); - } - ether3_setbuffer(dev, buffer_read, this_ptr); - ether3_readbuffer(dev, addrs+2, 12); - -if (next_ptr < RX_START || next_ptr >= RX_END) { - int i; - printk("%s: bad next pointer @%04X: ", dev->name, priv(dev)->rx_head); - printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8); - for (i = 2; i < 14; i++) - printk("%02X ", addrs[i]); - printk("\n"); - next_ptr = priv(dev)->rx_head; - break; -} - /* - * ignore our own packets... - */ - if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) && - !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) { - maxcnt ++; /* compensate for loopedback packet */ - ether3_outw(next_ptr >> 8, REG_RECVEND); - } else - if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) { - unsigned int length = next_ptr - this_ptr; - struct sk_buff *skb; - - if (next_ptr <= this_ptr) - length += RX_END - RX_START; - - skb = dev_alloc_skb(length + 2); - if (skb) { - unsigned char *buf; - - skb_reserve(skb, 2); - buf = skb_put(skb, length); - ether3_readbuffer(dev, buf + 12, length - 12); - ether3_outw(next_ptr >> 8, REG_RECVEND); - *(unsigned short *)(buf + 0) = *(unsigned short *)(addrs + 2); - *(unsigned long *)(buf + 2) = *(unsigned long *)(addrs + 4); - *(unsigned long *)(buf + 6) = *(unsigned long *)(addrs + 8); - *(unsigned short *)(buf + 10) = *(unsigned short *)(addrs + 12); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - received ++; - } else - goto dropping; - } else { - struct net_device_stats *stats = &dev->stats; - ether3_outw(next_ptr >> 8, REG_RECVEND); - if (status & RXSTAT_OVERSIZE) stats->rx_over_errors ++; - if (status & RXSTAT_CRCERROR) stats->rx_crc_errors ++; - if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++; - if (status & RXSTAT_SHORTPACKET) stats->rx_length_errors ++; - stats->rx_errors++; - } - } - while (-- maxcnt); - -done: - dev->stats.rx_packets += received; - priv(dev)->rx_head = next_ptr; - /* - * If rx went off line, then that means that the buffer may be full. We - * have dropped at least one packet. - */ - if (!(ether3_inw(REG_STATUS) & STAT_RXON)) { - dev->stats.rx_dropped++; - ether3_outw(next_ptr, REG_RECVPTR); - ether3_outw(priv(dev)->regs.command | CMD_RXON, REG_COMMAND); - } - - return maxcnt; - -dropping:{ - static unsigned long last_warned; - - ether3_outw(next_ptr >> 8, REG_RECVEND); - /* - * Don't print this message too many times... - */ - if (time_after(jiffies, last_warned + 10 * HZ)) { - last_warned = jiffies; - printk("%s: memory squeeze, dropping packet.\n", dev->name); - } - dev->stats.rx_dropped++; - goto done; - } -} - -/* - * Update stats for the transmitted packet(s) - */ -static void ether3_tx(struct net_device *dev) -{ - unsigned int tx_tail = priv(dev)->tx_tail; - int max_work = 14; - - do { - unsigned long status; - - /* - * Read the packet header - */ - ether3_setbuffer(dev, buffer_read, tx_tail * 0x600); - status = ether3_readlong(dev); - - /* - * Check to see if this packet has been transmitted - */ - if ((status & (TXSTAT_DONE | TXHDR_TRANSMIT)) != - (TXSTAT_DONE | TXHDR_TRANSMIT)) - break; - - /* - * Update errors - */ - if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS))) - dev->stats.tx_packets++; - else { - dev->stats.tx_errors++; - if (status & TXSTAT_16COLLISIONS) - dev->stats.collisions += 16; - if (status & TXSTAT_BABBLED) - dev->stats.tx_fifo_errors++; - } - - tx_tail = (tx_tail + 1) & 15; - } while (--max_work); - - if (priv(dev)->tx_tail != tx_tail) { - priv(dev)->tx_tail = tx_tail; - netif_wake_queue(dev); - } -} - -static void __devinit ether3_banner(void) -{ - static unsigned version_printed = 0; - - if (net_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); -} - -static const struct net_device_ops ether3_netdev_ops = { - .ndo_open = ether3_open, - .ndo_stop = ether3_close, - .ndo_start_xmit = ether3_sendpacket, - .ndo_set_multicast_list = ether3_setmulticastlist, - .ndo_tx_timeout = ether3_timeout, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -}; - -static int __devinit -ether3_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - const struct ether3_data *data = id->data; - struct net_device *dev; - int bus_type, ret; - - ether3_banner(); - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - dev = alloc_etherdev(sizeof(struct dev_priv)); - if (!dev) { - ret = -ENOMEM; - goto release; - } - - SET_NETDEV_DEV(dev, &ec->dev); - - priv(dev)->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); - if (!priv(dev)->base) { - ret = -ENOMEM; - goto free; - } - - ec->irqaddr = priv(dev)->base + data->base_offset; - ec->irqmask = 0xf0; - - priv(dev)->seeq = priv(dev)->base + data->base_offset; - dev->irq = ec->irq; - - ether3_addr(dev->dev_addr, ec); - - init_timer(&priv(dev)->timer); - - /* Reset card... - */ - ether3_outb(0x80, REG_CONFIG2 + 4); - bus_type = BUS_UNKNOWN; - udelay(4); - - /* Test using Receive Pointer (16-bit register) to find out - * how the ether3 is connected to the bus... - */ - if (ether3_probe_bus_8(dev, 0x100) && - ether3_probe_bus_8(dev, 0x201)) - bus_type = BUS_8; - - if (bus_type == BUS_UNKNOWN && - ether3_probe_bus_16(dev, 0x101) && - ether3_probe_bus_16(dev, 0x201)) - bus_type = BUS_16; - - switch (bus_type) { - case BUS_UNKNOWN: - printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); - ret = -ENODEV; - goto free; - - case BUS_8: - printk(KERN_ERR "%s: %s found, but is an unsupported " - "8-bit card\n", dev->name, data->name); - ret = -ENODEV; - goto free; - - default: - break; - } - - if (ether3_init_2(dev)) { - ret = -ENODEV; - goto free; - } - - dev->netdev_ops = ðer3_netdev_ops; - dev->watchdog_timeo = 5 * HZ / 100; - - ret = register_netdev(dev); - if (ret) - goto free; - - printk("%s: %s in slot %d, %pM\n", - dev->name, data->name, ec->slot_no, dev->dev_addr); - - ecard_set_drvdata(ec, dev); - return 0; - - free: - free_netdev(dev); - release: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit ether3_remove(struct expansion_card *ec) -{ - struct net_device *dev = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - - unregister_netdev(dev); - free_netdev(dev); - ecard_release_resources(ec); -} - -static struct ether3_data ether3 = { - .name = "ether3", - .base_offset = 0, -}; - -static struct ether3_data etherb = { - .name = "etherb", - .base_offset = 0x800, -}; - -static const struct ecard_id ether3_ids[] = { - { MANU_ANT2, PROD_ANT_ETHER3, ðer3 }, - { MANU_ANT, PROD_ANT_ETHER3, ðer3 }, - { MANU_ANT, PROD_ANT_ETHERB, ðerb }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver ether3_driver = { - .probe = ether3_probe, - .remove = __devexit_p(ether3_remove), - .id_table = ether3_ids, - .drv = { - .name = "ether3", - }, -}; - -static int __init ether3_init(void) -{ - return ecard_register_driver(ðer3_driver); -} - -static void __exit ether3_exit(void) -{ - ecard_remove_driver(ðer3_driver); -} - -module_init(ether3_init); -module_exit(ether3_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/arm/ether3.h b/drivers/net/arm/ether3.h deleted file mode 100644 index 2db63b08bdf..00000000000 --- a/drivers/net/arm/ether3.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * linux/drivers/acorn/net/ether3.h - * - * Copyright (C) 1995-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * network driver for Acorn/ANT Ether3 cards - */ - -#ifndef _LINUX_ether3_H -#define _LINUX_ether3_H - -/* use 0 for production, 1 for verification, >2 for debug. debug flags: */ -#define DEBUG_TX 2 -#define DEBUG_RX 4 -#define DEBUG_INT 8 -#define DEBUG_IC 16 -#ifndef NET_DEBUG -#define NET_DEBUG 0 -#endif - -#define priv(dev) ((struct dev_priv *)netdev_priv(dev)) - -/* Command register definitions & bits */ -#define REG_COMMAND (priv(dev)->seeq + 0x0000) -#define CMD_ENINTDMA 0x0001 -#define CMD_ENINTRX 0x0002 -#define CMD_ENINTTX 0x0004 -#define CMD_ENINTBUFWIN 0x0008 -#define CMD_ACKINTDMA 0x0010 -#define CMD_ACKINTRX 0x0020 -#define CMD_ACKINTTX 0x0040 -#define CMD_ACKINTBUFWIN 0x0080 -#define CMD_DMAON 0x0100 -#define CMD_RXON 0x0200 -#define CMD_TXON 0x0400 -#define CMD_DMAOFF 0x0800 -#define CMD_RXOFF 0x1000 -#define CMD_TXOFF 0x2000 -#define CMD_FIFOREAD 0x4000 -#define CMD_FIFOWRITE 0x8000 - -/* status register */ -#define REG_STATUS (priv(dev)->seeq + 0x0000) -#define STAT_ENINTSTAT 0x0001 -#define STAT_ENINTRX 0x0002 -#define STAT_ENINTTX 0x0004 -#define STAT_ENINTBUFWIN 0x0008 -#define STAT_INTDMA 0x0010 -#define STAT_INTRX 0x0020 -#define STAT_INTTX 0x0040 -#define STAT_INTBUFWIN 0x0080 -#define STAT_DMAON 0x0100 -#define STAT_RXON 0x0200 -#define STAT_TXON 0x0400 -#define STAT_FIFOFULL 0x2000 -#define STAT_FIFOEMPTY 0x4000 -#define STAT_FIFODIR 0x8000 - -/* configuration register 1 */ -#define REG_CONFIG1 (priv(dev)->seeq + 0x0040) -#define CFG1_BUFSELSTAT0 0x0000 -#define CFG1_BUFSELSTAT1 0x0001 -#define CFG1_BUFSELSTAT2 0x0002 -#define CFG1_BUFSELSTAT3 0x0003 -#define CFG1_BUFSELSTAT4 0x0004 -#define CFG1_BUFSELSTAT5 0x0005 -#define CFG1_ADDRPROM 0x0006 -#define CFG1_TRANSEND 0x0007 -#define CFG1_LOCBUFMEM 0x0008 -#define CFG1_INTVECTOR 0x0009 -#define CFG1_RECVSPECONLY 0x0000 -#define CFG1_RECVSPECBROAD 0x4000 -#define CFG1_RECVSPECBRMULTI 0x8000 -#define CFG1_RECVPROMISC 0xC000 - -/* The following aren't in 8004 */ -#define CFG1_DMABURSTCONT 0x0000 -#define CFG1_DMABURST800NS 0x0010 -#define CFG1_DMABURST1600NS 0x0020 -#define CFG1_DMABURST3200NS 0x0030 -#define CFG1_DMABURST1 0x0000 -#define CFG1_DMABURST4 0x0040 -#define CFG1_DMABURST8 0x0080 -#define CFG1_DMABURST16 0x00C0 -#define CFG1_RECVCOMPSTAT0 0x0100 -#define CFG1_RECVCOMPSTAT1 0x0200 -#define CFG1_RECVCOMPSTAT2 0x0400 -#define CFG1_RECVCOMPSTAT3 0x0800 -#define CFG1_RECVCOMPSTAT4 0x1000 -#define CFG1_RECVCOMPSTAT5 0x2000 - -/* configuration register 2 */ -#define REG_CONFIG2 (priv(dev)->seeq + 0x0080) -#define CFG2_BYTESWAP 0x0001 -#define CFG2_ERRENCRC 0x0008 -#define CFG2_ERRENDRIBBLE 0x0010 -#define CFG2_ERRSHORTFRAME 0x0020 -#define CFG2_SLOTSELECT 0x0040 -#define CFG2_PREAMSELECT 0x0080 -#define CFG2_ADDRLENGTH 0x0100 -#define CFG2_RECVCRC 0x0200 -#define CFG2_XMITNOCRC 0x0400 -#define CFG2_LOOPBACK 0x0800 -#define CFG2_CTRLO 0x1000 -#define CFG2_RESET 0x8000 - -#define REG_RECVEND (priv(dev)->seeq + 0x00c0) - -#define REG_BUFWIN (priv(dev)->seeq + 0x0100) - -#define REG_RECVPTR (priv(dev)->seeq + 0x0140) - -#define REG_TRANSMITPTR (priv(dev)->seeq + 0x0180) - -#define REG_DMAADDR (priv(dev)->seeq + 0x01c0) - -/* - * Cards transmit/receive headers - */ -#define TX_NEXT (0xffff) -#define TXHDR_ENBABBLEINT (1 << 16) -#define TXHDR_ENCOLLISIONINT (1 << 17) -#define TXHDR_EN16COLLISION (1 << 18) -#define TXHDR_ENSUCCESS (1 << 19) -#define TXHDR_DATAFOLLOWS (1 << 21) -#define TXHDR_CHAINCONTINUE (1 << 22) -#define TXHDR_TRANSMIT (1 << 23) -#define TXSTAT_BABBLED (1 << 24) -#define TXSTAT_COLLISION (1 << 25) -#define TXSTAT_16COLLISIONS (1 << 26) -#define TXSTAT_DONE (1 << 31) - -#define RX_NEXT (0xffff) -#define RXHDR_CHAINCONTINUE (1 << 6) -#define RXHDR_RECEIVE (1 << 7) -#define RXSTAT_OVERSIZE (1 << 8) -#define RXSTAT_CRCERROR (1 << 9) -#define RXSTAT_DRIBBLEERROR (1 << 10) -#define RXSTAT_SHORTPACKET (1 << 11) -#define RXSTAT_DONE (1 << 15) - - -#define TX_START 0x0000 -#define TX_END 0x6000 -#define RX_START 0x6000 -#define RX_LEN 0xA000 -#define RX_END 0x10000 -/* must be a power of 2 and greater than MAX_TX_BUFFERED */ -#define MAX_TXED 16 -#define MAX_TX_BUFFERED 10 - -struct dev_priv { - void __iomem *base; - void __iomem *seeq; - struct { - unsigned int command; - unsigned int config1; - unsigned int config2; - } regs; - unsigned char tx_head; /* buffer nr to insert next packet */ - unsigned char tx_tail; /* buffer nr of transmitting packet */ - unsigned int rx_head; /* address to fetch next packet from */ - struct timer_list timer; - int broken; /* 0 = ok, 1 = something went wrong */ -}; - -struct ether3_data { - const char name[8]; - unsigned long base_offset; -}; - -#endif diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c deleted file mode 100644 index 03e217a868d..00000000000 --- a/drivers/net/arm/etherh.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * linux/drivers/acorn/net/etherh.c - * - * Copyright (C) 2000-2002 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * NS8390 I-cubed EtherH and ANT EtherM specific driver - * Thanks to I-Cubed for information on their cards. - * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton - * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan) - * EtherM integration re-engineered by Russell King. - * - * Changelog: - * 08-12-1996 RMK 1.00 Created - * RMK 1.03 Added support for EtherLan500 cards - * 23-11-1997 RMK 1.04 Added media autodetection - * 16-04-1998 RMK 1.05 Improved media autodetection - * 10-02-2000 RMK 1.06 Updated for 2.3.43 - * 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8 - * 12-10-1999 CK/TEW EtherM driver first release - * 21-12-2000 TTC EtherH/EtherM integration - * 25-12-2000 RMK 1.08 Clean integration of EtherM into this driver. - * 03-01-2002 RMK 1.09 Always enable IRQs if we're in the nic slot. - */ - -#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/errno.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <linux/jiffies.h> - -#include <asm/system.h> -#include <asm/ecard.h> -#include <asm/io.h> - -#define EI_SHIFT(x) (ei_local->reg_offset[x]) - -#define ei_inb(_p) readb((void __iomem *)_p) -#define ei_outb(_v,_p) writeb(_v,(void __iomem *)_p) -#define ei_inb_p(_p) readb((void __iomem *)_p) -#define ei_outb_p(_v,_p) writeb(_v,(void __iomem *)_p) - -#define NET_DEBUG 0 -#define DEBUG_INIT 2 - -#define DRV_NAME "etherh" -#define DRV_VERSION "1.11" - -static char version[] __initdata = - "EtherH/EtherM Driver (c) 2002-2004 Russell King " DRV_VERSION "\n"; - -#include "../lib8390.c" - -static unsigned int net_debug = NET_DEBUG; - -struct etherh_priv { - void __iomem *ioc_fast; - void __iomem *memc; - void __iomem *dma_base; - unsigned int id; - void __iomem *ctrl_port; - unsigned char ctrl; - u32 supported; -}; - -struct etherh_data { - unsigned long ns8390_offset; - unsigned long dataport_offset; - unsigned long ctrlport_offset; - int ctrl_ioc; - const char name[16]; - u32 supported; - unsigned char tx_start_page; - unsigned char stop_page; -}; - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("EtherH/EtherM driver"); -MODULE_LICENSE("GPL"); - -#define ETHERH500_DATAPORT 0x800 /* MEMC */ -#define ETHERH500_NS8390 0x000 /* MEMC */ -#define ETHERH500_CTRLPORT 0x800 /* IOC */ - -#define ETHERH600_DATAPORT 0x040 /* MEMC */ -#define ETHERH600_NS8390 0x800 /* MEMC */ -#define ETHERH600_CTRLPORT 0x200 /* MEMC */ - -#define ETHERH_CP_IE 1 -#define ETHERH_CP_IF 2 -#define ETHERH_CP_HEARTBEAT 2 - -#define ETHERH_TX_START_PAGE 1 -#define ETHERH_STOP_PAGE 127 - -/* - * These came from CK/TEW - */ -#define ETHERM_DATAPORT 0x200 /* MEMC */ -#define ETHERM_NS8390 0x800 /* MEMC */ -#define ETHERM_CTRLPORT 0x23c /* MEMC */ - -#define ETHERM_TX_START_PAGE 64 -#define ETHERM_STOP_PAGE 127 - -/* ------------------------------------------------------------------------ */ - -#define etherh_priv(dev) \ - ((struct etherh_priv *)(((char *)netdev_priv(dev)) + sizeof(struct ei_device))) - -static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned char mask) -{ - unsigned char ctrl = eh->ctrl | mask; - eh->ctrl = ctrl; - writeb(ctrl, eh->ctrl_port); -} - -static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned char mask) -{ - unsigned char ctrl = eh->ctrl & ~mask; - eh->ctrl = ctrl; - writeb(ctrl, eh->ctrl_port); -} - -static inline unsigned int etherh_get_stat(struct etherh_priv *eh) -{ - return readb(eh->ctrl_port); -} - - - - -static void etherh_irq_enable(ecard_t *ec, int irqnr) -{ - struct etherh_priv *eh = ec->irq_data; - - etherh_set_ctrl(eh, ETHERH_CP_IE); -} - -static void etherh_irq_disable(ecard_t *ec, int irqnr) -{ - struct etherh_priv *eh = ec->irq_data; - - etherh_clr_ctrl(eh, ETHERH_CP_IE); -} - -static expansioncard_ops_t etherh_ops = { - .irqenable = etherh_irq_enable, - .irqdisable = etherh_irq_disable, -}; - - - - -static void -etherh_setif(struct net_device *dev) -{ - struct ei_device *ei_local = netdev_priv(dev); - unsigned long flags; - void __iomem *addr; - - local_irq_save(flags); - - /* set the interface type */ - switch (etherh_priv(dev)->id) { - case PROD_I3_ETHERLAN600: - case PROD_I3_ETHERLAN600A: - addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; - - switch (dev->if_port) { - case IF_PORT_10BASE2: - writeb((readb(addr) & 0xf8) | 1, addr); - break; - case IF_PORT_10BASET: - writeb((readb(addr) & 0xf8), addr); - break; - } - break; - - case PROD_I3_ETHERLAN500: - switch (dev->if_port) { - case IF_PORT_10BASE2: - etherh_clr_ctrl(etherh_priv(dev), ETHERH_CP_IF); - break; - - case IF_PORT_10BASET: - etherh_set_ctrl(etherh_priv(dev), ETHERH_CP_IF); - break; - } - break; - - default: - break; - } - - local_irq_restore(flags); -} - -static int -etherh_getifstat(struct net_device *dev) -{ - struct ei_device *ei_local = netdev_priv(dev); - void __iomem *addr; - int stat = 0; - - switch (etherh_priv(dev)->id) { - case PROD_I3_ETHERLAN600: - case PROD_I3_ETHERLAN600A: - addr = (void __iomem *)dev->base_addr + EN0_RCNTHI; - switch (dev->if_port) { - case IF_PORT_10BASE2: - stat = 1; - break; - case IF_PORT_10BASET: - stat = readb(addr) & 4; - break; - } - break; - - case PROD_I3_ETHERLAN500: - switch (dev->if_port) { - case IF_PORT_10BASE2: - stat = 1; - break; - case IF_PORT_10BASET: - stat = etherh_get_stat(etherh_priv(dev)) & ETHERH_CP_HEARTBEAT; - break; - } - break; - - default: - stat = 0; - break; - } - - return stat != 0; -} - -/* - * Configure the interface. Note that we ignore the other - * parts of ifmap, since its mostly meaningless for this driver. - */ -static int etherh_set_config(struct net_device *dev, struct ifmap *map) -{ - switch (map->port) { - case IF_PORT_10BASE2: - case IF_PORT_10BASET: - /* - * If the user explicitly sets the interface - * media type, turn off automedia detection. - */ - dev->flags &= ~IFF_AUTOMEDIA; - dev->if_port = map->port; - break; - - default: - return -EINVAL; - } - - etherh_setif(dev); - - return 0; -} - -/* - * Reset the 8390 (hard reset). Note that we can't actually do this. - */ -static void -etherh_reset(struct net_device *dev) -{ - struct ei_device *ei_local = netdev_priv(dev); - void __iomem *addr = (void __iomem *)dev->base_addr; - - writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr); - - /* - * See if we need to change the interface type. - * Note that we use 'interface_num' as a flag - * to indicate that we need to change the media. - */ - if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) { - ei_local->interface_num = 0; - - if (dev->if_port == IF_PORT_10BASET) - dev->if_port = IF_PORT_10BASE2; - else - dev->if_port = IF_PORT_10BASET; - - etherh_setif(dev); - } -} - -/* - * Write a block of data out to the 8390 - */ -static void -etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) -{ - struct ei_device *ei_local = netdev_priv(dev); - unsigned long dma_start; - void __iomem *dma_base, *addr; - - if (ei_local->dmaing) { - printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " - " DMAstat %d irqlock %d\n", dev->name, - ei_local->dmaing, ei_local->irqlock); - return; - } - - /* - * Make sure we have a round number of bytes if we're in word mode. - */ - if (count & 1 && ei_local->word16) - count++; - - ei_local->dmaing = 1; - - addr = (void __iomem *)dev->base_addr; - dma_base = etherh_priv(dev)->dma_base; - - count = (count + 1) & ~1; - writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); - - writeb (0x42, addr + EN0_RCNTLO); - writeb (0x00, addr + EN0_RCNTHI); - writeb (0x42, addr + EN0_RSARLO); - writeb (0x00, addr + EN0_RSARHI); - writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); - - udelay (1); - - writeb (ENISR_RDC, addr + EN0_ISR); - writeb (count, addr + EN0_RCNTLO); - writeb (count >> 8, addr + EN0_RCNTHI); - writeb (0, addr + EN0_RSARLO); - writeb (start_page, addr + EN0_RSARHI); - writeb (E8390_RWRITE | E8390_START, addr + E8390_CMD); - - if (ei_local->word16) - writesw (dma_base, buf, count >> 1); - else - writesb (dma_base, buf, count); - - dma_start = jiffies; - - while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0) - if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ - printk(KERN_ERR "%s: timeout waiting for TX RDC\n", - dev->name); - etherh_reset (dev); - __NS8390_init (dev, 1); - break; - } - - writeb (ENISR_RDC, addr + EN0_ISR); - ei_local->dmaing = 0; -} - -/* - * Read a block of data from the 8390 - */ -static void -etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - struct ei_device *ei_local = netdev_priv(dev); - unsigned char *buf; - void __iomem *dma_base, *addr; - - if (ei_local->dmaing) { - printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: " - " DMAstat %d irqlock %d\n", dev->name, - ei_local->dmaing, ei_local->irqlock); - return; - } - - ei_local->dmaing = 1; - - addr = (void __iomem *)dev->base_addr; - dma_base = etherh_priv(dev)->dma_base; - - buf = skb->data; - writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); - writeb (count, addr + EN0_RCNTLO); - writeb (count >> 8, addr + EN0_RCNTHI); - writeb (ring_offset, addr + EN0_RSARLO); - writeb (ring_offset >> 8, addr + EN0_RSARHI); - writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); - - if (ei_local->word16) { - readsw (dma_base, buf, count >> 1); - if (count & 1) - buf[count - 1] = readb (dma_base); - } else - readsb (dma_base, buf, count); - - writeb (ENISR_RDC, addr + EN0_ISR); - ei_local->dmaing = 0; -} - -/* - * Read a header from the 8390 - */ -static void -etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - struct ei_device *ei_local = netdev_priv(dev); - void __iomem *dma_base, *addr; - - if (ei_local->dmaing) { - printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: " - " DMAstat %d irqlock %d\n", dev->name, - ei_local->dmaing, ei_local->irqlock); - return; - } - - ei_local->dmaing = 1; - - addr = (void __iomem *)dev->base_addr; - dma_base = etherh_priv(dev)->dma_base; - - writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); - writeb (sizeof (*hdr), addr + EN0_RCNTLO); - writeb (0, addr + EN0_RCNTHI); - writeb (0, addr + EN0_RSARLO); - writeb (ring_page, addr + EN0_RSARHI); - writeb (E8390_RREAD | E8390_START, addr + E8390_CMD); - - if (ei_local->word16) - readsw (dma_base, hdr, sizeof (*hdr) >> 1); - else - readsb (dma_base, hdr, sizeof (*hdr)); - - writeb (ENISR_RDC, addr + EN0_ISR); - ei_local->dmaing = 0; -} - -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -static int -etherh_open(struct net_device *dev) -{ - struct ei_device *ei_local = netdev_priv(dev); - - if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_WARNING "%s: invalid ethernet MAC address\n", - dev->name); - return -EINVAL; - } - - if (request_irq(dev->irq, __ei_interrupt, 0, dev->name, dev)) - return -EAGAIN; - - /* - * Make sure that we aren't going to change the - * media type on the next reset - we are about to - * do automedia manually now. - */ - ei_local->interface_num = 0; - - /* - * If we are doing automedia detection, do it now. - * This is more reliable than the 8390's detection. - */ - if (dev->flags & IFF_AUTOMEDIA) { - dev->if_port = IF_PORT_10BASET; - etherh_setif(dev); - mdelay(1); - if (!etherh_getifstat(dev)) { - dev->if_port = IF_PORT_10BASE2; - etherh_setif(dev); - } - } else - etherh_setif(dev); - - etherh_reset(dev); - __ei_open(dev); - - return 0; -} - -/* - * The inverse routine to etherh_open(). - */ -static int -etherh_close(struct net_device *dev) -{ - __ei_close (dev); - free_irq (dev->irq, dev); - return 0; -} - -/* - * Initialisation - */ - -static void __init etherh_banner(void) -{ - static int version_printed; - - if (net_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); -} - -/* - * Read the ethernet address string from the on board rom. - * This is an ascii string... - */ -static int __devinit etherh_addr(char *addr, struct expansion_card *ec) -{ - struct in_chunk_dir cd; - char *s; - - if (!ecard_readchunk(&cd, ec, 0xf5, 0)) { - printk(KERN_ERR "%s: unable to read podule description string\n", - dev_name(&ec->dev)); - goto no_addr; - } - - s = strchr(cd.d.string, '('); - if (s) { - int i; - - for (i = 0; i < 6; i++) { - addr[i] = simple_strtoul(s + 1, &s, 0x10); - if (*s != (i == 5? ')' : ':')) - break; - } - - if (i == 6) - return 0; - } - - printk(KERN_ERR "%s: unable to parse MAC address: %s\n", - dev_name(&ec->dev), cd.d.string); - - no_addr: - return -ENODEV; -} - -/* - * Create an ethernet address from the system serial number. - */ -static int __init etherm_addr(char *addr) -{ - unsigned int serial; - - if (system_serial_low == 0 && system_serial_high == 0) - return -ENODEV; - - serial = system_serial_low | system_serial_high; - - addr[0] = 0; - addr[1] = 0; - addr[2] = 0xa4; - addr[3] = 0x10 + (serial >> 24); - addr[4] = serial >> 16; - addr[5] = serial >> 8; - return 0; -} - -static void etherh_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)); - strlcpy(info->bus_info, dev_name(dev->dev.parent), - sizeof(info->bus_info)); -} - -static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - cmd->supported = etherh_priv(dev)->supported; - ethtool_cmd_speed_set(cmd, SPEED_10); - cmd->duplex = DUPLEX_HALF; - cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; - cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ? - AUTONEG_ENABLE : AUTONEG_DISABLE); - return 0; -} - -static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - switch (cmd->autoneg) { - case AUTONEG_ENABLE: - dev->flags |= IFF_AUTOMEDIA; - break; - - case AUTONEG_DISABLE: - switch (cmd->port) { - case PORT_TP: - dev->if_port = IF_PORT_10BASET; - break; - - case PORT_BNC: - dev->if_port = IF_PORT_10BASE2; - break; - - default: - return -EINVAL; - } - dev->flags &= ~IFF_AUTOMEDIA; - break; - - default: - return -EINVAL; - } - - etherh_setif(dev); - - return 0; -} - -static const struct ethtool_ops etherh_ethtool_ops = { - .get_settings = etherh_get_settings, - .set_settings = etherh_set_settings, - .get_drvinfo = etherh_get_drvinfo, -}; - -static const struct net_device_ops etherh_netdev_ops = { - .ndo_open = etherh_open, - .ndo_stop = etherh_close, - .ndo_set_config = etherh_set_config, - .ndo_start_xmit = __ei_start_xmit, - .ndo_tx_timeout = __ei_tx_timeout, - .ndo_get_stats = __ei_get_stats, - .ndo_set_multicast_list = __ei_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_change_mtu = eth_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = __ei_poll, -#endif -}; - -static u32 etherh_regoffsets[16]; -static u32 etherm_regoffsets[16]; - -static int __devinit -etherh_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - const struct etherh_data *data = id->data; - struct ei_device *ei_local; - struct net_device *dev; - struct etherh_priv *eh; - int ret; - - etherh_banner(); - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - dev = ____alloc_ei_netdev(sizeof(struct etherh_priv)); - if (!dev) { - ret = -ENOMEM; - goto release; - } - - SET_NETDEV_DEV(dev, &ec->dev); - - dev->netdev_ops = ðerh_netdev_ops; - dev->irq = ec->irq; - dev->ethtool_ops = ðerh_ethtool_ops; - - if (data->supported & SUPPORTED_Autoneg) - dev->flags |= IFF_AUTOMEDIA; - if (data->supported & SUPPORTED_TP) { - dev->flags |= IFF_PORTSEL; - dev->if_port = IF_PORT_10BASET; - } else if (data->supported & SUPPORTED_BNC) { - dev->flags |= IFF_PORTSEL; - dev->if_port = IF_PORT_10BASE2; - } else - dev->if_port = IF_PORT_UNKNOWN; - - eh = etherh_priv(dev); - eh->supported = data->supported; - eh->ctrl = 0; - eh->id = ec->cid.product; - eh->memc = ecardm_iomap(ec, ECARD_RES_MEMC, 0, PAGE_SIZE); - if (!eh->memc) { - ret = -ENOMEM; - goto free; - } - - eh->ctrl_port = eh->memc; - if (data->ctrl_ioc) { - eh->ioc_fast = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, PAGE_SIZE); - if (!eh->ioc_fast) { - ret = -ENOMEM; - goto free; - } - eh->ctrl_port = eh->ioc_fast; - } - - dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset; - eh->dma_base = eh->memc + data->dataport_offset; - eh->ctrl_port += data->ctrlport_offset; - - /* - * IRQ and control port handling - only for non-NIC slot cards. - */ - if (ec->slot_no != 8) { - ecard_setirq(ec, ðerh_ops, eh); - } else { - /* - * If we're in the NIC slot, make sure the IRQ is enabled - */ - etherh_set_ctrl(eh, ETHERH_CP_IE); - } - - ei_local = netdev_priv(dev); - spin_lock_init(&ei_local->page_lock); - - if (ec->cid.product == PROD_ANT_ETHERM) { - etherm_addr(dev->dev_addr); - ei_local->reg_offset = etherm_regoffsets; - } else { - etherh_addr(dev->dev_addr, ec); - ei_local->reg_offset = etherh_regoffsets; - } - - ei_local->name = dev->name; - ei_local->word16 = 1; - ei_local->tx_start_page = data->tx_start_page; - ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES; - ei_local->stop_page = data->stop_page; - ei_local->reset_8390 = etherh_reset; - ei_local->block_input = etherh_block_input; - ei_local->block_output = etherh_block_output; - ei_local->get_8390_hdr = etherh_get_header; - ei_local->interface_num = 0; - - etherh_reset(dev); - __NS8390_init(dev, 0); - - ret = register_netdev(dev); - if (ret) - goto free; - - printk(KERN_INFO "%s: %s in slot %d, %pM\n", - dev->name, data->name, ec->slot_no, dev->dev_addr); - - ecard_set_drvdata(ec, dev); - - return 0; - - free: - free_netdev(dev); - release: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit etherh_remove(struct expansion_card *ec) -{ - struct net_device *dev = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - - unregister_netdev(dev); - - free_netdev(dev); - - ecard_release_resources(ec); -} - -static struct etherh_data etherm_data = { - .ns8390_offset = ETHERM_NS8390, - .dataport_offset = ETHERM_NS8390 + ETHERM_DATAPORT, - .ctrlport_offset = ETHERM_NS8390 + ETHERM_CTRLPORT, - .name = "ANT EtherM", - .supported = SUPPORTED_10baseT_Half, - .tx_start_page = ETHERM_TX_START_PAGE, - .stop_page = ETHERM_STOP_PAGE, -}; - -static struct etherh_data etherlan500_data = { - .ns8390_offset = ETHERH500_NS8390, - .dataport_offset = ETHERH500_NS8390 + ETHERH500_DATAPORT, - .ctrlport_offset = ETHERH500_CTRLPORT, - .ctrl_ioc = 1, - .name = "i3 EtherH 500", - .supported = SUPPORTED_10baseT_Half, - .tx_start_page = ETHERH_TX_START_PAGE, - .stop_page = ETHERH_STOP_PAGE, -}; - -static struct etherh_data etherlan600_data = { - .ns8390_offset = ETHERH600_NS8390, - .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, - .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, - .name = "i3 EtherH 600", - .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, - .tx_start_page = ETHERH_TX_START_PAGE, - .stop_page = ETHERH_STOP_PAGE, -}; - -static struct etherh_data etherlan600a_data = { - .ns8390_offset = ETHERH600_NS8390, - .dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT, - .ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT, - .name = "i3 EtherH 600A", - .supported = SUPPORTED_10baseT_Half | SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_Autoneg, - .tx_start_page = ETHERH_TX_START_PAGE, - .stop_page = ETHERH_STOP_PAGE, -}; - -static const struct ecard_id etherh_ids[] = { - { MANU_ANT, PROD_ANT_ETHERM, ðerm_data }, - { MANU_I3, PROD_I3_ETHERLAN500, ðerlan500_data }, - { MANU_I3, PROD_I3_ETHERLAN600, ðerlan600_data }, - { MANU_I3, PROD_I3_ETHERLAN600A, ðerlan600a_data }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver etherh_driver = { - .probe = etherh_probe, - .remove = __devexit_p(etherh_remove), - .id_table = etherh_ids, - .drv = { - .name = DRV_NAME, - }, -}; - -static int __init etherh_init(void) -{ - int i; - - for (i = 0; i < 16; i++) { - etherh_regoffsets[i] = i << 2; - etherm_regoffsets[i] = i << 5; - } - - return ecard_register_driver(ðerh_driver); -} - -static void __exit etherh_exit(void) -{ - ecard_remove_driver(ðerh_driver); -} - -module_init(etherh_init); -module_exit(etherh_exit); diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c deleted file mode 100644 index de51e8453c1..00000000000 --- a/drivers/net/arm/ixp4xx_eth.c +++ /dev/null @@ -1,1489 +0,0 @@ -/* - * Intel IXP4xx Ethernet driver for Linux - * - * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * Ethernet port config (0x00 is not present on IXP42X): - * - * logical port 0x00 0x10 0x20 - * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C) - * physical PortId 2 0 1 - * TX queue 23 24 25 - * RX-free queue 26 27 28 - * TX-done queue is always 31, per-port RX and TX-ready queues are configurable - * - * - * Queue entries: - * bits 0 -> 1 - NPE ID (RX and TX-done) - * bits 0 -> 2 - priority (TX, per 802.1D) - * bits 3 -> 4 - port ID (user-set?) - * bits 5 -> 31 - physical descriptor address - */ - -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/etherdevice.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/net_tstamp.h> -#include <linux/phy.h> -#include <linux/platform_device.h> -#include <linux/ptp_classify.h> -#include <linux/slab.h> -#include <mach/ixp46x_ts.h> -#include <mach/npe.h> -#include <mach/qmgr.h> - -#define DEBUG_DESC 0 -#define DEBUG_RX 0 -#define DEBUG_TX 0 -#define DEBUG_PKT_BYTES 0 -#define DEBUG_MDIO 0 -#define DEBUG_CLOSE 0 - -#define DRV_NAME "ixp4xx_eth" - -#define MAX_NPES 3 - -#define RX_DESCS 64 /* also length of all RX queues */ -#define TX_DESCS 16 /* also length of all TX queues */ -#define TXDONE_QUEUE_LEN 64 /* dwords */ - -#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS)) -#define REGS_SIZE 0x1000 -#define MAX_MRU 1536 /* 0x600 */ -#define RX_BUFF_SIZE ALIGN((NET_IP_ALIGN) + MAX_MRU, 4) - -#define NAPI_WEIGHT 16 -#define MDIO_INTERVAL (3 * HZ) -#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */ -#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */ - -#define NPE_ID(port_id) ((port_id) >> 4) -#define PHYSICAL_ID(port_id) ((NPE_ID(port_id) + 2) % 3) -#define TX_QUEUE(port_id) (NPE_ID(port_id) + 23) -#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26) -#define TXDONE_QUEUE 31 - -#define PTP_SLAVE_MODE 1 -#define PTP_MASTER_MODE 2 -#define PORT2CHANNEL(p) NPE_ID(p->id) - -/* TX Control Registers */ -#define TX_CNTRL0_TX_EN 0x01 -#define TX_CNTRL0_HALFDUPLEX 0x02 -#define TX_CNTRL0_RETRY 0x04 -#define TX_CNTRL0_PAD_EN 0x08 -#define TX_CNTRL0_APPEND_FCS 0x10 -#define TX_CNTRL0_2DEFER 0x20 -#define TX_CNTRL0_RMII 0x40 /* reduced MII */ -#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */ - -/* RX Control Registers */ -#define RX_CNTRL0_RX_EN 0x01 -#define RX_CNTRL0_PADSTRIP_EN 0x02 -#define RX_CNTRL0_SEND_FCS 0x04 -#define RX_CNTRL0_PAUSE_EN 0x08 -#define RX_CNTRL0_LOOP_EN 0x10 -#define RX_CNTRL0_ADDR_FLTR_EN 0x20 -#define RX_CNTRL0_RX_RUNT_EN 0x40 -#define RX_CNTRL0_BCAST_DIS 0x80 -#define RX_CNTRL1_DEFER_EN 0x01 - -/* Core Control Register */ -#define CORE_RESET 0x01 -#define CORE_RX_FIFO_FLUSH 0x02 -#define CORE_TX_FIFO_FLUSH 0x04 -#define CORE_SEND_JAM 0x08 -#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */ - -#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \ - TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \ - TX_CNTRL0_2DEFER) -#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN -#define DEFAULT_CORE_CNTRL CORE_MDC_EN - - -/* NPE message codes */ -#define NPE_GETSTATUS 0x00 -#define NPE_EDB_SETPORTADDRESS 0x01 -#define NPE_EDB_GETMACADDRESSDATABASE 0x02 -#define NPE_EDB_SETMACADDRESSSDATABASE 0x03 -#define NPE_GETSTATS 0x04 -#define NPE_RESETSTATS 0x05 -#define NPE_SETMAXFRAMELENGTHS 0x06 -#define NPE_VLAN_SETRXTAGMODE 0x07 -#define NPE_VLAN_SETDEFAULTRXVID 0x08 -#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09 -#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A -#define NPE_VLAN_SETRXQOSENTRY 0x0B -#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C -#define NPE_STP_SETBLOCKINGSTATE 0x0D -#define NPE_FW_SETFIREWALLMODE 0x0E -#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F -#define NPE_PC_SETAPMACTABLE 0x11 -#define NPE_SETLOOPBACK_MODE 0x12 -#define NPE_PC_SETBSSIDTABLE 0x13 -#define NPE_ADDRESS_FILTER_CONFIG 0x14 -#define NPE_APPENDFCSCONFIG 0x15 -#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16 -#define NPE_MAC_RECOVERY_START 0x17 - - -#ifdef __ARMEB__ -typedef struct sk_buff buffer_t; -#define free_buffer dev_kfree_skb -#define free_buffer_irq dev_kfree_skb_irq -#else -typedef void buffer_t; -#define free_buffer kfree -#define free_buffer_irq kfree -#endif - -struct eth_regs { - u32 tx_control[2], __res1[2]; /* 000 */ - u32 rx_control[2], __res2[2]; /* 010 */ - u32 random_seed, __res3[3]; /* 020 */ - u32 partial_empty_threshold, __res4; /* 030 */ - u32 partial_full_threshold, __res5; /* 038 */ - u32 tx_start_bytes, __res6[3]; /* 040 */ - u32 tx_deferral, rx_deferral, __res7[2];/* 050 */ - u32 tx_2part_deferral[2], __res8[2]; /* 060 */ - u32 slot_time, __res9[3]; /* 070 */ - u32 mdio_command[4]; /* 080 */ - u32 mdio_status[4]; /* 090 */ - u32 mcast_mask[6], __res10[2]; /* 0A0 */ - u32 mcast_addr[6], __res11[2]; /* 0C0 */ - u32 int_clock_threshold, __res12[3]; /* 0E0 */ - u32 hw_addr[6], __res13[61]; /* 0F0 */ - u32 core_control; /* 1FC */ -}; - -struct port { - struct resource *mem_res; - struct eth_regs __iomem *regs; - struct npe *npe; - struct net_device *netdev; - struct napi_struct napi; - struct phy_device *phydev; - struct eth_plat_info *plat; - buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; - struct desc *desc_tab; /* coherent */ - u32 desc_tab_phys; - int id; /* logical port ID */ - int speed, duplex; - u8 firmware[4]; - int hwts_tx_en; - int hwts_rx_en; -}; - -/* NPE message structure */ -struct msg { -#ifdef __ARMEB__ - u8 cmd, eth_id, byte2, byte3; - u8 byte4, byte5, byte6, byte7; -#else - u8 byte3, byte2, eth_id, cmd; - u8 byte7, byte6, byte5, byte4; -#endif -}; - -/* Ethernet packet descriptor */ -struct desc { - u32 next; /* pointer to next buffer, unused */ - -#ifdef __ARMEB__ - u16 buf_len; /* buffer length */ - u16 pkt_len; /* packet length */ - u32 data; /* pointer to data buffer in RAM */ - u8 dest_id; - u8 src_id; - u16 flags; - u8 qos; - u8 padlen; - u16 vlan_tci; -#else - u16 pkt_len; /* packet length */ - u16 buf_len; /* buffer length */ - u32 data; /* pointer to data buffer in RAM */ - u16 flags; - u8 src_id; - u8 dest_id; - u16 vlan_tci; - u8 padlen; - u8 qos; -#endif - -#ifdef __ARMEB__ - u8 dst_mac_0, dst_mac_1, dst_mac_2, dst_mac_3; - u8 dst_mac_4, dst_mac_5, src_mac_0, src_mac_1; - u8 src_mac_2, src_mac_3, src_mac_4, src_mac_5; -#else - u8 dst_mac_3, dst_mac_2, dst_mac_1, dst_mac_0; - u8 src_mac_1, src_mac_0, dst_mac_5, dst_mac_4; - u8 src_mac_5, src_mac_4, src_mac_3, src_mac_2; -#endif -}; - - -#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \ - (n) * sizeof(struct desc)) -#define rx_desc_ptr(port, n) (&(port)->desc_tab[n]) - -#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \ - ((n) + RX_DESCS) * sizeof(struct desc)) -#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS]) - -#ifndef __ARMEB__ -static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) -{ - int i; - for (i = 0; i < cnt; i++) - dest[i] = swab32(src[i]); -} -#endif - -static spinlock_t mdio_lock; -static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */ -static struct mii_bus *mdio_bus; -static int ports_open; -static struct port *npe_port_tab[MAX_NPES]; -static struct dma_pool *dma_pool; - -static struct sock_filter ptp_filter[] = { - PTP_FILTER -}; - -static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid) -{ - u8 *data = skb->data; - unsigned int offset; - u16 *hi, *id; - u32 lo; - - if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4) - return 0; - - offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; - - if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid)) - return 0; - - hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID); - id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); - - memcpy(&lo, &hi[1], sizeof(lo)); - - return (uid_hi == ntohs(*hi) && - uid_lo == ntohl(lo) && - seqid == ntohs(*id)); -} - -static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb) -{ - struct skb_shared_hwtstamps *shhwtstamps; - struct ixp46x_ts_regs *regs; - u64 ns; - u32 ch, hi, lo, val; - u16 uid, seq; - - if (!port->hwts_rx_en) - return; - - ch = PORT2CHANNEL(port); - - regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; - - val = __raw_readl(®s->channel[ch].ch_event); - - if (!(val & RX_SNAPSHOT_LOCKED)) - return; - - lo = __raw_readl(®s->channel[ch].src_uuid_lo); - hi = __raw_readl(®s->channel[ch].src_uuid_hi); - - uid = hi & 0xffff; - seq = (hi >> 16) & 0xffff; - - if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq))) - goto out; - - lo = __raw_readl(®s->channel[ch].rx_snap_lo); - hi = __raw_readl(®s->channel[ch].rx_snap_hi); - ns = ((u64) hi) << 32; - ns |= lo; - ns <<= TICKS_NS_SHIFT; - - shhwtstamps = skb_hwtstamps(skb); - memset(shhwtstamps, 0, sizeof(*shhwtstamps)); - shhwtstamps->hwtstamp = ns_to_ktime(ns); -out: - __raw_writel(RX_SNAPSHOT_LOCKED, ®s->channel[ch].ch_event); -} - -static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb) -{ - struct skb_shared_hwtstamps shhwtstamps; - struct ixp46x_ts_regs *regs; - struct skb_shared_info *shtx; - u64 ns; - u32 ch, cnt, hi, lo, val; - - shtx = skb_shinfo(skb); - if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en)) - shtx->tx_flags |= SKBTX_IN_PROGRESS; - else - return; - - ch = PORT2CHANNEL(port); - - regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; - - /* - * This really stinks, but we have to poll for the Tx time stamp. - * Usually, the time stamp is ready after 4 to 6 microseconds. - */ - for (cnt = 0; cnt < 100; cnt++) { - val = __raw_readl(®s->channel[ch].ch_event); - if (val & TX_SNAPSHOT_LOCKED) - break; - udelay(1); - } - if (!(val & TX_SNAPSHOT_LOCKED)) { - shtx->tx_flags &= ~SKBTX_IN_PROGRESS; - return; - } - - lo = __raw_readl(®s->channel[ch].tx_snap_lo); - hi = __raw_readl(®s->channel[ch].tx_snap_hi); - ns = ((u64) hi) << 32; - ns |= lo; - ns <<= TICKS_NS_SHIFT; - - memset(&shhwtstamps, 0, sizeof(shhwtstamps)); - shhwtstamps.hwtstamp = ns_to_ktime(ns); - skb_tstamp_tx(skb, &shhwtstamps); - - __raw_writel(TX_SNAPSHOT_LOCKED, ®s->channel[ch].ch_event); -} - -static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - struct hwtstamp_config cfg; - struct ixp46x_ts_regs *regs; - struct port *port = netdev_priv(netdev); - int ch; - - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - if (cfg.flags) /* reserved for future extensions */ - return -EINVAL; - - ch = PORT2CHANNEL(port); - regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; - - switch (cfg.tx_type) { - case HWTSTAMP_TX_OFF: - port->hwts_tx_en = 0; - break; - case HWTSTAMP_TX_ON: - port->hwts_tx_en = 1; - break; - default: - return -ERANGE; - } - - switch (cfg.rx_filter) { - case HWTSTAMP_FILTER_NONE: - port->hwts_rx_en = 0; - break; - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - port->hwts_rx_en = PTP_SLAVE_MODE; - __raw_writel(0, ®s->channel[ch].ch_control); - break; - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - port->hwts_rx_en = PTP_MASTER_MODE; - __raw_writel(MASTER_MODE, ®s->channel[ch].ch_control); - break; - default: - return -ERANGE; - } - - /* Clear out any old time stamps. */ - __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED, - ®s->channel[ch].ch_event); - - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; -} - -static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, - int write, u16 cmd) -{ - int cycles = 0; - - if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) { - printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name); - return -1; - } - - if (write) { - __raw_writel(cmd & 0xFF, &mdio_regs->mdio_command[0]); - __raw_writel(cmd >> 8, &mdio_regs->mdio_command[1]); - } - __raw_writel(((phy_id << 5) | location) & 0xFF, - &mdio_regs->mdio_command[2]); - __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */, - &mdio_regs->mdio_command[3]); - - while ((cycles < MAX_MDIO_RETRIES) && - (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) { - udelay(1); - cycles++; - } - - if (cycles == MAX_MDIO_RETRIES) { - printk(KERN_ERR "%s #%i: MII write failed\n", bus->name, - phy_id); - return -1; - } - -#if DEBUG_MDIO - printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name, - phy_id, write ? "write" : "read", cycles); -#endif - - if (write) - return 0; - - if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) { -#if DEBUG_MDIO - printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name, - phy_id); -#endif - return 0xFFFF; /* don't return error */ - } - - return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) | - ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8); -} - -static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&mdio_lock, flags); - ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0); - spin_unlock_irqrestore(&mdio_lock, flags); -#if DEBUG_MDIO - printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name, - phy_id, location, ret); -#endif - return ret; -} - -static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location, - u16 val) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&mdio_lock, flags); - ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val); - spin_unlock_irqrestore(&mdio_lock, flags); -#if DEBUG_MDIO - printk(KERN_DEBUG "%s #%i: MII write [%i] <- 0x%X, err = %i\n", - bus->name, phy_id, location, val, ret); -#endif - return ret; -} - -static int ixp4xx_mdio_register(void) -{ - int err; - - if (!(mdio_bus = mdiobus_alloc())) - return -ENOMEM; - - if (cpu_is_ixp43x()) { - /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */ - if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH)) - return -ENODEV; - mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT; - } else { - /* All MII PHY accesses use NPE-B Ethernet registers */ - if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0)) - return -ENODEV; - mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; - } - - __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); - spin_lock_init(&mdio_lock); - mdio_bus->name = "IXP4xx MII Bus"; - mdio_bus->read = &ixp4xx_mdio_read; - mdio_bus->write = &ixp4xx_mdio_write; - strcpy(mdio_bus->id, "0"); - - if ((err = mdiobus_register(mdio_bus))) - mdiobus_free(mdio_bus); - return err; -} - -static void ixp4xx_mdio_remove(void) -{ - mdiobus_unregister(mdio_bus); - mdiobus_free(mdio_bus); -} - - -static void ixp4xx_adjust_link(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - struct phy_device *phydev = port->phydev; - - if (!phydev->link) { - if (port->speed) { - port->speed = 0; - printk(KERN_INFO "%s: link down\n", dev->name); - } - return; - } - - if (port->speed == phydev->speed && port->duplex == phydev->duplex) - return; - - port->speed = phydev->speed; - port->duplex = phydev->duplex; - - if (port->duplex) - __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX, - &port->regs->tx_control[0]); - else - __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX, - &port->regs->tx_control[0]); - - printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n", - dev->name, port->speed, port->duplex ? "full" : "half"); -} - - -static inline void debug_pkt(struct net_device *dev, const char *func, - u8 *data, int len) -{ -#if DEBUG_PKT_BYTES - int i; - - printk(KERN_DEBUG "%s: %s(%i) ", dev->name, func, len); - for (i = 0; i < len; i++) { - if (i >= DEBUG_PKT_BYTES) - break; - printk("%s%02X", - ((i == 6) || (i == 12) || (i >= 14)) ? " " : "", - data[i]); - } - printk("\n"); -#endif -} - - -static inline void debug_desc(u32 phys, struct desc *desc) -{ -#if DEBUG_DESC - printk(KERN_DEBUG "%X: %X %3X %3X %08X %2X < %2X %4X %X" - " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n", - phys, desc->next, desc->buf_len, desc->pkt_len, - desc->data, desc->dest_id, desc->src_id, desc->flags, - desc->qos, desc->padlen, desc->vlan_tci, - desc->dst_mac_0, desc->dst_mac_1, desc->dst_mac_2, - desc->dst_mac_3, desc->dst_mac_4, desc->dst_mac_5, - desc->src_mac_0, desc->src_mac_1, desc->src_mac_2, - desc->src_mac_3, desc->src_mac_4, desc->src_mac_5); -#endif -} - -static inline int queue_get_desc(unsigned int queue, struct port *port, - int is_tx) -{ - u32 phys, tab_phys, n_desc; - struct desc *tab; - - if (!(phys = qmgr_get_entry(queue))) - return -1; - - phys &= ~0x1F; /* mask out non-address bits */ - tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0); - tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0); - n_desc = (phys - tab_phys) / sizeof(struct desc); - BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS)); - debug_desc(phys, &tab[n_desc]); - BUG_ON(tab[n_desc].next); - return n_desc; -} - -static inline void queue_put_desc(unsigned int queue, u32 phys, - struct desc *desc) -{ - debug_desc(phys, desc); - BUG_ON(phys & 0x1F); - qmgr_put_entry(queue, phys); - /* Don't check for queue overflow here, we've allocated sufficient - length and queues >= 32 don't support this check anyway. */ -} - - -static inline void dma_unmap_tx(struct port *port, struct desc *desc) -{ -#ifdef __ARMEB__ - dma_unmap_single(&port->netdev->dev, desc->data, - desc->buf_len, DMA_TO_DEVICE); -#else - dma_unmap_single(&port->netdev->dev, desc->data & ~3, - ALIGN((desc->data & 3) + desc->buf_len, 4), - DMA_TO_DEVICE); -#endif -} - - -static void eth_rx_irq(void *pdev) -{ - struct net_device *dev = pdev; - struct port *port = netdev_priv(dev); - -#if DEBUG_RX - printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name); -#endif - qmgr_disable_irq(port->plat->rxq); - napi_schedule(&port->napi); -} - -static int eth_poll(struct napi_struct *napi, int budget) -{ - struct port *port = container_of(napi, struct port, napi); - struct net_device *dev = port->netdev; - unsigned int rxq = port->plat->rxq, rxfreeq = RXFREE_QUEUE(port->id); - int received = 0; - -#if DEBUG_RX - printk(KERN_DEBUG "%s: eth_poll\n", dev->name); -#endif - - while (received < budget) { - struct sk_buff *skb; - struct desc *desc; - int n; -#ifdef __ARMEB__ - struct sk_buff *temp; - u32 phys; -#endif - - if ((n = queue_get_desc(rxq, port, 0)) < 0) { -#if DEBUG_RX - printk(KERN_DEBUG "%s: eth_poll napi_complete\n", - dev->name); -#endif - napi_complete(napi); - qmgr_enable_irq(rxq); - if (!qmgr_stat_below_low_watermark(rxq) && - napi_reschedule(napi)) { /* not empty again */ -#if DEBUG_RX - printk(KERN_DEBUG "%s: eth_poll" - " napi_reschedule successed\n", - dev->name); -#endif - qmgr_disable_irq(rxq); - continue; - } -#if DEBUG_RX - printk(KERN_DEBUG "%s: eth_poll all done\n", - dev->name); -#endif - return received; /* all work done */ - } - - desc = rx_desc_ptr(port, n); - -#ifdef __ARMEB__ - if ((skb = netdev_alloc_skb(dev, RX_BUFF_SIZE))) { - phys = dma_map_single(&dev->dev, skb->data, - RX_BUFF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(&dev->dev, phys)) { - dev_kfree_skb(skb); - skb = NULL; - } - } -#else - skb = netdev_alloc_skb(dev, - ALIGN(NET_IP_ALIGN + desc->pkt_len, 4)); -#endif - - if (!skb) { - dev->stats.rx_dropped++; - /* put the desc back on RX-ready queue */ - desc->buf_len = MAX_MRU; - desc->pkt_len = 0; - queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc); - continue; - } - - /* process received frame */ -#ifdef __ARMEB__ - temp = skb; - skb = port->rx_buff_tab[n]; - dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN, - RX_BUFF_SIZE, DMA_FROM_DEVICE); -#else - dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN, - RX_BUFF_SIZE, DMA_FROM_DEVICE); - memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], - ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4); -#endif - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, desc->pkt_len); - - debug_pkt(dev, "eth_poll", skb->data, skb->len); - - ixp_rx_timestamp(port, skb); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_receive_skb(skb); - - /* put the new buffer on RX-free queue */ -#ifdef __ARMEB__ - port->rx_buff_tab[n] = temp; - desc->data = phys + NET_IP_ALIGN; -#endif - desc->buf_len = MAX_MRU; - desc->pkt_len = 0; - queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc); - received++; - } - -#if DEBUG_RX - printk(KERN_DEBUG "eth_poll(): end, not all work done\n"); -#endif - return received; /* not all work done */ -} - - -static void eth_txdone_irq(void *unused) -{ - u32 phys; - -#if DEBUG_TX - printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n"); -#endif - while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) { - u32 npe_id, n_desc; - struct port *port; - struct desc *desc; - int start; - - npe_id = phys & 3; - BUG_ON(npe_id >= MAX_NPES); - port = npe_port_tab[npe_id]; - BUG_ON(!port); - phys &= ~0x1F; /* mask out non-address bits */ - n_desc = (phys - tx_desc_phys(port, 0)) / sizeof(struct desc); - BUG_ON(n_desc >= TX_DESCS); - desc = tx_desc_ptr(port, n_desc); - debug_desc(phys, desc); - - if (port->tx_buff_tab[n_desc]) { /* not the draining packet */ - port->netdev->stats.tx_packets++; - port->netdev->stats.tx_bytes += desc->pkt_len; - - dma_unmap_tx(port, desc); -#if DEBUG_TX - printk(KERN_DEBUG "%s: eth_txdone_irq free %p\n", - port->netdev->name, port->tx_buff_tab[n_desc]); -#endif - free_buffer_irq(port->tx_buff_tab[n_desc]); - port->tx_buff_tab[n_desc] = NULL; - } - - start = qmgr_stat_below_low_watermark(port->plat->txreadyq); - queue_put_desc(port->plat->txreadyq, phys, desc); - if (start) { /* TX-ready queue was empty */ -#if DEBUG_TX - printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n", - port->netdev->name); -#endif - netif_wake_queue(port->netdev); - } - } -} - -static int eth_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - unsigned int txreadyq = port->plat->txreadyq; - int len, offset, bytes, n; - void *mem; - u32 phys; - struct desc *desc; - -#if DEBUG_TX - printk(KERN_DEBUG "%s: eth_xmit\n", dev->name); -#endif - - if (unlikely(skb->len > MAX_MRU)) { - dev_kfree_skb(skb); - dev->stats.tx_errors++; - return NETDEV_TX_OK; - } - - debug_pkt(dev, "eth_xmit", skb->data, skb->len); - - len = skb->len; -#ifdef __ARMEB__ - offset = 0; /* no need to keep alignment */ - bytes = len; - mem = skb->data; -#else - offset = (int)skb->data & 3; /* keep 32-bit alignment */ - bytes = ALIGN(offset + len, 4); - if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); -#endif - - phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE); - if (dma_mapping_error(&dev->dev, phys)) { - dev_kfree_skb(skb); -#ifndef __ARMEB__ - kfree(mem); -#endif - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - n = queue_get_desc(txreadyq, port, 1); - BUG_ON(n < 0); - desc = tx_desc_ptr(port, n); - -#ifdef __ARMEB__ - port->tx_buff_tab[n] = skb; -#else - port->tx_buff_tab[n] = mem; -#endif - desc->data = phys + offset; - desc->buf_len = desc->pkt_len = len; - - /* NPE firmware pads short frames with zeros internally */ - wmb(); - queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc); - - if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */ -#if DEBUG_TX - printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name); -#endif - netif_stop_queue(dev); - /* we could miss TX ready interrupt */ - /* really empty in fact */ - if (!qmgr_stat_below_low_watermark(txreadyq)) { -#if DEBUG_TX - printk(KERN_DEBUG "%s: eth_xmit ready again\n", - dev->name); -#endif - netif_wake_queue(dev); - } - } - -#if DEBUG_TX - printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name); -#endif - - ixp_tx_timestamp(port, skb); - skb_tx_timestamp(skb); - -#ifndef __ARMEB__ - dev_kfree_skb(skb); -#endif - return NETDEV_TX_OK; -} - - -static void eth_set_mcast_list(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - struct netdev_hw_addr *ha; - u8 diffs[ETH_ALEN], *addr; - int i; - static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - if (dev->flags & IFF_ALLMULTI) { - for (i = 0; i < ETH_ALEN; i++) { - __raw_writel(allmulti[i], &port->regs->mcast_addr[i]); - __raw_writel(allmulti[i], &port->regs->mcast_mask[i]); - } - __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN, - &port->regs->rx_control[0]); - return; - } - - if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) { - __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN, - &port->regs->rx_control[0]); - return; - } - - memset(diffs, 0, ETH_ALEN); - - addr = NULL; - netdev_for_each_mc_addr(ha, dev) { - if (!addr) - addr = ha->addr; /* first MAC address */ - for (i = 0; i < ETH_ALEN; i++) - diffs[i] |= addr[i] ^ ha->addr[i]; - } - - for (i = 0; i < ETH_ALEN; i++) { - __raw_writel(addr[i], &port->regs->mcast_addr[i]); - __raw_writel(~diffs[i], &port->regs->mcast_mask[i]); - } - - __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN, - &port->regs->rx_control[0]); -} - - -static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - struct port *port = netdev_priv(dev); - - if (!netif_running(dev)) - return -EINVAL; - - if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP) - return hwtstamp_ioctl(dev, req, cmd); - - return phy_mii_ioctl(port->phydev, req, cmd); -} - -/* ethtool support */ - -static void ixp4xx_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct port *port = netdev_priv(dev); - strcpy(info->driver, DRV_NAME); - snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u", - port->firmware[0], port->firmware[1], - port->firmware[2], port->firmware[3]); - strcpy(info->bus_info, "internal"); -} - -static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct port *port = netdev_priv(dev); - return phy_ethtool_gset(port->phydev, cmd); -} - -static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct port *port = netdev_priv(dev); - return phy_ethtool_sset(port->phydev, cmd); -} - -static int ixp4xx_nway_reset(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - return phy_start_aneg(port->phydev); -} - -static const struct ethtool_ops ixp4xx_ethtool_ops = { - .get_drvinfo = ixp4xx_get_drvinfo, - .get_settings = ixp4xx_get_settings, - .set_settings = ixp4xx_set_settings, - .nway_reset = ixp4xx_nway_reset, - .get_link = ethtool_op_get_link, -}; - - -static int request_queues(struct port *port) -{ - int err; - - err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0, - "%s:RX-free", port->netdev->name); - if (err) - return err; - - err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0, - "%s:RX", port->netdev->name); - if (err) - goto rel_rxfree; - - err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0, - "%s:TX", port->netdev->name); - if (err) - goto rel_rx; - - err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, - "%s:TX-ready", port->netdev->name); - if (err) - goto rel_tx; - - /* TX-done queue handles skbs sent out by the NPEs */ - if (!ports_open) { - err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0, - "%s:TX-done", DRV_NAME); - if (err) - goto rel_txready; - } - return 0; - -rel_txready: - qmgr_release_queue(port->plat->txreadyq); -rel_tx: - qmgr_release_queue(TX_QUEUE(port->id)); -rel_rx: - qmgr_release_queue(port->plat->rxq); -rel_rxfree: - qmgr_release_queue(RXFREE_QUEUE(port->id)); - printk(KERN_DEBUG "%s: unable to request hardware queues\n", - port->netdev->name); - return err; -} - -static void release_queues(struct port *port) -{ - qmgr_release_queue(RXFREE_QUEUE(port->id)); - qmgr_release_queue(port->plat->rxq); - qmgr_release_queue(TX_QUEUE(port->id)); - qmgr_release_queue(port->plat->txreadyq); - - if (!ports_open) - qmgr_release_queue(TXDONE_QUEUE); -} - -static int init_queues(struct port *port) -{ - int i; - - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) - return -ENOMEM; - - if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, - &port->desc_tab_phys))) - return -ENOMEM; - memset(port->desc_tab, 0, POOL_ALLOC_SIZE); - memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */ - memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab)); - - /* Setup RX buffers */ - for (i = 0; i < RX_DESCS; i++) { - struct desc *desc = rx_desc_ptr(port, i); - buffer_t *buff; /* skb or kmalloc()ated memory */ - void *data; -#ifdef __ARMEB__ - if (!(buff = netdev_alloc_skb(port->netdev, RX_BUFF_SIZE))) - return -ENOMEM; - data = buff->data; -#else - if (!(buff = kmalloc(RX_BUFF_SIZE, GFP_KERNEL))) - return -ENOMEM; - data = buff; -#endif - desc->buf_len = MAX_MRU; - desc->data = dma_map_single(&port->netdev->dev, data, - RX_BUFF_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(&port->netdev->dev, desc->data)) { - free_buffer(buff); - return -EIO; - } - desc->data += NET_IP_ALIGN; - port->rx_buff_tab[i] = buff; - } - - return 0; -} - -static void destroy_queues(struct port *port) -{ - int i; - - if (port->desc_tab) { - for (i = 0; i < RX_DESCS; i++) { - struct desc *desc = rx_desc_ptr(port, i); - buffer_t *buff = port->rx_buff_tab[i]; - if (buff) { - dma_unmap_single(&port->netdev->dev, - desc->data - NET_IP_ALIGN, - RX_BUFF_SIZE, DMA_FROM_DEVICE); - free_buffer(buff); - } - } - for (i = 0; i < TX_DESCS; i++) { - struct desc *desc = tx_desc_ptr(port, i); - buffer_t *buff = port->tx_buff_tab[i]; - if (buff) { - dma_unmap_tx(port, desc); - free_buffer(buff); - } - } - dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys); - port->desc_tab = NULL; - } - - if (!ports_open && dma_pool) { - dma_pool_destroy(dma_pool); - dma_pool = NULL; - } -} - -static int eth_open(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - struct npe *npe = port->npe; - struct msg msg; - int i, err; - - if (!npe_running(npe)) { - err = npe_load_firmware(npe, npe_name(npe), &dev->dev); - if (err) - return err; - - if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) { - printk(KERN_ERR "%s: %s not responding\n", dev->name, - npe_name(npe)); - return -EIO; - } - port->firmware[0] = msg.byte4; - port->firmware[1] = msg.byte5; - port->firmware[2] = msg.byte6; - port->firmware[3] = msg.byte7; - } - - memset(&msg, 0, sizeof(msg)); - msg.cmd = NPE_VLAN_SETRXQOSENTRY; - msg.eth_id = port->id; - msg.byte5 = port->plat->rxq | 0x80; - msg.byte7 = port->plat->rxq << 4; - for (i = 0; i < 8; i++) { - msg.byte3 = i; - if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) - return -EIO; - } - - msg.cmd = NPE_EDB_SETPORTADDRESS; - msg.eth_id = PHYSICAL_ID(port->id); - msg.byte2 = dev->dev_addr[0]; - msg.byte3 = dev->dev_addr[1]; - msg.byte4 = dev->dev_addr[2]; - msg.byte5 = dev->dev_addr[3]; - msg.byte6 = dev->dev_addr[4]; - msg.byte7 = dev->dev_addr[5]; - if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) - return -EIO; - - memset(&msg, 0, sizeof(msg)); - msg.cmd = NPE_FW_SETFIREWALLMODE; - msg.eth_id = port->id; - if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) - return -EIO; - - if ((err = request_queues(port)) != 0) - return err; - - if ((err = init_queues(port)) != 0) { - destroy_queues(port); - release_queues(port); - return err; - } - - port->speed = 0; /* force "link up" message */ - phy_start(port->phydev); - - for (i = 0; i < ETH_ALEN; i++) - __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]); - __raw_writel(0x08, &port->regs->random_seed); - __raw_writel(0x12, &port->regs->partial_empty_threshold); - __raw_writel(0x30, &port->regs->partial_full_threshold); - __raw_writel(0x08, &port->regs->tx_start_bytes); - __raw_writel(0x15, &port->regs->tx_deferral); - __raw_writel(0x08, &port->regs->tx_2part_deferral[0]); - __raw_writel(0x07, &port->regs->tx_2part_deferral[1]); - __raw_writel(0x80, &port->regs->slot_time); - __raw_writel(0x01, &port->regs->int_clock_threshold); - - /* Populate queues with buffers, no failure after this point */ - for (i = 0; i < TX_DESCS; i++) - queue_put_desc(port->plat->txreadyq, - tx_desc_phys(port, i), tx_desc_ptr(port, i)); - - for (i = 0; i < RX_DESCS; i++) - queue_put_desc(RXFREE_QUEUE(port->id), - rx_desc_phys(port, i), rx_desc_ptr(port, i)); - - __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]); - __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]); - __raw_writel(0, &port->regs->rx_control[1]); - __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]); - - napi_enable(&port->napi); - eth_set_mcast_list(dev); - netif_start_queue(dev); - - qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY, - eth_rx_irq, dev); - if (!ports_open) { - qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY, - eth_txdone_irq, NULL); - qmgr_enable_irq(TXDONE_QUEUE); - } - ports_open++; - /* we may already have RX data, enables IRQ */ - napi_schedule(&port->napi); - return 0; -} - -static int eth_close(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - struct msg msg; - int buffs = RX_DESCS; /* allocated RX buffers */ - int i; - - ports_open--; - qmgr_disable_irq(port->plat->rxq); - napi_disable(&port->napi); - netif_stop_queue(dev); - - while (queue_get_desc(RXFREE_QUEUE(port->id), port, 0) >= 0) - buffs--; - - memset(&msg, 0, sizeof(msg)); - msg.cmd = NPE_SETLOOPBACK_MODE; - msg.eth_id = port->id; - msg.byte3 = 1; - if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK")) - printk(KERN_CRIT "%s: unable to enable loopback\n", dev->name); - - i = 0; - do { /* drain RX buffers */ - while (queue_get_desc(port->plat->rxq, port, 0) >= 0) - buffs--; - if (!buffs) - break; - if (qmgr_stat_empty(TX_QUEUE(port->id))) { - /* we have to inject some packet */ - struct desc *desc; - u32 phys; - int n = queue_get_desc(port->plat->txreadyq, port, 1); - BUG_ON(n < 0); - desc = tx_desc_ptr(port, n); - phys = tx_desc_phys(port, n); - desc->buf_len = desc->pkt_len = 1; - wmb(); - queue_put_desc(TX_QUEUE(port->id), phys, desc); - } - udelay(1); - } while (++i < MAX_CLOSE_WAIT); - - if (buffs) - printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)" - " left in NPE\n", dev->name, buffs); -#if DEBUG_CLOSE - if (!buffs) - printk(KERN_DEBUG "Draining RX queue took %i cycles\n", i); -#endif - - buffs = TX_DESCS; - while (queue_get_desc(TX_QUEUE(port->id), port, 1) >= 0) - buffs--; /* cancel TX */ - - i = 0; - do { - while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0) - buffs--; - if (!buffs) - break; - } while (++i < MAX_CLOSE_WAIT); - - if (buffs) - printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) " - "left in NPE\n", dev->name, buffs); -#if DEBUG_CLOSE - if (!buffs) - printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i); -#endif - - msg.byte3 = 0; - if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK")) - printk(KERN_CRIT "%s: unable to disable loopback\n", - dev->name); - - phy_stop(port->phydev); - - if (!ports_open) - qmgr_disable_irq(TXDONE_QUEUE); - destroy_queues(port); - release_queues(port); - return 0; -} - -static const struct net_device_ops ixp4xx_netdev_ops = { - .ndo_open = eth_open, - .ndo_stop = eth_close, - .ndo_start_xmit = eth_xmit, - .ndo_set_multicast_list = eth_set_mcast_list, - .ndo_do_ioctl = eth_ioctl, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int __devinit eth_init_one(struct platform_device *pdev) -{ - struct port *port; - struct net_device *dev; - struct eth_plat_info *plat = pdev->dev.platform_data; - u32 regs_phys; - char phy_id[MII_BUS_ID_SIZE + 3]; - int err; - - if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) { - pr_err("ixp4xx_eth: bad ptp filter\n"); - return -EINVAL; - } - - if (!(dev = alloc_etherdev(sizeof(struct port)))) - return -ENOMEM; - - SET_NETDEV_DEV(dev, &pdev->dev); - port = netdev_priv(dev); - port->netdev = dev; - port->id = pdev->id; - - switch (port->id) { - case IXP4XX_ETH_NPEA: - port->regs = (struct eth_regs __iomem *)IXP4XX_EthA_BASE_VIRT; - regs_phys = IXP4XX_EthA_BASE_PHYS; - break; - case IXP4XX_ETH_NPEB: - port->regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; - regs_phys = IXP4XX_EthB_BASE_PHYS; - break; - case IXP4XX_ETH_NPEC: - port->regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT; - regs_phys = IXP4XX_EthC_BASE_PHYS; - break; - default: - err = -ENODEV; - goto err_free; - } - - dev->netdev_ops = &ixp4xx_netdev_ops; - dev->ethtool_ops = &ixp4xx_ethtool_ops; - dev->tx_queue_len = 100; - - netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT); - - if (!(port->npe = npe_request(NPE_ID(port->id)))) { - err = -EIO; - goto err_free; - } - - port->mem_res = request_mem_region(regs_phys, REGS_SIZE, dev->name); - if (!port->mem_res) { - err = -EBUSY; - goto err_npe_rel; - } - - port->plat = plat; - npe_port_tab[NPE_ID(port->id)] = port; - memcpy(dev->dev_addr, plat->hwaddr, ETH_ALEN); - - platform_set_drvdata(pdev, dev); - - __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET, - &port->regs->core_control); - udelay(50); - __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); - udelay(50); - - snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, "0", plat->phy); - port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0, - PHY_INTERFACE_MODE_MII); - if (IS_ERR(port->phydev)) { - err = PTR_ERR(port->phydev); - goto err_free_mem; - } - - port->phydev->irq = PHY_POLL; - - if ((err = register_netdev(dev))) - goto err_phy_dis; - - printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy, - npe_name(port->npe)); - - return 0; - -err_phy_dis: - phy_disconnect(port->phydev); -err_free_mem: - npe_port_tab[NPE_ID(port->id)] = NULL; - platform_set_drvdata(pdev, NULL); - release_resource(port->mem_res); -err_npe_rel: - npe_release(port->npe); -err_free: - free_netdev(dev); - return err; -} - -static int __devexit eth_remove_one(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct port *port = netdev_priv(dev); - - unregister_netdev(dev); - phy_disconnect(port->phydev); - npe_port_tab[NPE_ID(port->id)] = NULL; - platform_set_drvdata(pdev, NULL); - npe_release(port->npe); - release_resource(port->mem_res); - free_netdev(dev); - return 0; -} - -static struct platform_driver ixp4xx_eth_driver = { - .driver.name = DRV_NAME, - .probe = eth_init_one, - .remove = eth_remove_one, -}; - -static int __init eth_init_module(void) -{ - int err; - if ((err = ixp4xx_mdio_register())) - return err; - return platform_driver_register(&ixp4xx_eth_driver); -} - -static void __exit eth_cleanup_module(void) -{ - platform_driver_unregister(&ixp4xx_eth_driver); - ixp4xx_mdio_remove(); -} - -MODULE_AUTHOR("Krzysztof Halasa"); -MODULE_DESCRIPTION("Intel IXP4xx Ethernet driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:ixp4xx_eth"); -module_init(eth_init_module); -module_exit(eth_cleanup_module); diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c deleted file mode 100644 index c827a6097d0..00000000000 --- a/drivers/net/arm/ks8695net.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* - * Micrel KS8695 (Centaur) Ethernet. - * - * 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. - * - * Copyright 2008 Simtec Electronics - * Daniel Silverstone <dsilvers@simtec.co.uk> - * Vincent Sanders <vince@simtec.co.uk> - */ - -#include <linux/dma-mapping.h> -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/crc32.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <asm/irq.h> - -#include <mach/regs-switch.h> -#include <mach/regs-misc.h> -#include <asm/mach/irq.h> -#include <mach/regs-irq.h> - -#include "ks8695net.h" - -#define MODULENAME "ks8695_ether" -#define MODULEVERSION "1.02" - -/* - * Transmit and device reset timeout, default 5 seconds. - */ -static int watchdog = 5000; - -/* Hardware structures */ - -/** - * struct rx_ring_desc - Receive descriptor ring element - * @status: The status of the descriptor element (E.g. who owns it) - * @length: The number of bytes in the block pointed to by data_ptr - * @data_ptr: The physical address of the data block to receive into - * @next_desc: The physical address of the next descriptor element. - */ -struct rx_ring_desc { - __le32 status; - __le32 length; - __le32 data_ptr; - __le32 next_desc; -}; - -/** - * struct tx_ring_desc - Transmit descriptor ring element - * @owner: Who owns the descriptor - * @status: The number of bytes in the block pointed to by data_ptr - * @data_ptr: The physical address of the data block to receive into - * @next_desc: The physical address of the next descriptor element. - */ -struct tx_ring_desc { - __le32 owner; - __le32 status; - __le32 data_ptr; - __le32 next_desc; -}; - -/** - * struct ks8695_skbuff - sk_buff wrapper for rx/tx rings. - * @skb: The buffer in the ring - * @dma_ptr: The mapped DMA pointer of the buffer - * @length: The number of bytes mapped to dma_ptr - */ -struct ks8695_skbuff { - struct sk_buff *skb; - dma_addr_t dma_ptr; - u32 length; -}; - -/* Private device structure */ - -#define MAX_TX_DESC 8 -#define MAX_TX_DESC_MASK 0x7 -#define MAX_RX_DESC 16 -#define MAX_RX_DESC_MASK 0xf - -/*napi_weight have better more than rx DMA buffers*/ -#define NAPI_WEIGHT 64 - -#define MAX_RXBUF_SIZE 0x700 - -#define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC) -#define RX_RING_DMA_SIZE (sizeof(struct rx_ring_desc) * MAX_RX_DESC) -#define RING_DMA_SIZE (TX_RING_DMA_SIZE + RX_RING_DMA_SIZE) - -/** - * enum ks8695_dtype - Device type - * @KS8695_DTYPE_WAN: This device is a WAN interface - * @KS8695_DTYPE_LAN: This device is a LAN interface - * @KS8695_DTYPE_HPNA: This device is an HPNA interface - */ -enum ks8695_dtype { - KS8695_DTYPE_WAN, - KS8695_DTYPE_LAN, - KS8695_DTYPE_HPNA, -}; - -/** - * struct ks8695_priv - Private data for the KS8695 Ethernet - * @in_suspend: Flag to indicate if we're suspending/resuming - * @ndev: The net_device for this interface - * @dev: The platform device object for this interface - * @dtype: The type of this device - * @io_regs: The ioremapped registers for this interface - * @napi : Add support NAPI for Rx - * @rx_irq_name: The textual name of the RX IRQ from the platform data - * @tx_irq_name: The textual name of the TX IRQ from the platform data - * @link_irq_name: The textual name of the link IRQ from the - * platform data if available - * @rx_irq: The IRQ number for the RX IRQ - * @tx_irq: The IRQ number for the TX IRQ - * @link_irq: The IRQ number for the link IRQ if available - * @regs_req: The resource request for the registers region - * @phyiface_req: The resource request for the phy/switch region - * if available - * @phyiface_regs: The ioremapped registers for the phy/switch if available - * @ring_base: The base pointer of the dma coherent memory for the rings - * @ring_base_dma: The DMA mapped equivalent of ring_base - * @tx_ring: The pointer in ring_base of the TX ring - * @tx_ring_used: The number of slots in the TX ring which are occupied - * @tx_ring_next_slot: The next slot to fill in the TX ring - * @tx_ring_dma: The DMA mapped equivalent of tx_ring - * @tx_buffers: The sk_buff mappings for the TX ring - * @txq_lock: A lock to protect the tx_buffers tx_ring_used etc variables - * @rx_ring: The pointer in ring_base of the RX ring - * @rx_ring_dma: The DMA mapped equivalent of rx_ring - * @rx_buffers: The sk_buff mappings for the RX ring - * @next_rx_desc_read: The next RX descriptor to read from on IRQ - * @rx_lock: A lock to protect Rx irq function - * @msg_enable: The flags for which messages to emit - */ -struct ks8695_priv { - int in_suspend; - struct net_device *ndev; - struct device *dev; - enum ks8695_dtype dtype; - void __iomem *io_regs; - - struct napi_struct napi; - - const char *rx_irq_name, *tx_irq_name, *link_irq_name; - int rx_irq, tx_irq, link_irq; - - struct resource *regs_req, *phyiface_req; - void __iomem *phyiface_regs; - - void *ring_base; - dma_addr_t ring_base_dma; - - struct tx_ring_desc *tx_ring; - int tx_ring_used; - int tx_ring_next_slot; - dma_addr_t tx_ring_dma; - struct ks8695_skbuff tx_buffers[MAX_TX_DESC]; - spinlock_t txq_lock; - - struct rx_ring_desc *rx_ring; - dma_addr_t rx_ring_dma; - struct ks8695_skbuff rx_buffers[MAX_RX_DESC]; - int next_rx_desc_read; - spinlock_t rx_lock; - - int msg_enable; -}; - -/* Register access */ - -/** - * ks8695_readreg - Read from a KS8695 ethernet register - * @ksp: The device to read from - * @reg: The register to read - */ -static inline u32 -ks8695_readreg(struct ks8695_priv *ksp, int reg) -{ - return readl(ksp->io_regs + reg); -} - -/** - * ks8695_writereg - Write to a KS8695 ethernet register - * @ksp: The device to write to - * @reg: The register to write - * @value: The value to write to the register - */ -static inline void -ks8695_writereg(struct ks8695_priv *ksp, int reg, u32 value) -{ - writel(value, ksp->io_regs + reg); -} - -/* Utility functions */ - -/** - * ks8695_port_type - Retrieve port-type as user-friendly string - * @ksp: The device to return the type for - * - * Returns a string indicating which of the WAN, LAN or HPNA - * ports this device is likely to represent. - */ -static const char * -ks8695_port_type(struct ks8695_priv *ksp) -{ - switch (ksp->dtype) { - case KS8695_DTYPE_LAN: - return "LAN"; - case KS8695_DTYPE_WAN: - return "WAN"; - case KS8695_DTYPE_HPNA: - return "HPNA"; - } - - return "UNKNOWN"; -} - -/** - * ks8695_update_mac - Update the MAC registers in the device - * @ksp: The device to update - * - * Updates the MAC registers in the KS8695 device from the address in the - * net_device structure associated with this interface. - */ -static void -ks8695_update_mac(struct ks8695_priv *ksp) -{ - /* Update the HW with the MAC from the net_device */ - struct net_device *ndev = ksp->ndev; - u32 machigh, maclow; - - maclow = ((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) | - (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5] << 0)); - machigh = ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1] << 0)); - - ks8695_writereg(ksp, KS8695_MAL, maclow); - ks8695_writereg(ksp, KS8695_MAH, machigh); - -} - -/** - * ks8695_refill_rxbuffers - Re-fill the RX buffer ring - * @ksp: The device to refill - * - * Iterates the RX ring of the device looking for empty slots. - * For each empty slot, we allocate and map a new SKB and give it - * to the hardware. - * This can be called from interrupt context safely. - */ -static void -ks8695_refill_rxbuffers(struct ks8695_priv *ksp) -{ - /* Run around the RX ring, filling in any missing sk_buff's */ - int buff_n; - - for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { - if (!ksp->rx_buffers[buff_n].skb) { - struct sk_buff *skb = dev_alloc_skb(MAX_RXBUF_SIZE); - dma_addr_t mapping; - - ksp->rx_buffers[buff_n].skb = skb; - if (skb == NULL) { - /* Failed to allocate one, perhaps - * we'll try again later. - */ - break; - } - - mapping = dma_map_single(ksp->dev, skb->data, - MAX_RXBUF_SIZE, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(ksp->dev, mapping))) { - /* Failed to DMA map this SKB, try later */ - dev_kfree_skb_irq(skb); - ksp->rx_buffers[buff_n].skb = NULL; - break; - } - ksp->rx_buffers[buff_n].dma_ptr = mapping; - skb->dev = ksp->ndev; - ksp->rx_buffers[buff_n].length = MAX_RXBUF_SIZE; - - /* Record this into the DMA ring */ - ksp->rx_ring[buff_n].data_ptr = cpu_to_le32(mapping); - ksp->rx_ring[buff_n].length = - cpu_to_le32(MAX_RXBUF_SIZE); - - wmb(); - - /* And give ownership over to the hardware */ - ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); - } - } -} - -/* Maximum number of multicast addresses which the KS8695 HW supports */ -#define KS8695_NR_ADDRESSES 16 - -/** - * ks8695_init_partial_multicast - Init the mcast addr registers - * @ksp: The device to initialise - * @addr: The multicast address list to use - * @nr_addr: The number of addresses in the list - * - * This routine is a helper for ks8695_set_multicast - it writes - * the additional-address registers in the KS8695 ethernet device - * and cleans up any others left behind. - */ -static void -ks8695_init_partial_multicast(struct ks8695_priv *ksp, - struct net_device *ndev) -{ - u32 low, high; - int i; - struct netdev_hw_addr *ha; - - i = 0; - netdev_for_each_mc_addr(ha, ndev) { - /* Ran out of space in chip? */ - BUG_ON(i == KS8695_NR_ADDRESSES); - - low = (ha->addr[2] << 24) | (ha->addr[3] << 16) | - (ha->addr[4] << 8) | (ha->addr[5]); - high = (ha->addr[0] << 8) | (ha->addr[1]); - - ks8695_writereg(ksp, KS8695_AAL_(i), low); - ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high); - i++; - } - - /* Clear the remaining Additional Station Addresses */ - for (; i < KS8695_NR_ADDRESSES; i++) { - ks8695_writereg(ksp, KS8695_AAL_(i), 0); - ks8695_writereg(ksp, KS8695_AAH_(i), 0); - } -} - -/* Interrupt handling */ - -/** - * ks8695_tx_irq - Transmit IRQ handler - * @irq: The IRQ which went off (ignored) - * @dev_id: The net_device for the interrupt - * - * Process the TX ring, clearing out any transmitted slots. - * Allows the net_device to pass us new packets once slots are - * freed. - */ -static irqreturn_t -ks8695_tx_irq(int irq, void *dev_id) -{ - struct net_device *ndev = (struct net_device *)dev_id; - struct ks8695_priv *ksp = netdev_priv(ndev); - int buff_n; - - for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { - if (ksp->tx_buffers[buff_n].skb && - !(ksp->tx_ring[buff_n].owner & cpu_to_le32(TDES_OWN))) { - rmb(); - /* An SKB which is not owned by HW is present */ - /* Update the stats for the net_device */ - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += ksp->tx_buffers[buff_n].length; - - /* Free the packet from the ring */ - ksp->tx_ring[buff_n].data_ptr = 0; - - /* Free the sk_buff */ - dma_unmap_single(ksp->dev, - ksp->tx_buffers[buff_n].dma_ptr, - ksp->tx_buffers[buff_n].length, - DMA_TO_DEVICE); - dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb); - ksp->tx_buffers[buff_n].skb = NULL; - ksp->tx_ring_used--; - } - } - - netif_wake_queue(ndev); - - return IRQ_HANDLED; -} - -/** - * ks8695_get_rx_enable_bit - Get rx interrupt enable/status bit - * @ksp: Private data for the KS8695 Ethernet - * - * For KS8695 document: - * Interrupt Enable Register (offset 0xE204) - * Bit29 : WAN MAC Receive Interrupt Enable - * Bit16 : LAN MAC Receive Interrupt Enable - * Interrupt Status Register (Offset 0xF208) - * Bit29: WAN MAC Receive Status - * Bit16: LAN MAC Receive Status - * So, this Rx interrrupt enable/status bit number is equal - * as Rx IRQ number. - */ -static inline u32 ks8695_get_rx_enable_bit(struct ks8695_priv *ksp) -{ - return ksp->rx_irq; -} - -/** - * ks8695_rx_irq - Receive IRQ handler - * @irq: The IRQ which went off (ignored) - * @dev_id: The net_device for the interrupt - * - * Inform NAPI that packet reception needs to be scheduled - */ - -static irqreturn_t -ks8695_rx_irq(int irq, void *dev_id) -{ - struct net_device *ndev = (struct net_device *)dev_id; - struct ks8695_priv *ksp = netdev_priv(ndev); - - spin_lock(&ksp->rx_lock); - - if (napi_schedule_prep(&ksp->napi)) { - unsigned long status = readl(KS8695_IRQ_VA + KS8695_INTEN); - unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp); - /*disable rx interrupt*/ - status &= ~mask_bit; - writel(status , KS8695_IRQ_VA + KS8695_INTEN); - __napi_schedule(&ksp->napi); - } - - spin_unlock(&ksp->rx_lock); - return IRQ_HANDLED; -} - -/** - * ks8695_rx - Receive packets called by NAPI poll method - * @ksp: Private data for the KS8695 Ethernet - * @budget: Number of packets allowed to process - */ -static int ks8695_rx(struct ks8695_priv *ksp, int budget) -{ - struct net_device *ndev = ksp->ndev; - struct sk_buff *skb; - int buff_n; - u32 flags; - int pktlen; - int received = 0; - - buff_n = ksp->next_rx_desc_read; - while (received < budget - && ksp->rx_buffers[buff_n].skb - && (!(ksp->rx_ring[buff_n].status & - cpu_to_le32(RDES_OWN)))) { - rmb(); - flags = le32_to_cpu(ksp->rx_ring[buff_n].status); - - /* Found an SKB which we own, this means we - * received a packet - */ - if ((flags & (RDES_FS | RDES_LS)) != - (RDES_FS | RDES_LS)) { - /* This packet is not the first and - * the last segment. Therefore it is - * a "spanning" packet and we can't - * handle it - */ - goto rx_failure; - } - - if (flags & (RDES_ES | RDES_RE)) { - /* It's an error packet */ - ndev->stats.rx_errors++; - if (flags & RDES_TL) - ndev->stats.rx_length_errors++; - if (flags & RDES_RF) - ndev->stats.rx_length_errors++; - if (flags & RDES_CE) - ndev->stats.rx_crc_errors++; - if (flags & RDES_RE) - ndev->stats.rx_missed_errors++; - - goto rx_failure; - } - - pktlen = flags & RDES_FLEN; - pktlen -= 4; /* Drop the CRC */ - - /* Retrieve the sk_buff */ - skb = ksp->rx_buffers[buff_n].skb; - - /* Clear it from the ring */ - ksp->rx_buffers[buff_n].skb = NULL; - ksp->rx_ring[buff_n].data_ptr = 0; - - /* Unmap the SKB */ - dma_unmap_single(ksp->dev, - ksp->rx_buffers[buff_n].dma_ptr, - ksp->rx_buffers[buff_n].length, - DMA_FROM_DEVICE); - - /* Relinquish the SKB to the network layer */ - skb_put(skb, pktlen); - skb->protocol = eth_type_trans(skb, ndev); - netif_receive_skb(skb); - - /* Record stats */ - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += pktlen; - goto rx_finished; - -rx_failure: - /* This ring entry is an error, but we can - * re-use the skb - */ - /* Give the ring entry back to the hardware */ - ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); -rx_finished: - received++; - buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; - } - - /* And note which RX descriptor we last did */ - ksp->next_rx_desc_read = buff_n; - - /* And refill the buffers */ - ks8695_refill_rxbuffers(ksp); - - /* Kick the RX DMA engine, in case it became suspended */ - ks8695_writereg(ksp, KS8695_DRSC, 0); - - return received; -} - - -/** - * ks8695_poll - Receive packet by NAPI poll method - * @ksp: Private data for the KS8695 Ethernet - * @budget: The remaining number packets for network subsystem - * - * Invoked by the network core when it requests for new - * packets from the driver - */ -static int ks8695_poll(struct napi_struct *napi, int budget) -{ - struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi); - unsigned long work_done; - - unsigned long isr = readl(KS8695_IRQ_VA + KS8695_INTEN); - unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp); - - work_done = ks8695_rx(ksp, budget); - - if (work_done < budget) { - unsigned long flags; - spin_lock_irqsave(&ksp->rx_lock, flags); - __napi_complete(napi); - /*enable rx interrupt*/ - writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN); - spin_unlock_irqrestore(&ksp->rx_lock, flags); - } - return work_done; -} - -/** - * ks8695_link_irq - Link change IRQ handler - * @irq: The IRQ which went off (ignored) - * @dev_id: The net_device for the interrupt - * - * The WAN interface can generate an IRQ when the link changes, - * report this to the net layer and the user. - */ -static irqreturn_t -ks8695_link_irq(int irq, void *dev_id) -{ - struct net_device *ndev = (struct net_device *)dev_id; - struct ks8695_priv *ksp = netdev_priv(ndev); - u32 ctrl; - - ctrl = readl(ksp->phyiface_regs + KS8695_WMC); - if (ctrl & WMC_WLS) { - netif_carrier_on(ndev); - if (netif_msg_link(ksp)) - dev_info(ksp->dev, - "%s: Link is now up (10%sMbps/%s-duplex)\n", - ndev->name, - (ctrl & WMC_WSS) ? "0" : "", - (ctrl & WMC_WDS) ? "Full" : "Half"); - } else { - netif_carrier_off(ndev); - if (netif_msg_link(ksp)) - dev_info(ksp->dev, "%s: Link is now down.\n", - ndev->name); - } - - return IRQ_HANDLED; -} - - -/* KS8695 Device functions */ - -/** - * ks8695_reset - Reset a KS8695 ethernet interface - * @ksp: The interface to reset - * - * Perform an engine reset of the interface and re-program it - * with sensible defaults. - */ -static void -ks8695_reset(struct ks8695_priv *ksp) -{ - int reset_timeout = watchdog; - /* Issue the reset via the TX DMA control register */ - ks8695_writereg(ksp, KS8695_DTXC, DTXC_TRST); - while (reset_timeout--) { - if (!(ks8695_readreg(ksp, KS8695_DTXC) & DTXC_TRST)) - break; - msleep(1); - } - - if (reset_timeout < 0) { - dev_crit(ksp->dev, - "Timeout waiting for DMA engines to reset\n"); - /* And blithely carry on */ - } - - /* Definitely wait long enough before attempting to program - * the engines - */ - msleep(10); - - /* RX: unicast and broadcast */ - ks8695_writereg(ksp, KS8695_DRXC, DRXC_RU | DRXC_RB); - /* TX: pad and add CRC */ - ks8695_writereg(ksp, KS8695_DTXC, DTXC_TEP | DTXC_TAC); -} - -/** - * ks8695_shutdown - Shut down a KS8695 ethernet interface - * @ksp: The interface to shut down - * - * This disables packet RX/TX, cleans up IRQs, drains the rings, - * and basically places the interface into a clean shutdown - * state. - */ -static void -ks8695_shutdown(struct ks8695_priv *ksp) -{ - u32 ctrl; - int buff_n; - - /* Disable packet transmission */ - ctrl = ks8695_readreg(ksp, KS8695_DTXC); - ks8695_writereg(ksp, KS8695_DTXC, ctrl & ~DTXC_TE); - - /* Disable packet reception */ - ctrl = ks8695_readreg(ksp, KS8695_DRXC); - ks8695_writereg(ksp, KS8695_DRXC, ctrl & ~DRXC_RE); - - /* Release the IRQs */ - free_irq(ksp->rx_irq, ksp->ndev); - free_irq(ksp->tx_irq, ksp->ndev); - if (ksp->link_irq != -1) - free_irq(ksp->link_irq, ksp->ndev); - - /* Throw away any pending TX packets */ - for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { - if (ksp->tx_buffers[buff_n].skb) { - /* Remove this SKB from the TX ring */ - ksp->tx_ring[buff_n].owner = 0; - ksp->tx_ring[buff_n].status = 0; - ksp->tx_ring[buff_n].data_ptr = 0; - - /* Unmap and bin this SKB */ - dma_unmap_single(ksp->dev, - ksp->tx_buffers[buff_n].dma_ptr, - ksp->tx_buffers[buff_n].length, - DMA_TO_DEVICE); - dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb); - ksp->tx_buffers[buff_n].skb = NULL; - } - } - - /* Purge the RX buffers */ - for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { - if (ksp->rx_buffers[buff_n].skb) { - /* Remove the SKB from the RX ring */ - ksp->rx_ring[buff_n].status = 0; - ksp->rx_ring[buff_n].data_ptr = 0; - - /* Unmap and bin the SKB */ - dma_unmap_single(ksp->dev, - ksp->rx_buffers[buff_n].dma_ptr, - ksp->rx_buffers[buff_n].length, - DMA_FROM_DEVICE); - dev_kfree_skb_irq(ksp->rx_buffers[buff_n].skb); - ksp->rx_buffers[buff_n].skb = NULL; - } - } -} - - -/** - * ks8695_setup_irq - IRQ setup helper function - * @irq: The IRQ number to claim - * @irq_name: The name to give the IRQ claimant - * @handler: The function to call to handle the IRQ - * @ndev: The net_device to pass in as the dev_id argument to the handler - * - * Return 0 on success. - */ -static int -ks8695_setup_irq(int irq, const char *irq_name, - irq_handler_t handler, struct net_device *ndev) -{ - int ret; - - ret = request_irq(irq, handler, IRQF_SHARED, irq_name, ndev); - - if (ret) { - dev_err(&ndev->dev, "failure to request IRQ %d\n", irq); - return ret; - } - - return 0; -} - -/** - * ks8695_init_net - Initialise a KS8695 ethernet interface - * @ksp: The interface to initialise - * - * This routine fills the RX ring, initialises the DMA engines, - * allocates the IRQs and then starts the packet TX and RX - * engines. - */ -static int -ks8695_init_net(struct ks8695_priv *ksp) -{ - int ret; - u32 ctrl; - - ks8695_refill_rxbuffers(ksp); - - /* Initialise the DMA engines */ - ks8695_writereg(ksp, KS8695_RDLB, (u32) ksp->rx_ring_dma); - ks8695_writereg(ksp, KS8695_TDLB, (u32) ksp->tx_ring_dma); - - /* Request the IRQs */ - ret = ks8695_setup_irq(ksp->rx_irq, ksp->rx_irq_name, - ks8695_rx_irq, ksp->ndev); - if (ret) - return ret; - ret = ks8695_setup_irq(ksp->tx_irq, ksp->tx_irq_name, - ks8695_tx_irq, ksp->ndev); - if (ret) - return ret; - if (ksp->link_irq != -1) { - ret = ks8695_setup_irq(ksp->link_irq, ksp->link_irq_name, - ks8695_link_irq, ksp->ndev); - if (ret) - return ret; - } - - /* Set up the ring indices */ - ksp->next_rx_desc_read = 0; - ksp->tx_ring_next_slot = 0; - ksp->tx_ring_used = 0; - - /* Bring up transmission */ - ctrl = ks8695_readreg(ksp, KS8695_DTXC); - /* Enable packet transmission */ - ks8695_writereg(ksp, KS8695_DTXC, ctrl | DTXC_TE); - - /* Bring up the reception */ - ctrl = ks8695_readreg(ksp, KS8695_DRXC); - /* Enable packet reception */ - ks8695_writereg(ksp, KS8695_DRXC, ctrl | DRXC_RE); - /* And start the DMA engine */ - ks8695_writereg(ksp, KS8695_DRSC, 0); - - /* All done */ - return 0; -} - -/** - * ks8695_release_device - HW resource release for KS8695 e-net - * @ksp: The device to be freed - * - * This unallocates io memory regions, dma-coherent regions etc - * which were allocated in ks8695_probe. - */ -static void -ks8695_release_device(struct ks8695_priv *ksp) -{ - /* Unmap the registers */ - iounmap(ksp->io_regs); - if (ksp->phyiface_regs) - iounmap(ksp->phyiface_regs); - - /* And release the request */ - release_resource(ksp->regs_req); - kfree(ksp->regs_req); - if (ksp->phyiface_req) { - release_resource(ksp->phyiface_req); - kfree(ksp->phyiface_req); - } - - /* Free the ring buffers */ - dma_free_coherent(ksp->dev, RING_DMA_SIZE, - ksp->ring_base, ksp->ring_base_dma); -} - -/* Ethtool support */ - -/** - * ks8695_get_msglevel - Get the messages enabled for emission - * @ndev: The network device to read from - */ -static u32 -ks8695_get_msglevel(struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - - return ksp->msg_enable; -} - -/** - * ks8695_set_msglevel - Set the messages enabled for emission - * @ndev: The network device to configure - * @value: The messages to set for emission - */ -static void -ks8695_set_msglevel(struct net_device *ndev, u32 value) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - - ksp->msg_enable = value; -} - -/** - * ks8695_wan_get_settings - Get device-specific settings. - * @ndev: The network device to read settings from - * @cmd: The ethtool structure to read into - */ -static int -ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - u32 ctrl; - - /* All ports on the KS8695 support these... */ - cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_TP | SUPPORTED_MII); - cmd->transceiver = XCVR_INTERNAL; - - cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; - cmd->port = PORT_MII; - cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause); - cmd->phy_address = 0; - - ctrl = readl(ksp->phyiface_regs + KS8695_WMC); - if ((ctrl & WMC_WAND) == 0) { - /* auto-negotiation is enabled */ - cmd->advertising |= ADVERTISED_Autoneg; - if (ctrl & WMC_WANA100F) - cmd->advertising |= ADVERTISED_100baseT_Full; - if (ctrl & WMC_WANA100H) - cmd->advertising |= ADVERTISED_100baseT_Half; - if (ctrl & WMC_WANA10F) - cmd->advertising |= ADVERTISED_10baseT_Full; - if (ctrl & WMC_WANA10H) - cmd->advertising |= ADVERTISED_10baseT_Half; - if (ctrl & WMC_WANAP) - cmd->advertising |= ADVERTISED_Pause; - cmd->autoneg = AUTONEG_ENABLE; - - ethtool_cmd_speed_set(cmd, - (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10); - cmd->duplex = (ctrl & WMC_WDS) ? - DUPLEX_FULL : DUPLEX_HALF; - } else { - /* auto-negotiation is disabled */ - cmd->autoneg = AUTONEG_DISABLE; - - ethtool_cmd_speed_set(cmd, ((ctrl & WMC_WANF100) ? - SPEED_100 : SPEED_10)); - cmd->duplex = (ctrl & WMC_WANFF) ? - DUPLEX_FULL : DUPLEX_HALF; - } - - return 0; -} - -/** - * ks8695_wan_set_settings - Set device-specific settings. - * @ndev: The network device to configure - * @cmd: The settings to configure - */ -static int -ks8695_wan_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - u32 ctrl; - - if ((cmd->speed != SPEED_10) && (cmd->speed != SPEED_100)) - return -EINVAL; - if ((cmd->duplex != DUPLEX_HALF) && (cmd->duplex != DUPLEX_FULL)) - return -EINVAL; - if (cmd->port != PORT_MII) - return -EINVAL; - if (cmd->transceiver != XCVR_INTERNAL) - return -EINVAL; - if ((cmd->autoneg != AUTONEG_DISABLE) && - (cmd->autoneg != AUTONEG_ENABLE)) - return -EINVAL; - - if (cmd->autoneg == AUTONEG_ENABLE) { - if ((cmd->advertising & (ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full)) == 0) - return -EINVAL; - - ctrl = readl(ksp->phyiface_regs + KS8695_WMC); - - ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H | - WMC_WANA10F | WMC_WANA10H); - if (cmd->advertising & ADVERTISED_100baseT_Full) - ctrl |= WMC_WANA100F; - if (cmd->advertising & ADVERTISED_100baseT_Half) - ctrl |= WMC_WANA100H; - if (cmd->advertising & ADVERTISED_10baseT_Full) - ctrl |= WMC_WANA10F; - if (cmd->advertising & ADVERTISED_10baseT_Half) - ctrl |= WMC_WANA10H; - - /* force a re-negotiation */ - ctrl |= WMC_WANR; - writel(ctrl, ksp->phyiface_regs + KS8695_WMC); - } else { - ctrl = readl(ksp->phyiface_regs + KS8695_WMC); - - /* disable auto-negotiation */ - ctrl |= WMC_WAND; - ctrl &= ~(WMC_WANF100 | WMC_WANFF); - - if (cmd->speed == SPEED_100) - ctrl |= WMC_WANF100; - if (cmd->duplex == DUPLEX_FULL) - ctrl |= WMC_WANFF; - - writel(ctrl, ksp->phyiface_regs + KS8695_WMC); - } - - return 0; -} - -/** - * ks8695_wan_nwayreset - Restart the autonegotiation on the port. - * @ndev: The network device to restart autoneotiation on - */ -static int -ks8695_wan_nwayreset(struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - u32 ctrl; - - ctrl = readl(ksp->phyiface_regs + KS8695_WMC); - - if ((ctrl & WMC_WAND) == 0) - writel(ctrl | WMC_WANR, - ksp->phyiface_regs + KS8695_WMC); - else - /* auto-negotiation not enabled */ - return -EINVAL; - - return 0; -} - -/** - * ks8695_wan_get_pause - Retrieve network pause/flow-control advertising - * @ndev: The device to retrieve settings from - * @param: The structure to fill out with the information - */ -static void -ks8695_wan_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - u32 ctrl; - - ctrl = readl(ksp->phyiface_regs + KS8695_WMC); - - /* advertise Pause */ - param->autoneg = (ctrl & WMC_WANAP); - - /* current Rx Flow-control */ - ctrl = ks8695_readreg(ksp, KS8695_DRXC); - param->rx_pause = (ctrl & DRXC_RFCE); - - /* current Tx Flow-control */ - ctrl = ks8695_readreg(ksp, KS8695_DTXC); - param->tx_pause = (ctrl & DTXC_TFCE); -} - -/** - * ks8695_get_drvinfo - Retrieve driver information - * @ndev: The network device to retrieve info about - * @info: The info structure to fill out. - */ -static void -ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, MODULENAME, sizeof(info->driver)); - strlcpy(info->version, MODULEVERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev_name(ndev->dev.parent), - sizeof(info->bus_info)); -} - -static const struct ethtool_ops ks8695_ethtool_ops = { - .get_msglevel = ks8695_get_msglevel, - .set_msglevel = ks8695_set_msglevel, - .get_drvinfo = ks8695_get_drvinfo, -}; - -static const struct ethtool_ops ks8695_wan_ethtool_ops = { - .get_msglevel = ks8695_get_msglevel, - .set_msglevel = ks8695_set_msglevel, - .get_settings = ks8695_wan_get_settings, - .set_settings = ks8695_wan_set_settings, - .nway_reset = ks8695_wan_nwayreset, - .get_link = ethtool_op_get_link, - .get_pauseparam = ks8695_wan_get_pause, - .get_drvinfo = ks8695_get_drvinfo, -}; - -/* Network device interface functions */ - -/** - * ks8695_set_mac - Update MAC in net dev and HW - * @ndev: The network device to update - * @addr: The new MAC address to set - */ -static int -ks8695_set_mac(struct net_device *ndev, void *addr) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - struct sockaddr *address = addr; - - if (!is_valid_ether_addr(address->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len); - - ks8695_update_mac(ksp); - - dev_dbg(ksp->dev, "%s: Updated MAC address to %pM\n", - ndev->name, ndev->dev_addr); - - return 0; -} - -/** - * ks8695_set_multicast - Set up the multicast behaviour of the interface - * @ndev: The net_device to configure - * - * This routine, called by the net layer, configures promiscuity - * and multicast reception behaviour for the interface. - */ -static void -ks8695_set_multicast(struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - u32 ctrl; - - ctrl = ks8695_readreg(ksp, KS8695_DRXC); - - if (ndev->flags & IFF_PROMISC) { - /* enable promiscuous mode */ - ctrl |= DRXC_RA; - } else if (ndev->flags & ~IFF_PROMISC) { - /* disable promiscuous mode */ - ctrl &= ~DRXC_RA; - } - - if (ndev->flags & IFF_ALLMULTI) { - /* enable all multicast mode */ - ctrl |= DRXC_RM; - } else if (netdev_mc_count(ndev) > KS8695_NR_ADDRESSES) { - /* more specific multicast addresses than can be - * handled in hardware - */ - ctrl |= DRXC_RM; - } else { - /* enable specific multicasts */ - ctrl &= ~DRXC_RM; - ks8695_init_partial_multicast(ksp, ndev); - } - - ks8695_writereg(ksp, KS8695_DRXC, ctrl); -} - -/** - * ks8695_timeout - Handle a network tx/rx timeout. - * @ndev: The net_device which timed out. - * - * A network transaction timed out, reset the device. - */ -static void -ks8695_timeout(struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - - netif_stop_queue(ndev); - ks8695_shutdown(ksp); - - ks8695_reset(ksp); - - ks8695_update_mac(ksp); - - /* We ignore the return from this since it managed to init - * before it probably will be okay to init again. - */ - ks8695_init_net(ksp); - - /* Reconfigure promiscuity etc */ - ks8695_set_multicast(ndev); - - /* And start the TX queue once more */ - netif_start_queue(ndev); -} - -/** - * ks8695_start_xmit - Start a packet transmission - * @skb: The packet to transmit - * @ndev: The network device to send the packet on - * - * This routine, called by the net layer, takes ownership of the - * sk_buff and adds it to the TX ring. It then kicks the TX DMA - * engine to ensure transmission begins. - */ -static int -ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - int buff_n; - dma_addr_t dmap; - - spin_lock_irq(&ksp->txq_lock); - - if (ksp->tx_ring_used == MAX_TX_DESC) { - /* Somehow we got entered when we have no room */ - spin_unlock_irq(&ksp->txq_lock); - return NETDEV_TX_BUSY; - } - - buff_n = ksp->tx_ring_next_slot; - - BUG_ON(ksp->tx_buffers[buff_n].skb); - - dmap = dma_map_single(ksp->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(ksp->dev, dmap))) { - /* Failed to DMA map this SKB, give it back for now */ - spin_unlock_irq(&ksp->txq_lock); - dev_dbg(ksp->dev, "%s: Could not map DMA memory for "\ - "transmission, trying later\n", ndev->name); - return NETDEV_TX_BUSY; - } - - ksp->tx_buffers[buff_n].dma_ptr = dmap; - /* Mapped okay, store the buffer pointer and length for later */ - ksp->tx_buffers[buff_n].skb = skb; - ksp->tx_buffers[buff_n].length = skb->len; - - /* Fill out the TX descriptor */ - ksp->tx_ring[buff_n].data_ptr = - cpu_to_le32(ksp->tx_buffers[buff_n].dma_ptr); - ksp->tx_ring[buff_n].status = - cpu_to_le32(TDES_IC | TDES_FS | TDES_LS | - (skb->len & TDES_TBS)); - - wmb(); - - /* Hand it over to the hardware */ - ksp->tx_ring[buff_n].owner = cpu_to_le32(TDES_OWN); - - if (++ksp->tx_ring_used == MAX_TX_DESC) - netif_stop_queue(ndev); - - /* Kick the TX DMA in case it decided to go IDLE */ - ks8695_writereg(ksp, KS8695_DTSC, 0); - - /* And update the next ring slot */ - ksp->tx_ring_next_slot = (buff_n + 1) & MAX_TX_DESC_MASK; - - spin_unlock_irq(&ksp->txq_lock); - return NETDEV_TX_OK; -} - -/** - * ks8695_stop - Stop (shutdown) a KS8695 ethernet interface - * @ndev: The net_device to stop - * - * This disables the TX queue and cleans up a KS8695 ethernet - * device. - */ -static int -ks8695_stop(struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - - netif_stop_queue(ndev); - napi_disable(&ksp->napi); - - ks8695_shutdown(ksp); - - return 0; -} - -/** - * ks8695_open - Open (bring up) a KS8695 ethernet interface - * @ndev: The net_device to open - * - * This resets, configures the MAC, initialises the RX ring and - * DMA engines and starts the TX queue for a KS8695 ethernet - * device. - */ -static int -ks8695_open(struct net_device *ndev) -{ - struct ks8695_priv *ksp = netdev_priv(ndev); - int ret; - - if (!is_valid_ether_addr(ndev->dev_addr)) - return -EADDRNOTAVAIL; - - ks8695_reset(ksp); - - ks8695_update_mac(ksp); - - ret = ks8695_init_net(ksp); - if (ret) { - ks8695_shutdown(ksp); - return ret; - } - - napi_enable(&ksp->napi); - netif_start_queue(ndev); - - return 0; -} - -/* Platform device driver */ - -/** - * ks8695_init_switch - Init LAN switch to known good defaults. - * @ksp: The device to initialise - * - * This initialises the LAN switch in the KS8695 to a known-good - * set of defaults. - */ -static void __devinit -ks8695_init_switch(struct ks8695_priv *ksp) -{ - u32 ctrl; - - /* Default value for SEC0 according to datasheet */ - ctrl = 0x40819e00; - - /* LED0 = Speed LED1 = Link/Activity */ - ctrl &= ~(SEC0_LLED1S | SEC0_LLED0S); - ctrl |= (LLED0S_LINK | LLED1S_LINK_ACTIVITY); - - /* Enable Switch */ - ctrl |= SEC0_ENABLE; - - writel(ctrl, ksp->phyiface_regs + KS8695_SEC0); - - /* Defaults for SEC1 */ - writel(0x9400100, ksp->phyiface_regs + KS8695_SEC1); -} - -/** - * ks8695_init_wan_phy - Initialise the WAN PHY to sensible defaults - * @ksp: The device to initialise - * - * This initialises a KS8695's WAN phy to sensible values for - * autonegotiation etc. - */ -static void __devinit -ks8695_init_wan_phy(struct ks8695_priv *ksp) -{ - u32 ctrl; - - /* Support auto-negotiation */ - ctrl = (WMC_WANAP | WMC_WANA100F | WMC_WANA100H | - WMC_WANA10F | WMC_WANA10H); - - /* LED0 = Activity , LED1 = Link */ - ctrl |= (WLED0S_ACTIVITY | WLED1S_LINK); - - /* Restart Auto-negotiation */ - ctrl |= WMC_WANR; - - writel(ctrl, ksp->phyiface_regs + KS8695_WMC); - - writel(0, ksp->phyiface_regs + KS8695_WPPM); - writel(0, ksp->phyiface_regs + KS8695_PPS); -} - -static const struct net_device_ops ks8695_netdev_ops = { - .ndo_open = ks8695_open, - .ndo_stop = ks8695_stop, - .ndo_start_xmit = ks8695_start_xmit, - .ndo_tx_timeout = ks8695_timeout, - .ndo_set_mac_address = ks8695_set_mac, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = ks8695_set_multicast, -}; - -/** - * ks8695_probe - Probe and initialise a KS8695 ethernet interface - * @pdev: The platform device to probe - * - * Initialise a KS8695 ethernet device from platform data. - * - * This driver requires at least one IORESOURCE_MEM for the - * registers and two IORESOURCE_IRQ for the RX and TX IRQs - * respectively. It can optionally take an additional - * IORESOURCE_MEM for the switch or phy in the case of the lan or - * wan ports, and an IORESOURCE_IRQ for the link IRQ for the wan - * port. - */ -static int __devinit -ks8695_probe(struct platform_device *pdev) -{ - struct ks8695_priv *ksp; - struct net_device *ndev; - struct resource *regs_res, *phyiface_res; - struct resource *rxirq_res, *txirq_res, *linkirq_res; - int ret = 0; - int buff_n; - u32 machigh, maclow; - - /* Initialise a net_device */ - ndev = alloc_etherdev(sizeof(struct ks8695_priv)); - if (!ndev) { - dev_err(&pdev->dev, "could not allocate device.\n"); - return -ENOMEM; - } - - SET_NETDEV_DEV(ndev, &pdev->dev); - - dev_dbg(&pdev->dev, "ks8695_probe() called\n"); - - /* Configure our private structure a little */ - ksp = netdev_priv(ndev); - - ksp->dev = &pdev->dev; - ksp->ndev = ndev; - ksp->msg_enable = NETIF_MSG_LINK; - - /* Retrieve resources */ - regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - phyiface_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - rxirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - txirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - linkirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 2); - - if (!(regs_res && rxirq_res && txirq_res)) { - dev_err(ksp->dev, "insufficient resources\n"); - ret = -ENOENT; - goto failure; - } - - ksp->regs_req = request_mem_region(regs_res->start, - resource_size(regs_res), - pdev->name); - - if (!ksp->regs_req) { - dev_err(ksp->dev, "cannot claim register space\n"); - ret = -EIO; - goto failure; - } - - ksp->io_regs = ioremap(regs_res->start, resource_size(regs_res)); - - if (!ksp->io_regs) { - dev_err(ksp->dev, "failed to ioremap registers\n"); - ret = -EINVAL; - goto failure; - } - - if (phyiface_res) { - ksp->phyiface_req = - request_mem_region(phyiface_res->start, - resource_size(phyiface_res), - phyiface_res->name); - - if (!ksp->phyiface_req) { - dev_err(ksp->dev, - "cannot claim switch register space\n"); - ret = -EIO; - goto failure; - } - - ksp->phyiface_regs = ioremap(phyiface_res->start, - resource_size(phyiface_res)); - - if (!ksp->phyiface_regs) { - dev_err(ksp->dev, - "failed to ioremap switch registers\n"); - ret = -EINVAL; - goto failure; - } - } - - ksp->rx_irq = rxirq_res->start; - ksp->rx_irq_name = rxirq_res->name ? rxirq_res->name : "Ethernet RX"; - ksp->tx_irq = txirq_res->start; - ksp->tx_irq_name = txirq_res->name ? txirq_res->name : "Ethernet TX"; - ksp->link_irq = (linkirq_res ? linkirq_res->start : -1); - ksp->link_irq_name = (linkirq_res && linkirq_res->name) ? - linkirq_res->name : "Ethernet Link"; - - /* driver system setup */ - ndev->netdev_ops = &ks8695_netdev_ops; - ndev->watchdog_timeo = msecs_to_jiffies(watchdog); - - netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT); - - /* Retrieve the default MAC addr from the chip. */ - /* The bootloader should have left it in there for us. */ - - machigh = ks8695_readreg(ksp, KS8695_MAH); - maclow = ks8695_readreg(ksp, KS8695_MAL); - - ndev->dev_addr[0] = (machigh >> 8) & 0xFF; - ndev->dev_addr[1] = machigh & 0xFF; - ndev->dev_addr[2] = (maclow >> 24) & 0xFF; - ndev->dev_addr[3] = (maclow >> 16) & 0xFF; - ndev->dev_addr[4] = (maclow >> 8) & 0xFF; - ndev->dev_addr[5] = maclow & 0xFF; - - if (!is_valid_ether_addr(ndev->dev_addr)) - dev_warn(ksp->dev, "%s: Invalid ethernet MAC address. Please " - "set using ifconfig\n", ndev->name); - - /* In order to be efficient memory-wise, we allocate both - * rings in one go. - */ - ksp->ring_base = dma_alloc_coherent(&pdev->dev, RING_DMA_SIZE, - &ksp->ring_base_dma, GFP_KERNEL); - if (!ksp->ring_base) { - ret = -ENOMEM; - goto failure; - } - - /* Specify the TX DMA ring buffer */ - ksp->tx_ring = ksp->ring_base; - ksp->tx_ring_dma = ksp->ring_base_dma; - - /* And initialise the queue's lock */ - spin_lock_init(&ksp->txq_lock); - spin_lock_init(&ksp->rx_lock); - - /* Specify the RX DMA ring buffer */ - ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE; - ksp->rx_ring_dma = ksp->ring_base_dma + TX_RING_DMA_SIZE; - - /* Zero the descriptor rings */ - memset(ksp->tx_ring, 0, TX_RING_DMA_SIZE); - memset(ksp->rx_ring, 0, RX_RING_DMA_SIZE); - - /* Build the rings */ - for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { - ksp->tx_ring[buff_n].next_desc = - cpu_to_le32(ksp->tx_ring_dma + - (sizeof(struct tx_ring_desc) * - ((buff_n + 1) & MAX_TX_DESC_MASK))); - } - - for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { - ksp->rx_ring[buff_n].next_desc = - cpu_to_le32(ksp->rx_ring_dma + - (sizeof(struct rx_ring_desc) * - ((buff_n + 1) & MAX_RX_DESC_MASK))); - } - - /* Initialise the port (physically) */ - if (ksp->phyiface_regs && ksp->link_irq == -1) { - ks8695_init_switch(ksp); - ksp->dtype = KS8695_DTYPE_LAN; - SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops); - } else if (ksp->phyiface_regs && ksp->link_irq != -1) { - ks8695_init_wan_phy(ksp); - ksp->dtype = KS8695_DTYPE_WAN; - SET_ETHTOOL_OPS(ndev, &ks8695_wan_ethtool_ops); - } else { - /* No initialisation since HPNA does not have a PHY */ - ksp->dtype = KS8695_DTYPE_HPNA; - SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops); - } - - /* And bring up the net_device with the net core */ - platform_set_drvdata(pdev, ndev); - ret = register_netdev(ndev); - - if (ret == 0) { - dev_info(ksp->dev, "ks8695 ethernet (%s) MAC: %pM\n", - ks8695_port_type(ksp), ndev->dev_addr); - } else { - /* Report the failure to register the net_device */ - dev_err(ksp->dev, "ks8695net: failed to register netdev.\n"); - goto failure; - } - - /* All is well */ - return 0; - - /* Error exit path */ -failure: - ks8695_release_device(ksp); - free_netdev(ndev); - - return ret; -} - -/** - * ks8695_drv_suspend - Suspend a KS8695 ethernet platform device. - * @pdev: The device to suspend - * @state: The suspend state - * - * This routine detaches and shuts down a KS8695 ethernet device. - */ -static int -ks8695_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct ks8695_priv *ksp = netdev_priv(ndev); - - ksp->in_suspend = 1; - - if (netif_running(ndev)) { - netif_device_detach(ndev); - ks8695_shutdown(ksp); - } - - return 0; -} - -/** - * ks8695_drv_resume - Resume a KS8695 ethernet platform device. - * @pdev: The device to resume - * - * This routine re-initialises and re-attaches a KS8695 ethernet - * device. - */ -static int -ks8695_drv_resume(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct ks8695_priv *ksp = netdev_priv(ndev); - - if (netif_running(ndev)) { - ks8695_reset(ksp); - ks8695_init_net(ksp); - ks8695_set_multicast(ndev); - netif_device_attach(ndev); - } - - ksp->in_suspend = 0; - - return 0; -} - -/** - * ks8695_drv_remove - Remove a KS8695 net device on driver unload. - * @pdev: The platform device to remove - * - * This unregisters and releases a KS8695 ethernet device. - */ -static int __devexit -ks8695_drv_remove(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct ks8695_priv *ksp = netdev_priv(ndev); - - platform_set_drvdata(pdev, NULL); - netif_napi_del(&ksp->napi); - - unregister_netdev(ndev); - ks8695_release_device(ksp); - free_netdev(ndev); - - dev_dbg(&pdev->dev, "released and freed device\n"); - return 0; -} - -static struct platform_driver ks8695_driver = { - .driver = { - .name = MODULENAME, - .owner = THIS_MODULE, - }, - .probe = ks8695_probe, - .remove = __devexit_p(ks8695_drv_remove), - .suspend = ks8695_drv_suspend, - .resume = ks8695_drv_resume, -}; - -/* Module interface */ - -static int __init -ks8695_init(void) -{ - printk(KERN_INFO "%s Ethernet driver, V%s\n", - MODULENAME, MODULEVERSION); - - return platform_driver_register(&ks8695_driver); -} - -static void __exit -ks8695_cleanup(void) -{ - platform_driver_unregister(&ks8695_driver); -} - -module_init(ks8695_init); -module_exit(ks8695_cleanup); - -MODULE_AUTHOR("Simtec Electronics"); -MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" MODULENAME); - -module_param(watchdog, int, 0400); -MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); diff --git a/drivers/net/arm/ks8695net.h b/drivers/net/arm/ks8695net.h deleted file mode 100644 index 80eff6ea516..00000000000 --- a/drivers/net/arm/ks8695net.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Micrel KS8695 (Centaur) Ethernet. - * - * Copyright 2008 Simtec Electronics - * Daniel Silverstone <dsilvers@simtec.co.uk> - * Vincent Sanders <vince@simtec.co.uk> - */ - -#ifndef KS8695NET_H -#define KS8695NET_H - -/* Receive descriptor flags */ -#define RDES_OWN (1 << 31) /* Ownership */ -#define RDES_FS (1 << 30) /* First Descriptor */ -#define RDES_LS (1 << 29) /* Last Descriptor */ -#define RDES_IPE (1 << 28) /* IP Checksum error */ -#define RDES_TCPE (1 << 27) /* TCP Checksum error */ -#define RDES_UDPE (1 << 26) /* UDP Checksum error */ -#define RDES_ES (1 << 25) /* Error summary */ -#define RDES_MF (1 << 24) /* Multicast Frame */ -#define RDES_RE (1 << 19) /* MII Error reported */ -#define RDES_TL (1 << 18) /* Frame too Long */ -#define RDES_RF (1 << 17) /* Runt Frame */ -#define RDES_CE (1 << 16) /* CRC error */ -#define RDES_FT (1 << 15) /* Frame Type */ -#define RDES_FLEN (0x7ff) /* Frame Length */ - -#define RDES_RER (1 << 25) /* Receive End of Ring */ -#define RDES_RBS (0x7ff) /* Receive Buffer Size */ - -/* Transmit descriptor flags */ - -#define TDES_OWN (1 << 31) /* Ownership */ - -#define TDES_IC (1 << 31) /* Interrupt on Completion */ -#define TDES_FS (1 << 30) /* First Segment */ -#define TDES_LS (1 << 29) /* Last Segment */ -#define TDES_IPCKG (1 << 28) /* IP Checksum generate */ -#define TDES_TCPCKG (1 << 27) /* TCP Checksum generate */ -#define TDES_UDPCKG (1 << 26) /* UDP Checksum generate */ -#define TDES_TER (1 << 25) /* Transmit End of Ring */ -#define TDES_TBS (0x7ff) /* Transmit Buffer Size */ - -/* - * Network controller register offsets - */ -#define KS8695_DTXC (0x00) /* DMA Transmit Control */ -#define KS8695_DRXC (0x04) /* DMA Receive Control */ -#define KS8695_DTSC (0x08) /* DMA Transmit Start Command */ -#define KS8695_DRSC (0x0c) /* DMA Receive Start Command */ -#define KS8695_TDLB (0x10) /* Transmit Descriptor List - * Base Address - */ -#define KS8695_RDLB (0x14) /* Receive Descriptor List - * Base Address - */ -#define KS8695_MAL (0x18) /* MAC Station Address Low */ -#define KS8695_MAH (0x1c) /* MAC Station Address High */ -#define KS8695_AAL_(n) (0x80 + ((n)*8)) /* MAC Additional - * Station Address - * (0..15) Low - */ -#define KS8695_AAH_(n) (0x84 + ((n)*8)) /* MAC Additional - * Station Address - * (0..15) High - */ - - -/* DMA Transmit Control Register */ -#define DTXC_TRST (1 << 31) /* Soft Reset */ -#define DTXC_TBS (0x3f << 24) /* Transmit Burst Size */ -#define DTXC_TUCG (1 << 18) /* Transmit UDP - * Checksum Generate - */ -#define DTXC_TTCG (1 << 17) /* Transmit TCP - * Checksum Generate - */ -#define DTXC_TICG (1 << 16) /* Transmit IP - * Checksum Generate - */ -#define DTXC_TFCE (1 << 9) /* Transmit Flow - * Control Enable - */ -#define DTXC_TLB (1 << 8) /* Loopback mode */ -#define DTXC_TEP (1 << 2) /* Transmit Enable Padding */ -#define DTXC_TAC (1 << 1) /* Transmit Add CRC */ -#define DTXC_TE (1 << 0) /* TX Enable */ - -/* DMA Receive Control Register */ -#define DRXC_RBS (0x3f << 24) /* Receive Burst Size */ -#define DRXC_RUCC (1 << 18) /* Receive UDP Checksum check */ -#define DRXC_RTCG (1 << 17) /* Receive TCP Checksum check */ -#define DRXC_RICG (1 << 16) /* Receive IP Checksum check */ -#define DRXC_RFCE (1 << 9) /* Receive Flow Control - * Enable - */ -#define DRXC_RB (1 << 6) /* Receive Broadcast */ -#define DRXC_RM (1 << 5) /* Receive Multicast */ -#define DRXC_RU (1 << 4) /* Receive Unicast */ -#define DRXC_RERR (1 << 3) /* Receive Error Frame */ -#define DRXC_RA (1 << 2) /* Receive All */ -#define DRXC_RE (1 << 0) /* RX Enable */ - -/* Additional Station Address High */ -#define AAH_E (1 << 31) /* Address Enabled */ - -#endif /* KS8695NET_H */ diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c deleted file mode 100644 index bfea499a351..00000000000 --- a/drivers/net/arm/w90p910_ether.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * Copyright (c) 2008-2009 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - * - * 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;version 2 of the License. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mii.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/ethtool.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/gfp.h> - -#define DRV_MODULE_NAME "w90p910-emc" -#define DRV_MODULE_VERSION "0.1" - -/* Ethernet MAC Registers */ -#define REG_CAMCMR 0x00 -#define REG_CAMEN 0x04 -#define REG_CAMM_BASE 0x08 -#define REG_CAML_BASE 0x0c -#define REG_TXDLSA 0x88 -#define REG_RXDLSA 0x8C -#define REG_MCMDR 0x90 -#define REG_MIID 0x94 -#define REG_MIIDA 0x98 -#define REG_FFTCR 0x9C -#define REG_TSDR 0xa0 -#define REG_RSDR 0xa4 -#define REG_DMARFC 0xa8 -#define REG_MIEN 0xac -#define REG_MISTA 0xb0 -#define REG_CTXDSA 0xcc -#define REG_CTXBSA 0xd0 -#define REG_CRXDSA 0xd4 -#define REG_CRXBSA 0xd8 - -/* mac controller bit */ -#define MCMDR_RXON 0x01 -#define MCMDR_ACP (0x01 << 3) -#define MCMDR_SPCRC (0x01 << 5) -#define MCMDR_TXON (0x01 << 8) -#define MCMDR_FDUP (0x01 << 18) -#define MCMDR_ENMDC (0x01 << 19) -#define MCMDR_OPMOD (0x01 << 20) -#define SWR (0x01 << 24) - -/* cam command regiser */ -#define CAMCMR_AUP 0x01 -#define CAMCMR_AMP (0x01 << 1) -#define CAMCMR_ABP (0x01 << 2) -#define CAMCMR_CCAM (0x01 << 3) -#define CAMCMR_ECMP (0x01 << 4) -#define CAM0EN 0x01 - -/* mac mii controller bit */ -#define MDCCR (0x0a << 20) -#define PHYAD (0x01 << 8) -#define PHYWR (0x01 << 16) -#define PHYBUSY (0x01 << 17) -#define PHYPRESP (0x01 << 18) -#define CAM_ENTRY_SIZE 0x08 - -/* rx and tx status */ -#define TXDS_TXCP (0x01 << 19) -#define RXDS_CRCE (0x01 << 17) -#define RXDS_PTLE (0x01 << 19) -#define RXDS_RXGD (0x01 << 20) -#define RXDS_ALIE (0x01 << 21) -#define RXDS_RP (0x01 << 22) - -/* mac interrupt status*/ -#define MISTA_EXDEF (0x01 << 19) -#define MISTA_TXBERR (0x01 << 24) -#define MISTA_TDU (0x01 << 23) -#define MISTA_RDU (0x01 << 10) -#define MISTA_RXBERR (0x01 << 11) - -#define ENSTART 0x01 -#define ENRXINTR 0x01 -#define ENRXGD (0x01 << 4) -#define ENRXBERR (0x01 << 11) -#define ENTXINTR (0x01 << 16) -#define ENTXCP (0x01 << 18) -#define ENTXABT (0x01 << 21) -#define ENTXBERR (0x01 << 24) -#define ENMDC (0x01 << 19) -#define PHYBUSY (0x01 << 17) -#define MDCCR_VAL 0xa00000 - -/* rx and tx owner bit */ -#define RX_OWEN_DMA (0x01 << 31) -#define RX_OWEN_CPU (~(0x03 << 30)) -#define TX_OWEN_DMA (0x01 << 31) -#define TX_OWEN_CPU (~(0x01 << 31)) - -/* tx frame desc controller bit */ -#define MACTXINTEN 0x04 -#define CRCMODE 0x02 -#define PADDINGMODE 0x01 - -/* fftcr controller bit */ -#define TXTHD (0x03 << 8) -#define BLENGTH (0x01 << 20) - -/* global setting for driver */ -#define RX_DESC_SIZE 50 -#define TX_DESC_SIZE 10 -#define MAX_RBUFF_SZ 0x600 -#define MAX_TBUFF_SZ 0x600 -#define TX_TIMEOUT (HZ/2) -#define DELAY 1000 -#define CAM0 0x0 - -static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg); - -struct w90p910_rxbd { - unsigned int sl; - unsigned int buffer; - unsigned int reserved; - unsigned int next; -}; - -struct w90p910_txbd { - unsigned int mode; - unsigned int buffer; - unsigned int sl; - unsigned int next; -}; - -struct recv_pdesc { - struct w90p910_rxbd desclist[RX_DESC_SIZE]; - char recv_buf[RX_DESC_SIZE][MAX_RBUFF_SZ]; -}; - -struct tran_pdesc { - struct w90p910_txbd desclist[TX_DESC_SIZE]; - char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ]; -}; - -struct w90p910_ether { - struct recv_pdesc *rdesc; - struct tran_pdesc *tdesc; - dma_addr_t rdesc_phys; - dma_addr_t tdesc_phys; - struct net_device_stats stats; - struct platform_device *pdev; - struct resource *res; - struct sk_buff *skb; - struct clk *clk; - struct clk *rmiiclk; - struct mii_if_info mii; - struct timer_list check_timer; - void __iomem *reg; - int rxirq; - int txirq; - unsigned int cur_tx; - unsigned int cur_rx; - unsigned int finish_tx; - unsigned int rx_packets; - unsigned int rx_bytes; - unsigned int start_tx_ptr; - unsigned int start_rx_ptr; - unsigned int linkflag; -}; - -static void update_linkspeed_register(struct net_device *dev, - unsigned int speed, unsigned int duplex) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = __raw_readl(ether->reg + REG_MCMDR); - - if (speed == SPEED_100) { - /* 100 full/half duplex */ - if (duplex == DUPLEX_FULL) { - val |= (MCMDR_OPMOD | MCMDR_FDUP); - } else { - val |= MCMDR_OPMOD; - val &= ~MCMDR_FDUP; - } - } else { - /* 10 full/half duplex */ - if (duplex == DUPLEX_FULL) { - val |= MCMDR_FDUP; - val &= ~MCMDR_OPMOD; - } else { - val &= ~(MCMDR_FDUP | MCMDR_OPMOD); - } - } - - __raw_writel(val, ether->reg + REG_MCMDR); -} - -static void update_linkspeed(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - struct platform_device *pdev; - unsigned int bmsr, bmcr, lpa, speed, duplex; - - pdev = ether->pdev; - - if (!mii_link_ok(ðer->mii)) { - ether->linkflag = 0x0; - netif_carrier_off(dev); - dev_warn(&pdev->dev, "%s: Link down.\n", dev->name); - return; - } - - if (ether->linkflag == 1) - return; - - bmsr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMSR); - bmcr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMCR); - - if (bmcr & BMCR_ANENABLE) { - if (!(bmsr & BMSR_ANEGCOMPLETE)) - return; - - lpa = w90p910_mdio_read(dev, ether->mii.phy_id, MII_LPA); - - if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) - speed = SPEED_100; - else - speed = SPEED_10; - - if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) - duplex = DUPLEX_FULL; - else - duplex = DUPLEX_HALF; - - } else { - speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; - duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; - } - - update_linkspeed_register(dev, speed, duplex); - - dev_info(&pdev->dev, "%s: Link now %i-%s\n", dev->name, speed, - (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); - ether->linkflag = 0x01; - - netif_carrier_on(dev); -} - -static void w90p910_check_link(unsigned long dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct w90p910_ether *ether = netdev_priv(dev); - - update_linkspeed(dev); - mod_timer(ðer->check_timer, jiffies + msecs_to_jiffies(1000)); -} - -static void w90p910_write_cam(struct net_device *dev, - unsigned int x, unsigned char *pval) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int msw, lsw; - - msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3]; - - lsw = (pval[4] << 24) | (pval[5] << 16); - - __raw_writel(lsw, ether->reg + REG_CAML_BASE + x * CAM_ENTRY_SIZE); - __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE); -} - -static int w90p910_init_desc(struct net_device *dev) -{ - struct w90p910_ether *ether; - struct w90p910_txbd *tdesc; - struct w90p910_rxbd *rdesc; - struct platform_device *pdev; - unsigned int i; - - ether = netdev_priv(dev); - pdev = ether->pdev; - - ether->tdesc = (struct tran_pdesc *) - dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc), - ðer->tdesc_phys, GFP_KERNEL); - - if (!ether->tdesc) { - dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n"); - return -ENOMEM; - } - - ether->rdesc = (struct recv_pdesc *) - dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc), - ðer->rdesc_phys, GFP_KERNEL); - - if (!ether->rdesc) { - dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n"); - dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), - ether->tdesc, ether->tdesc_phys); - return -ENOMEM; - } - - for (i = 0; i < TX_DESC_SIZE; i++) { - unsigned int offset; - - tdesc = &(ether->tdesc->desclist[i]); - - if (i == TX_DESC_SIZE - 1) - offset = offsetof(struct tran_pdesc, desclist[0]); - else - offset = offsetof(struct tran_pdesc, desclist[i + 1]); - - tdesc->next = ether->tdesc_phys + offset; - tdesc->buffer = ether->tdesc_phys + - offsetof(struct tran_pdesc, tran_buf[i]); - tdesc->sl = 0; - tdesc->mode = 0; - } - - ether->start_tx_ptr = ether->tdesc_phys; - - for (i = 0; i < RX_DESC_SIZE; i++) { - unsigned int offset; - - rdesc = &(ether->rdesc->desclist[i]); - - if (i == RX_DESC_SIZE - 1) - offset = offsetof(struct recv_pdesc, desclist[0]); - else - offset = offsetof(struct recv_pdesc, desclist[i + 1]); - - rdesc->next = ether->rdesc_phys + offset; - rdesc->sl = RX_OWEN_DMA; - rdesc->buffer = ether->rdesc_phys + - offsetof(struct recv_pdesc, recv_buf[i]); - } - - ether->start_rx_ptr = ether->rdesc_phys; - - return 0; -} - -static void w90p910_set_fifo_threshold(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = TXTHD | BLENGTH; - __raw_writel(val, ether->reg + REG_FFTCR); -} - -static void w90p910_return_default_idle(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = __raw_readl(ether->reg + REG_MCMDR); - val |= SWR; - __raw_writel(val, ether->reg + REG_MCMDR); -} - -static void w90p910_trigger_rx(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - __raw_writel(ENSTART, ether->reg + REG_RSDR); -} - -static void w90p910_trigger_tx(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - __raw_writel(ENSTART, ether->reg + REG_TSDR); -} - -static void w90p910_enable_mac_interrupt(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP; - val |= ENTXBERR | ENRXBERR | ENTXABT; - - __raw_writel(val, ether->reg + REG_MIEN); -} - -static void w90p910_get_and_clear_int(struct net_device *dev, - unsigned int *val) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - *val = __raw_readl(ether->reg + REG_MISTA); - __raw_writel(*val, ether->reg + REG_MISTA); -} - -static void w90p910_set_global_maccmd(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = __raw_readl(ether->reg + REG_MCMDR); - val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | ENMDC; - __raw_writel(val, ether->reg + REG_MCMDR); -} - -static void w90p910_enable_cam(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - w90p910_write_cam(dev, CAM0, dev->dev_addr); - - val = __raw_readl(ether->reg + REG_CAMEN); - val |= CAM0EN; - __raw_writel(val, ether->reg + REG_CAMEN); -} - -static void w90p910_enable_cam_command(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AMP; - __raw_writel(val, ether->reg + REG_CAMCMR); -} - -static void w90p910_enable_tx(struct net_device *dev, unsigned int enable) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = __raw_readl(ether->reg + REG_MCMDR); - - if (enable) - val |= MCMDR_TXON; - else - val &= ~MCMDR_TXON; - - __raw_writel(val, ether->reg + REG_MCMDR); -} - -static void w90p910_enable_rx(struct net_device *dev, unsigned int enable) -{ - struct w90p910_ether *ether = netdev_priv(dev); - unsigned int val; - - val = __raw_readl(ether->reg + REG_MCMDR); - - if (enable) - val |= MCMDR_RXON; - else - val &= ~MCMDR_RXON; - - __raw_writel(val, ether->reg + REG_MCMDR); -} - -static void w90p910_set_curdest(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - __raw_writel(ether->start_rx_ptr, ether->reg + REG_RXDLSA); - __raw_writel(ether->start_tx_ptr, ether->reg + REG_TXDLSA); -} - -static void w90p910_reset_mac(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - w90p910_enable_tx(dev, 0); - w90p910_enable_rx(dev, 0); - w90p910_set_fifo_threshold(dev); - w90p910_return_default_idle(dev); - - if (!netif_queue_stopped(dev)) - netif_stop_queue(dev); - - w90p910_init_desc(dev); - - dev->trans_start = jiffies; /* prevent tx timeout */ - ether->cur_tx = 0x0; - ether->finish_tx = 0x0; - ether->cur_rx = 0x0; - - w90p910_set_curdest(dev); - w90p910_enable_cam(dev); - w90p910_enable_cam_command(dev); - w90p910_enable_mac_interrupt(dev); - w90p910_enable_tx(dev, 1); - w90p910_enable_rx(dev, 1); - w90p910_trigger_tx(dev); - w90p910_trigger_rx(dev); - - dev->trans_start = jiffies; /* prevent tx timeout */ - - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -static void w90p910_mdio_write(struct net_device *dev, - int phy_id, int reg, int data) -{ - struct w90p910_ether *ether = netdev_priv(dev); - struct platform_device *pdev; - unsigned int val, i; - - pdev = ether->pdev; - - __raw_writel(data, ether->reg + REG_MIID); - - val = (phy_id << 0x08) | reg; - val |= PHYBUSY | PHYWR | MDCCR_VAL; - __raw_writel(val, ether->reg + REG_MIIDA); - - for (i = 0; i < DELAY; i++) { - if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0) - break; - } - - if (i == DELAY) - dev_warn(&pdev->dev, "mdio write timed out\n"); -} - -static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg) -{ - struct w90p910_ether *ether = netdev_priv(dev); - struct platform_device *pdev; - unsigned int val, i, data; - - pdev = ether->pdev; - - val = (phy_id << 0x08) | reg; - val |= PHYBUSY | MDCCR_VAL; - __raw_writel(val, ether->reg + REG_MIIDA); - - for (i = 0; i < DELAY; i++) { - if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0) - break; - } - - if (i == DELAY) { - dev_warn(&pdev->dev, "mdio read timed out\n"); - data = 0xffff; - } else { - data = __raw_readl(ether->reg + REG_MIID); - } - - return data; -} - -static int w90p910_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *address = addr; - - if (!is_valid_ether_addr(address->sa_data)) - return -EADDRNOTAVAIL; - - memcpy(dev->dev_addr, address->sa_data, dev->addr_len); - w90p910_write_cam(dev, CAM0, dev->dev_addr); - - return 0; -} - -static int w90p910_ether_close(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - struct platform_device *pdev; - - pdev = ether->pdev; - - dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc), - ether->rdesc, ether->rdesc_phys); - dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc), - ether->tdesc, ether->tdesc_phys); - - netif_stop_queue(dev); - - del_timer_sync(ðer->check_timer); - clk_disable(ether->rmiiclk); - clk_disable(ether->clk); - - free_irq(ether->txirq, dev); - free_irq(ether->rxirq, dev); - - return 0; -} - -static struct net_device_stats *w90p910_ether_stats(struct net_device *dev) -{ - struct w90p910_ether *ether; - - ether = netdev_priv(dev); - - return ðer->stats; -} - -static int w90p910_send_frame(struct net_device *dev, - unsigned char *data, int length) -{ - struct w90p910_ether *ether; - struct w90p910_txbd *txbd; - struct platform_device *pdev; - unsigned char *buffer; - - ether = netdev_priv(dev); - pdev = ether->pdev; - - txbd = ðer->tdesc->desclist[ether->cur_tx]; - buffer = ether->tdesc->tran_buf[ether->cur_tx]; - - if (length > 1514) { - dev_err(&pdev->dev, "send data %d bytes, check it\n", length); - length = 1514; - } - - txbd->sl = length & 0xFFFF; - - memcpy(buffer, data, length); - - txbd->mode = TX_OWEN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN; - - w90p910_enable_tx(dev, 1); - - w90p910_trigger_tx(dev); - - if (++ether->cur_tx >= TX_DESC_SIZE) - ether->cur_tx = 0; - - txbd = ðer->tdesc->desclist[ether->cur_tx]; - - if (txbd->mode & TX_OWEN_DMA) - netif_stop_queue(dev); - - return 0; -} - -static int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - if (!(w90p910_send_frame(dev, skb->data, skb->len))) { - ether->skb = skb; - dev_kfree_skb_irq(skb); - return 0; - } - return -EAGAIN; -} - -static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id) -{ - struct w90p910_ether *ether; - struct w90p910_txbd *txbd; - struct platform_device *pdev; - struct net_device *dev; - unsigned int cur_entry, entry, status; - - dev = dev_id; - ether = netdev_priv(dev); - pdev = ether->pdev; - - w90p910_get_and_clear_int(dev, &status); - - cur_entry = __raw_readl(ether->reg + REG_CTXDSA); - - entry = ether->tdesc_phys + - offsetof(struct tran_pdesc, desclist[ether->finish_tx]); - - while (entry != cur_entry) { - txbd = ðer->tdesc->desclist[ether->finish_tx]; - - if (++ether->finish_tx >= TX_DESC_SIZE) - ether->finish_tx = 0; - - if (txbd->sl & TXDS_TXCP) { - ether->stats.tx_packets++; - ether->stats.tx_bytes += txbd->sl & 0xFFFF; - } else { - ether->stats.tx_errors++; - } - - txbd->sl = 0x0; - txbd->mode = 0x0; - - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - - entry = ether->tdesc_phys + - offsetof(struct tran_pdesc, desclist[ether->finish_tx]); - } - - if (status & MISTA_EXDEF) { - dev_err(&pdev->dev, "emc defer exceed interrupt\n"); - } else if (status & MISTA_TXBERR) { - dev_err(&pdev->dev, "emc bus error interrupt\n"); - w90p910_reset_mac(dev); - } else if (status & MISTA_TDU) { - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } - - return IRQ_HANDLED; -} - -static void netdev_rx(struct net_device *dev) -{ - struct w90p910_ether *ether; - struct w90p910_rxbd *rxbd; - struct platform_device *pdev; - struct sk_buff *skb; - unsigned char *data; - unsigned int length, status, val, entry; - - ether = netdev_priv(dev); - pdev = ether->pdev; - - rxbd = ðer->rdesc->desclist[ether->cur_rx]; - - do { - val = __raw_readl(ether->reg + REG_CRXDSA); - - entry = ether->rdesc_phys + - offsetof(struct recv_pdesc, desclist[ether->cur_rx]); - - if (val == entry) - break; - - status = rxbd->sl; - length = status & 0xFFFF; - - if (status & RXDS_RXGD) { - data = ether->rdesc->recv_buf[ether->cur_rx]; - skb = dev_alloc_skb(length+2); - if (!skb) { - dev_err(&pdev->dev, "get skb buffer error\n"); - ether->stats.rx_dropped++; - return; - } - - skb_reserve(skb, 2); - skb_put(skb, length); - skb_copy_to_linear_data(skb, data, length); - skb->protocol = eth_type_trans(skb, dev); - ether->stats.rx_packets++; - ether->stats.rx_bytes += length; - netif_rx(skb); - } else { - ether->stats.rx_errors++; - - if (status & RXDS_RP) { - dev_err(&pdev->dev, "rx runt err\n"); - ether->stats.rx_length_errors++; - } else if (status & RXDS_CRCE) { - dev_err(&pdev->dev, "rx crc err\n"); - ether->stats.rx_crc_errors++; - } else if (status & RXDS_ALIE) { - dev_err(&pdev->dev, "rx aligment err\n"); - ether->stats.rx_frame_errors++; - } else if (status & RXDS_PTLE) { - dev_err(&pdev->dev, "rx longer err\n"); - ether->stats.rx_over_errors++; - } - } - - rxbd->sl = RX_OWEN_DMA; - rxbd->reserved = 0x0; - - if (++ether->cur_rx >= RX_DESC_SIZE) - ether->cur_rx = 0; - - rxbd = ðer->rdesc->desclist[ether->cur_rx]; - - } while (1); -} - -static irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id) -{ - struct net_device *dev; - struct w90p910_ether *ether; - struct platform_device *pdev; - unsigned int status; - - dev = dev_id; - ether = netdev_priv(dev); - pdev = ether->pdev; - - w90p910_get_and_clear_int(dev, &status); - - if (status & MISTA_RDU) { - netdev_rx(dev); - w90p910_trigger_rx(dev); - - return IRQ_HANDLED; - } else if (status & MISTA_RXBERR) { - dev_err(&pdev->dev, "emc rx bus error\n"); - w90p910_reset_mac(dev); - } - - netdev_rx(dev); - return IRQ_HANDLED; -} - -static int w90p910_ether_open(struct net_device *dev) -{ - struct w90p910_ether *ether; - struct platform_device *pdev; - - ether = netdev_priv(dev); - pdev = ether->pdev; - - w90p910_reset_mac(dev); - w90p910_set_fifo_threshold(dev); - w90p910_set_curdest(dev); - w90p910_enable_cam(dev); - w90p910_enable_cam_command(dev); - w90p910_enable_mac_interrupt(dev); - w90p910_set_global_maccmd(dev); - w90p910_enable_rx(dev, 1); - - clk_enable(ether->rmiiclk); - clk_enable(ether->clk); - - ether->rx_packets = 0x0; - ether->rx_bytes = 0x0; - - if (request_irq(ether->txirq, w90p910_tx_interrupt, - 0x0, pdev->name, dev)) { - dev_err(&pdev->dev, "register irq tx failed\n"); - return -EAGAIN; - } - - if (request_irq(ether->rxirq, w90p910_rx_interrupt, - 0x0, pdev->name, dev)) { - dev_err(&pdev->dev, "register irq rx failed\n"); - free_irq(ether->txirq, dev); - return -EAGAIN; - } - - mod_timer(ðer->check_timer, jiffies + msecs_to_jiffies(1000)); - netif_start_queue(dev); - w90p910_trigger_rx(dev); - - dev_info(&pdev->dev, "%s is OPENED\n", dev->name); - - return 0; -} - -static void w90p910_ether_set_multicast_list(struct net_device *dev) -{ - struct w90p910_ether *ether; - unsigned int rx_mode; - - ether = netdev_priv(dev); - - if (dev->flags & IFF_PROMISC) - rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP; - else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) - rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP; - else - rx_mode = CAMCMR_ECMP | CAMCMR_ABP; - __raw_writel(rx_mode, ether->reg + REG_CAMCMR); -} - -static int w90p910_ether_ioctl(struct net_device *dev, - struct ifreq *ifr, int cmd) -{ - struct w90p910_ether *ether = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(ifr); - - return generic_mii_ioctl(ðer->mii, data, cmd, NULL); -} - -static void w90p910_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_MODULE_NAME); - strcpy(info->version, DRV_MODULE_VERSION); -} - -static int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct w90p910_ether *ether = netdev_priv(dev); - return mii_ethtool_gset(ðer->mii, cmd); -} - -static int w90p910_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct w90p910_ether *ether = netdev_priv(dev); - return mii_ethtool_sset(ðer->mii, cmd); -} - -static int w90p910_nway_reset(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - return mii_nway_restart(ðer->mii); -} - -static u32 w90p910_get_link(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - return mii_link_ok(ðer->mii); -} - -static const struct ethtool_ops w90p910_ether_ethtool_ops = { - .get_settings = w90p910_get_settings, - .set_settings = w90p910_set_settings, - .get_drvinfo = w90p910_get_drvinfo, - .nway_reset = w90p910_nway_reset, - .get_link = w90p910_get_link, -}; - -static const struct net_device_ops w90p910_ether_netdev_ops = { - .ndo_open = w90p910_ether_open, - .ndo_stop = w90p910_ether_close, - .ndo_start_xmit = w90p910_ether_start_xmit, - .ndo_get_stats = w90p910_ether_stats, - .ndo_set_multicast_list = w90p910_ether_set_multicast_list, - .ndo_set_mac_address = w90p910_set_mac_address, - .ndo_do_ioctl = w90p910_ether_ioctl, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, -}; - -static void __init get_mac_address(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - struct platform_device *pdev; - char addr[6]; - - pdev = ether->pdev; - - addr[0] = 0x00; - addr[1] = 0x02; - addr[2] = 0xac; - addr[3] = 0x55; - addr[4] = 0x88; - addr[5] = 0xa8; - - if (is_valid_ether_addr(addr)) - memcpy(dev->dev_addr, &addr, 0x06); - else - dev_err(&pdev->dev, "invalid mac address\n"); -} - -static int w90p910_ether_setup(struct net_device *dev) -{ - struct w90p910_ether *ether = netdev_priv(dev); - - ether_setup(dev); - dev->netdev_ops = &w90p910_ether_netdev_ops; - dev->ethtool_ops = &w90p910_ether_ethtool_ops; - - dev->tx_queue_len = 16; - dev->dma = 0x0; - dev->watchdog_timeo = TX_TIMEOUT; - - get_mac_address(dev); - - ether->cur_tx = 0x0; - ether->cur_rx = 0x0; - ether->finish_tx = 0x0; - ether->linkflag = 0x0; - ether->mii.phy_id = 0x01; - ether->mii.phy_id_mask = 0x1f; - ether->mii.reg_num_mask = 0x1f; - ether->mii.dev = dev; - ether->mii.mdio_read = w90p910_mdio_read; - ether->mii.mdio_write = w90p910_mdio_write; - - setup_timer(ðer->check_timer, w90p910_check_link, - (unsigned long)dev); - - return 0; -} - -static int __devinit w90p910_ether_probe(struct platform_device *pdev) -{ - struct w90p910_ether *ether; - struct net_device *dev; - int error; - - dev = alloc_etherdev(sizeof(struct w90p910_ether)); - if (!dev) - return -ENOMEM; - - ether = netdev_priv(dev); - - ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (ether->res == NULL) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - error = -ENXIO; - goto failed_free; - } - - if (!request_mem_region(ether->res->start, - resource_size(ether->res), pdev->name)) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto failed_free; - } - - ether->reg = ioremap(ether->res->start, resource_size(ether->res)); - if (ether->reg == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENXIO; - goto failed_free_mem; - } - - ether->txirq = platform_get_irq(pdev, 0); - if (ether->txirq < 0) { - dev_err(&pdev->dev, "failed to get ether tx irq\n"); - error = -ENXIO; - goto failed_free_io; - } - - ether->rxirq = platform_get_irq(pdev, 1); - if (ether->rxirq < 0) { - dev_err(&pdev->dev, "failed to get ether rx irq\n"); - error = -ENXIO; - goto failed_free_txirq; - } - - platform_set_drvdata(pdev, dev); - - ether->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(ether->clk)) { - dev_err(&pdev->dev, "failed to get ether clock\n"); - error = PTR_ERR(ether->clk); - goto failed_free_rxirq; - } - - ether->rmiiclk = clk_get(&pdev->dev, "RMII"); - if (IS_ERR(ether->rmiiclk)) { - dev_err(&pdev->dev, "failed to get ether clock\n"); - error = PTR_ERR(ether->rmiiclk); - goto failed_put_clk; - } - - ether->pdev = pdev; - - w90p910_ether_setup(dev); - - error = register_netdev(dev); - if (error != 0) { - dev_err(&pdev->dev, "Regiter EMC w90p910 FAILED\n"); - error = -ENODEV; - goto failed_put_rmiiclk; - } - - return 0; -failed_put_rmiiclk: - clk_put(ether->rmiiclk); -failed_put_clk: - clk_put(ether->clk); -failed_free_rxirq: - free_irq(ether->rxirq, pdev); - platform_set_drvdata(pdev, NULL); -failed_free_txirq: - free_irq(ether->txirq, pdev); -failed_free_io: - iounmap(ether->reg); -failed_free_mem: - release_mem_region(ether->res->start, resource_size(ether->res)); -failed_free: - free_netdev(dev); - return error; -} - -static int __devexit w90p910_ether_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct w90p910_ether *ether = netdev_priv(dev); - - unregister_netdev(dev); - - clk_put(ether->rmiiclk); - clk_put(ether->clk); - - iounmap(ether->reg); - release_mem_region(ether->res->start, resource_size(ether->res)); - - free_irq(ether->txirq, dev); - free_irq(ether->rxirq, dev); - - del_timer_sync(ðer->check_timer); - platform_set_drvdata(pdev, NULL); - - free_netdev(dev); - return 0; -} - -static struct platform_driver w90p910_ether_driver = { - .probe = w90p910_ether_probe, - .remove = __devexit_p(w90p910_ether_remove), - .driver = { - .name = "nuc900-emc", - .owner = THIS_MODULE, - }, -}; - -static int __init w90p910_ether_init(void) -{ - return platform_driver_register(&w90p910_ether_driver); -} - -static void __exit w90p910_ether_exit(void) -{ - platform_driver_unregister(&w90p910_ether_driver); -} - -module_init(w90p910_ether_init); -module_exit(w90p910_ether_exit); - -MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("w90p910 MAC driver!"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-emc"); - |