diff options
-rw-r--r-- | drivers/net/Kconfig | 14 | ||||
-rw-r--r-- | drivers/net/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/a2065.c | 4 | ||||
-rw-r--r-- | drivers/net/atarilance.c | 2 | ||||
-rw-r--r-- | drivers/net/declance.c | 4 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 5 | ||||
-rw-r--r-- | drivers/net/hplance.c | 4 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 7 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 7 | ||||
-rw-r--r-- | drivers/net/lib8390.c | 4 | ||||
-rw-r--r-- | drivers/net/mac8390.c | 8 | ||||
-rw-r--r-- | drivers/net/macb.c | 6 | ||||
-rw-r--r-- | drivers/net/macsonic.c | 19 | ||||
-rw-r--r-- | drivers/net/sh_eth.c | 1174 | ||||
-rw-r--r-- | drivers/net/sh_eth.h | 464 | ||||
-rw-r--r-- | drivers/net/smc911x.c | 423 | ||||
-rw-r--r-- | drivers/net/smc911x.h | 495 | ||||
-rw-r--r-- | drivers/net/sunlance.c | 4 | ||||
-rw-r--r-- | drivers/net/usb/Kconfig | 10 | ||||
-rw-r--r-- | drivers/net/usb/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/usb/hso.c | 2836 | ||||
-rw-r--r-- | include/linux/smc911x.h | 12 |
22 files changed, 5017 insertions, 488 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c537f53ffcb..40eb24d6d75 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -524,6 +524,18 @@ config STNIC If unsure, say N. +config SH_ETH + tristate "Renesas SuperH Ethernet support" + depends on SUPERH && \ + (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712) + select CRC32 + select MII + select MDIO_BITBANG + select PHYLIB + help + Renesas SuperH Ethernet device driver. + This driver support SH7710 and SH7712. + config SUNLANCE tristate "Sun LANCE support" depends on SBUS @@ -955,7 +967,7 @@ config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 select MII - depends on ARCH_PXA || SH_MAGIC_PANEL_R2 + depends on ARCH_PXA || SUPERH help This is a driver for SMSC's LAN911x series of Ethernet chipsets including the new LAN9115, LAN9116, LAN9117, and LAN9118. diff --git a/drivers/net/Makefile b/drivers/net/Makefile index dcbfe842115..c96fe203680 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o obj-$(CONFIG_RIONET) += rionet.o +obj-$(CONFIG_SH_ETH) += sh_eth.o # # end link order section @@ -236,6 +237,7 @@ obj-$(CONFIG_USB_CATC) += usb/ obj-$(CONFIG_USB_KAWETH) += usb/ obj-$(CONFIG_USB_PEGASUS) += usb/ obj-$(CONFIG_USB_RTL8150) += usb/ +obj-$(CONFIG_USB_HSO) += usb/ obj-$(CONFIG_USB_USBNET) += usb/ obj-$(CONFIG_USB_ZD1201) += usb/ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 6c5719ae8cc..9c0837435b6 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -475,16 +475,12 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id) return IRQ_HANDLED; } -struct net_device *last_dev; - static int lance_open (struct net_device *dev) { struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int ret; - last_dev = dev; - /* Stop the Lance */ ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 4cceaac8863..0860cc280b0 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -243,7 +243,7 @@ struct lance_private { /* Possible memory/IO addresses for probing */ -struct lance_addr { +static struct lance_addr { unsigned long memaddr; unsigned long ioaddr; int slow_flag; diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 6b1e77cc069..3e3506411ac 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -773,8 +773,6 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -struct net_device *last_dev = 0; - static int lance_open(struct net_device *dev) { volatile u16 *ib = (volatile u16 *)dev->mem_start; @@ -782,8 +780,6 @@ static int lance_open(struct net_device *dev) volatile struct lance_regs *ll = lp->ll; int status = 0; - last_dev = dev; - /* Stop the Lance */ writereg(&ll->rap, LE_CSR0); writereg(&ll->rdp, LE_C0_STOP); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index cab1835173c..ccb8ca2cbb2 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4343,6 +4343,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index be6e5bc7c88..2e802634d36 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -220,12 +220,12 @@ static int hplance_close(struct net_device *dev) return 0; } -int __init hplance_init_module(void) +static int __init hplance_init_module(void) { return dio_register_driver(&hplance_driver); } -void __exit hplance_cleanup_module(void) +static void __exit hplance_cleanup_module(void) { dio_unregister_driver(&hplance_driver); } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index ae398f04c7b..7b6b780dc8a 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -967,8 +967,13 @@ static int __devinit igb_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_FILTER; netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 7b859220c25..0d37c9025be 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -3518,8 +3518,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_FILTER; netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; + + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; + netdev->vlan_features |= NETIF_F_HW_CSUM; + netdev->vlan_features |= NETIF_F_SG; + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index ed495275b57..00d59ab2f8a 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -553,6 +553,8 @@ static void __ei_poll(struct net_device *dev) static void ei_tx_err(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; + /* ei_local is used on some platforms via the EI_SHIFT macro */ + struct ei_device *ei_local __maybe_unused = netdev_priv(dev); unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -815,6 +817,8 @@ static void ei_rx_overrun(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; + /* ei_local is used on some platforms via the EI_SHIFT macro */ + struct ei_device *ei_local __maybe_unused = netdev_priv(dev); /* * Record whether a Tx was in progress and then issue the diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 9e700749bb3..98e3eb2697c 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -117,8 +117,6 @@ enum mac8390_access { ACCESS_16, }; -extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); -extern int mac8390_memsize(unsigned long membase); extern int mac8390_memtest(struct net_device * dev); static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type); @@ -163,7 +161,7 @@ static void slow_sane_block_output(struct net_device *dev, int count, static void word_memcpy_tocard(void *tp, const void *fp, int count); static void word_memcpy_fromcard(void *tp, const void *fp, int count); -enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) +static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev) { switch (dev->dr_sw) { case NUBUS_DRSW_3COM: @@ -234,7 +232,7 @@ enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) return MAC8390_NONE; } -enum mac8390_access __init mac8390_testio(volatile unsigned long membase) +static enum mac8390_access __init mac8390_testio(volatile unsigned long membase) { unsigned long outdata = 0xA5A0B5B0; unsigned long indata = 0x00000000; @@ -252,7 +250,7 @@ enum mac8390_access __init mac8390_testio(volatile unsigned long membase) return ACCESS_UNKNOWN; } -int __init mac8390_memsize(unsigned long membase) +static int __init mac8390_memsize(unsigned long membase) { unsigned long flags; int i, j; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 92dccd43bdc..e34630252ce 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -80,8 +80,12 @@ static void __init macb_get_hwaddr(struct macb *bp) addr[4] = top & 0xff; addr[5] = (top >> 8) & 0xff; - if (is_valid_ether_addr(addr)) + if (is_valid_ether_addr(addr)) { memcpy(bp->dev->dev_addr, addr, sizeof(addr)); + } else { + dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); + random_ether_addr(bp->dev->dev_addr); + } } static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index b267161418e..e64c2086d33 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -83,9 +83,6 @@ static unsigned int sonic_debug = 1; static int sonic_version_printed; -extern int mac_onboard_sonic_probe(struct net_device* dev); -extern int mac_nubus_sonic_probe(struct net_device* dev); - /* For onboard SONIC */ #define ONBOARD_SONIC_REGISTERS 0x50F0A000 #define ONBOARD_SONIC_PROM_BASE 0x50f08000 @@ -170,7 +167,7 @@ static int macsonic_close(struct net_device* dev) return err; } -int __init macsonic_init(struct net_device* dev) +static int __init macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); @@ -218,7 +215,7 @@ int __init macsonic_init(struct net_device* dev) return 0; } -int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) +static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; @@ -284,7 +281,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) } else return 0; } -int __init mac_onboard_sonic_probe(struct net_device* dev) +static int __init mac_onboard_sonic_probe(struct net_device *dev) { /* Bwahahaha */ static int once_is_more_than_enough; @@ -405,9 +402,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) return macsonic_init(dev); } -int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, - unsigned long prom_addr, - int id) +static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev, + unsigned long prom_addr, + int id) { int i; for(i = 0; i < 6; i++) @@ -420,7 +417,7 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, return 0; } -int __init macsonic_ident(struct nubus_dev* ndev) +static int __init macsonic_ident(struct nubus_dev *ndev) { if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && ndev->dr_sw == NUBUS_DRSW_SONIC_LC) @@ -445,7 +442,7 @@ int __init macsonic_ident(struct nubus_dev* ndev) return -1; } -int __init mac_nubus_sonic_probe(struct net_device* dev) +static int __init mac_nubus_sonic_probe(struct net_device *dev) { static int slots; struct nubus_dev* ndev = NULL; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c new file mode 100644 index 00000000000..f64d987140a --- /dev/null +++ b/drivers/net/sh_eth.c @@ -0,0 +1,1174 @@ +/* + * SuperH Ethernet device driver + * + * Copyright (C) 2006,2007 Nobuhiro Iwamatsu + * Copyright (C) 2008 Renesas Solutions Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/mdio-bitbang.h> +#include <linux/netdevice.h> +#include <linux/phy.h> +#include <linux/cache.h> +#include <linux/io.h> + +#include "sh_eth.h" + +/* + * Program the hardware MAC address from dev->dev_addr. + */ +static void update_mac_address(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ctrl_outl((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) | + (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), + ioaddr + MAHR); + ctrl_outl((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), + ioaddr + MALR); +} + +/* + * Get MAC address from SuperH MAC address register + * + * SuperH's Ethernet device doesn't have 'ROM' to MAC address. + * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g). + * When you want use this device, you must set MAC address in bootloader. + * + */ +static void read_mac_address(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24); + ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF; + ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF; + ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF); + ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF; + ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF); +} + +struct bb_info { + struct mdiobb_ctrl ctrl; + u32 addr; + u32 mmd_msk;/* MMD */ + u32 mdo_msk; + u32 mdi_msk; + u32 mdc_msk; +}; + +/* PHY bit set */ +static void bb_set(u32 addr, u32 msk) +{ + ctrl_outl(ctrl_inl(addr) | msk, addr); +} + +/* PHY bit clear */ +static void bb_clr(u32 addr, u32 msk) +{ + ctrl_outl((ctrl_inl(addr) & ~msk), addr); +} + +/* PHY bit read */ +static int bb_read(u32 addr, u32 msk) +{ + return (ctrl_inl(addr) & msk) != 0; +} + +/* Data I/O pin control */ +static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + if (bit) + bb_set(bitbang->addr, bitbang->mmd_msk); + else + bb_clr(bitbang->addr, bitbang->mmd_msk); +} + +/* Set bit data*/ +static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + + if (bit) + bb_set(bitbang->addr, bitbang->mdo_msk); + else + bb_clr(bitbang->addr, bitbang->mdo_msk); +} + +/* Get bit data*/ +static int sh_get_mdio(struct mdiobb_ctrl *ctrl) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + return bb_read(bitbang->addr, bitbang->mdi_msk); +} + +/* MDC pin control */ +static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit) +{ + struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); + + if (bit) + bb_set(bitbang->addr, bitbang->mdc_msk); + else + bb_clr(bitbang->addr, bitbang->mdc_msk); +} + +/* mdio bus control struct */ +static struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = sh_mdc_ctrl, + .set_mdio_dir = sh_mmd_ctrl, + .set_mdio_data = sh_set_mdio, + .get_mdio_data = sh_get_mdio, +}; + +static void sh_eth_reset(struct net_device *ndev) +{ + u32 ioaddr = ndev->base_addr; + + ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + mdelay(3); + ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); +} + +/* free skb and descriptor buffer */ +static void sh_eth_ring_free(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int i; + + /* Free Rx skb ringbuffer */ + if (mdp->rx_skbuff) { + for (i = 0; i < RX_RING_SIZE; i++) { + if (mdp->rx_skbuff[i]) + dev_kfree_skb(mdp->rx_skbuff[i]); + } + } + kfree(mdp->rx_skbuff); + + /* Free Tx skb ringbuffer */ + if (mdp->tx_skbuff) { + for (i = 0; i < TX_RING_SIZE; i++) { + if (mdp->tx_skbuff[i]) + dev_kfree_skb(mdp->tx_skbuff[i]); + } + } + kfree(mdp->tx_skbuff); +} + +/* format skb and descriptor buffer */ +static void sh_eth_ring_format(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int i; + struct sk_buff *skb; + struct sh_eth_rxdesc *rxdesc = NULL; + struct sh_eth_txdesc *txdesc = NULL; + int rx_ringsize = sizeof(*rxdesc) * RX_RING_SIZE; + int tx_ringsize = sizeof(*txdesc) * TX_RING_SIZE; + + mdp->cur_rx = mdp->cur_tx = 0; + mdp->dirty_rx = mdp->dirty_tx = 0; + + memset(mdp->rx_ring, 0, rx_ringsize); + + /* build Rx ring buffer */ + for (i = 0; i < RX_RING_SIZE; i++) { + /* skb */ + mdp->rx_skbuff[i] = NULL; + skb = dev_alloc_skb(mdp->rx_buf_sz); + mdp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = ndev; /* Mark as being used by this device. */ + skb_reserve(skb, RX_OFFSET); + + /* RX descriptor */ + rxdesc = &mdp->rx_ring[i]; + rxdesc->addr = (u32)skb->data & ~0x3UL; + rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP); + + /* The size of the buffer is 16 byte boundary. */ + rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + } + + mdp->dirty_rx = (u32) (i - RX_RING_SIZE); + + /* Mark the last entry as wrapping the ring. */ + rxdesc->status |= cpu_to_le32(RC_RDEL); + + memset(mdp->tx_ring, 0, tx_ringsize); + + /* build Tx ring buffer */ + for (i = 0; i < TX_RING_SIZE; i++) { + mdp->tx_skbuff[i] = NULL; + txdesc = &mdp->tx_ring[i]; + txdesc->status = cpu_to_le32(TD_TFP); + txdesc->buffer_length = 0; + } + + txdesc->status |= cpu_to_le32(TD_TDLE); +} + +/* Get skb and descriptor buffer */ +static int sh_eth_ring_init(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + int rx_ringsize, tx_ringsize, ret = 0; + + /* + * +26 gets the maximum ethernet encapsulation, +7 & ~7 because the + * card needs room to do 8 byte alignment, +2 so we can reserve + * the first 2 bytes, and +16 gets room for the status word from the + * card. + */ + mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ : + (((ndev->mtu + 26 + 7) & ~7) + 2 + 16)); + + /* Allocate RX and TX skb rings */ + mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE, + GFP_KERNEL); + if (!mdp->rx_skbuff) { + printk(KERN_ERR "%s: Cannot allocate Rx skb\n", ndev->name); + ret = -ENOMEM; + return ret; + } + + mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * TX_RING_SIZE, + GFP_KERNEL); + if (!mdp->tx_skbuff) { + printk(KERN_ERR "%s: Cannot allocate Tx skb\n", ndev->name); + ret = -ENOMEM; + goto skb_ring_free; + } + + /* Allocate all Rx descriptors. */ + rx_ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE; + mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma, + GFP_KERNEL); + + if (!mdp->rx_ring) { + printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n", + ndev->name, rx_ringsize); + ret = -ENOMEM; + goto desc_ring_free; + } + + mdp->dirty_rx = 0; + + /* Allocate all Tx descriptors. */ + tx_ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; + mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma, + GFP_KERNEL); + if (!mdp->tx_ring) { + printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", + ndev->name, tx_ringsize); + ret = -ENOMEM; + goto desc_ring_free; + } + return ret; + +desc_ring_free: + /* free DMA buffer */ + dma_free_coherent(NULL, rx_ringsize, mdp->rx_ring, mdp->rx_desc_dma); + +skb_ring_free: + /* Free Rx and Tx skb ring buffer */ + sh_eth_ring_free(ndev); + + return ret; +} + +static int sh_eth_dev_init(struct net_device *ndev) +{ + int ret = 0; + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + u_int32_t rx_int_var, tx_int_var; + u32 val; + + /* Soft Reset */ + sh_eth_reset(ndev); + + ctrl_outl(RPADIR_PADS1, ioaddr + RPADIR); /* SH7712-DMA-RX-PAD2 */ + + /* all sh_eth int mask */ + ctrl_outl(0, ioaddr + EESIPR); + + /* FIFO size set */ + ctrl_outl(0, ioaddr + EDMR); /* Endian change */ + + ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR); + ctrl_outl(0, ioaddr + TFTR); + + ctrl_outl(RMCR_RST, ioaddr + RMCR); + + rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5; + tx_int_var = mdp->tx_int_var = DESC_I_TINT2; + ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER); + + ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR); + ctrl_outl(0, ioaddr + TRIMD); + + /* Descriptor format */ + sh_eth_ring_format(ndev); + + ctrl_outl((u32)mdp->rx_ring, ioaddr + RDLAR); + ctrl_outl((u32)mdp->tx_ring, ioaddr + TDLAR); + + ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR); + ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR); + + /* PAUSE Prohibition */ + val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) | + ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE; + + ctrl_outl(val, ioaddr + ECMR); + ctrl_outl(ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD | + ECSIPR_MPDIP, ioaddr + ECSR); + ctrl_outl(ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | + ECSIPR_ICDIP | ECSIPR_MPDIP, ioaddr + ECSIPR); + + /* Set MAC address */ + update_mac_address(ndev); + + /* mask reset */ +#if defined(CONFIG_CPU_SUBTYPE_SH7710) + ctrl_outl(APR_AP, ioaddr + APR); + ctrl_outl(MPR_MP, ioaddr + MPR); + ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); + ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR); +#endif + /* Setting the Rx mode will start the Rx process. */ + ctrl_outl(EDRRR_R, ioaddr + EDRRR); + + netif_start_queue(ndev); + + return ret; +} + +/* free Tx skb function */ +static int sh_eth_txfree(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_txdesc *txdesc; + int freeNum = 0; + int entry = 0; + + for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) { + entry = mdp->dirty_tx % TX_RING_SIZE; + txdesc = &mdp->tx_ring[entry]; + if (txdesc->status & cpu_to_le32(TD_TACT)) + break; + /* Free the original skb. */ + if (mdp->tx_skbuff[entry]) { + dev_kfree_skb_irq(mdp->tx_skbuff[entry]); + mdp->tx_skbuff[entry] = NULL; + freeNum++; + } + txdesc->status = cpu_to_le32(TD_TFP); + if (entry >= TX_RING_SIZE - 1) + txdesc->status |= cpu_to_le32(TD_TDLE); + + mdp->stats.tx_packets++; + mdp->stats.tx_bytes += txdesc->buffer_length; + } + return freeNum; +} + +/* Packet receive function */ +static int sh_eth_rx(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + struct sh_eth_rxdesc *rxdesc; + + int entry = mdp->cur_rx % RX_RING_SIZE; + int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx; + struct sk_buff *skb; + u16 pkt_len = 0; + u32 desc_status; + + rxdesc = &mdp->rx_ring[entry]; + while (!(rxdesc->status & cpu_to_le32(RD_RACT))) { + desc_status = le32_to_cpu(rxdesc->status); + pkt_len = rxdesc->frame_length; + + if (--boguscnt < 0) + break; + + if (!(desc_status & RDFEND)) + mdp->stats.rx_length_errors++; + + if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | + RD_RFS5 | RD_RFS6 | RD_RFS10)) { + mdp->stats.rx_errors++; + if (desc_status & RD_RFS1) + mdp->stats.rx_crc_errors++; + if (desc_status & RD_RFS2) + mdp->stats.rx_frame_errors++; + if (desc_status & RD_RFS3) + mdp->stats.rx_length_errors++; + if (desc_status & RD_RFS4) + mdp->stats.rx_length_errors++; + if (desc_status & RD_RFS6) + mdp->stats.rx_missed_errors++; + if (desc_status & RD_RFS10) + mdp->stats.rx_over_errors++; + } else { + swaps((char *)(rxdesc->addr & ~0x3), pkt_len + 2); + skb = mdp->rx_skbuff[entry]; + mdp->rx_skbuff[entry] = NULL; + skb_put(skb, pkt_len); + skb->protocol = eth_type_trans(skb, ndev); + netif_rx(skb); + ndev->last_rx = jiffies; + mdp->stats.rx_packets++; + mdp->stats.rx_bytes += pkt_len; + } + rxdesc->status |= cpu_to_le32(RD_RACT); + entry = (++mdp->cur_rx) % RX_RING_SIZE; + } + + /* Refill the Rx ring buffers. */ + for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) { + entry = mdp->dirty_rx % RX_RING_SIZE; + rxdesc = &mdp->rx_ring[entry]; + if (mdp->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(mdp->rx_buf_sz); + mdp->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = ndev; + skb_reserve(skb, RX_OFFSET); + rxdesc->addr = (u32)skb->data & ~0x3UL; + } + /* The size of the buffer is 16 byte boundary. */ + rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F; + if (entry >= RX_RING_SIZE - 1) + rxdesc->status |= + cpu_to_le32(RD_RACT | RD_RFP | RC_RDEL); + else + rxdesc->status |= + cpu_to_le32(RD_RACT | RD_RFP); + } + + /* Restart Rx engine if stopped. */ + /* If we don't need to check status, don't. -KDU */ + ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR); + + return 0; +} + +/* error control function */ +static void sh_eth_error(struct net_device *ndev, int intr_status) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr = ndev->base_addr; + u32 felic_stat; + + if (intr_status & EESR_ECI) { + felic_stat = ctrl_inl(ioaddr + ECSR); + ctrl_outl(felic_stat, ioaddr + ECSR); /* clear int */ + if (felic_stat & ECSR_ICD) + mdp->stats.tx_carrier_errors++; + if (felic_stat & ECSR_LCHNG) { + /* Link Changed */ + u32 link_stat = (ctrl_inl(ioaddr + PSR)); + if (!(link_stat & PHY_ST_LINK)) { + /* Link Down : disable tx and rx */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) & + ~(ECMR_RE | ECMR_TE), ioaddr + ECMR); + } else { + /* Link Up */ + ctrl_outl(ctrl_inl(ioaddr + EESIPR) & + ~DMAC_M_ECI, ioaddr + EESIPR); + /*clear int */ + ctrl_outl(ctrl_inl(ioaddr + ECSR), + ioaddr + ECSR); + ctrl_outl(ctrl_inl(ioaddr + EESIPR) | + DMAC_M_ECI, ioaddr + EESIPR); + /* enable tx and rx */ + ctrl_outl(ctrl_inl(ioaddr + ECMR) | + (ECMR_RE | ECMR_TE), ioaddr + ECMR); + } + } + } + + if (intr_status & EESR_TWB) { + /* Write buck end. unused write back interrupt */ + if (intr_status & EESR_TABT) /* Transmit Abort int */ + mdp->stats.tx_aborted_errors++; + } + + if (intr_status & EESR_RABT) { + /* Receive Abort int */ + if (intr_status & EESR_RFRMER) { + /* Receive Frame Overflow int */ + mdp->stats.rx_frame_errors++; + printk(KERN_ERR "Receive Frame Overflow\n"); + } + } + + if (intr_status & EESR_ADE) { + if (intr_status & EESR_TDE) { + if (intr_status & EESR_TFE) + mdp->stats.tx_fifo_errors++; + } + } + + if (intr_status & EESR_RDE) { + /* Receive Descriptor Empty int */ + mdp->stats.rx_over_errors++; + + if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R) + ctrl_outl(EDRRR_R, ioaddr + EDRRR); + printk(KERN_ERR "Receive Descriptor Empty\n"); + } + if (intr_status & EESR_RFE) { + /* Receive FIFO Overflow int */ + mdp->stats.rx_fifo_errors++; + printk(KERN_ERR "Receive FIFO Overflow\n"); + } + if (intr_status & + (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)) { + /* Tx error */ + u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR); + /* dmesg */ + printk(KERN_ERR "%s:TX error. status=%8.8x cur_tx=%8.8x ", + ndev->name, intr_status, mdp->cur_tx); + printk(KERN_ERR "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", + mdp->dirty_tx, (u32) ndev->state, edtrr); + /* dirty buffer free */ + sh_eth_txfree(ndev); + + /* SH7712 BUG */ + if (edtrr ^ EDTRR_TRNS) { + /* tx dma start */ + ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + } + /* wakeup */ + netif_wake_queue(ndev); + } +} + +static irqreturn_t sh_eth_interrupt(int irq, void *netdev) +{ + struct net_device *ndev = netdev; + struct sh_eth_private *mdp = netdev_priv(ndev); + u32 ioaddr, boguscnt = RX_RING_SIZE; + u32 intr_status = 0; + + ioaddr = ndev->base_addr; + spin_lock(&mdp->lock); + + intr_status = ctrl_inl(ioaddr + EESR); + /* Clear interrupt */ + ctrl_outl(intr_status, ioaddr + EESR); + + if (intr_status & (EESR_FRC | EESR_RINT8 | + EESR_RINT5 | EESR_RINT4 | EESR_RINT3 | EESR_RINT2 | + EESR_RINT1)) + sh_eth_rx(ndev); + if (intr_status & (EESR_FTC | + EESR_TINT4 | EESR_TINT3 | EESR_TINT2 | EESR_TINT1)) { + + sh_eth_txfree(ndev); + netif_wake_queue(ndev); + } + + if (intr_status & EESR_ERR_CHECK) + sh_eth_error(ndev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING + "%s: Too much work at interrupt, status=0x%4.4x.\n", + ndev->name, intr_status); + } + + spin_unlock(&mdp->lock); + + return IRQ_HANDLED; +} + +static void sh_eth_timer(unsigned long data) +{ + struct net_device *ndev = (struct net_device *)data; + struct sh_eth_private *mdp = netdev_priv(ndev); |