X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/9d03573661b506cccf95810176c2a1c0a23ad399..2de43698c44aec6720d8eb41825b3bed8d108da1:/target/linux/ifxmips/patches-2.6.30/130-ethernet.patch diff --git a/target/linux/ifxmips/patches-2.6.30/130-ethernet.patch b/target/linux/ifxmips/patches-2.6.30/130-ethernet.patch index da87bb78c..30f169304 100644 --- a/target/linux/ifxmips/patches-2.6.30/130-ethernet.patch +++ b/target/linux/ifxmips/patches-2.6.30/130-ethernet.patch @@ -1,7 +1,7 @@ -Index: linux-2.6.30.5/drivers/net/Kconfig +Index: linux-2.6.30.8/drivers/net/Kconfig =================================================================== ---- linux-2.6.30.5.orig/drivers/net/Kconfig 2009-09-02 18:22:49.000000000 +0200 -+++ linux-2.6.30.5/drivers/net/Kconfig 2009-09-02 18:29:51.000000000 +0200 +--- linux-2.6.30.8.orig/drivers/net/Kconfig 2009-10-19 21:31:30.000000000 +0200 ++++ linux-2.6.30.8/drivers/net/Kconfig 2009-10-19 21:31:32.000000000 +0200 @@ -353,6 +353,12 @@ source "drivers/net/arm/Kconfig" @@ -15,10 +15,10 @@ Index: linux-2.6.30.5/drivers/net/Kconfig config AX88796 tristate "ASIX AX88796 NE2000 clone support" depends on ARM || MIPS || SUPERH -Index: linux-2.6.30.5/drivers/net/Makefile +Index: linux-2.6.30.8/drivers/net/Makefile =================================================================== ---- linux-2.6.30.5.orig/drivers/net/Makefile 2009-09-02 18:22:49.000000000 +0200 -+++ linux-2.6.30.5/drivers/net/Makefile 2009-09-02 18:30:37.000000000 +0200 +--- linux-2.6.30.8.orig/drivers/net/Makefile 2009-10-19 21:31:30.000000000 +0200 ++++ linux-2.6.30.8/drivers/net/Makefile 2009-10-19 21:31:32.000000000 +0200 @@ -234,6 +234,7 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_ENC28J60) += enc28j60.o @@ -27,3 +27,498 @@ Index: linux-2.6.30.5/drivers/net/Makefile obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o +Index: linux-2.6.30.8/drivers/net/ifxmips_mii0.c +=================================================================== +--- /dev/null 2010-01-25 20:01:36.843225078 +0100 ++++ linux-2.6.30.10/drivers/net/ifxmips_mii0.c 2010-03-13 19:04:25.000000000 +0100 +@@ -0,0 +1,489 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2005 Wu Qi Ming ++ * Copyright (C) 2008 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++struct ifxmips_mii_priv { ++ struct net_device_stats stats; ++ struct dma_device_info *dma_device; ++ struct sk_buff *skb; ++ ++ struct mii_bus *mii_bus; ++ struct phy_device *phydev; ++ int oldlink, oldspeed, oldduplex; ++}; ++ ++static struct net_device *ifxmips_mii0_dev; ++static unsigned char mac_addr[MAX_ADDR_LEN]; ++ ++static int ifxmips_mdiobus_write(struct mii_bus *bus, int phy_addr, ++ int phy_reg, u16 phy_data) ++{ ++ u32 val = MDIO_ACC_REQUEST | ++ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | ++ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) | ++ phy_data; ++ ++ while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST) ++ ; ++ ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC); ++ ++ return 0; ++} ++ ++static int ifxmips_mdiobus_read(struct mii_bus *bus, int phy_addr, int phy_reg) ++{ ++ u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ | ++ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | ++ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET); ++ ++ while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST) ++ ; ++ ifxmips_w32(val, IFXMIPS_PPE32_MDIO_ACC); ++ while (ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST) ++ ; ++ val = ifxmips_r32(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK; ++ return val; ++} ++ ++int ifxmips_ifxmips_mii_open(struct net_device *dev) ++{ ++ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev); ++ struct dma_device_info *dma_dev = priv->dma_device; ++ int i; ++ ++ for (i = 0; i < dma_dev->max_rx_chan_num; i++) { ++ if ((dma_dev->rx_chan[i])->control == IFXMIPS_DMA_CH_ON) ++ (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]); ++ } ++ netif_start_queue(dev); ++ return 0; ++} ++ ++int ifxmips_mii_release(struct net_device *dev) ++{ ++ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev); ++ struct dma_device_info *dma_dev = priv->dma_device; ++ int i; ++ ++ for (i = 0; i < dma_dev->max_rx_chan_num; i++) ++ dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]); ++ netif_stop_queue(dev); ++ return 0; ++} ++ ++int ifxmips_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev) ++{ ++ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev); ++ unsigned char *buf = NULL; ++ struct sk_buff *skb = NULL; ++ int len = 0; ++ ++ len = dma_device_read(dma_dev, &buf, (void **)&skb); ++ ++ if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) { ++ printk(KERN_INFO "ifxmips_mii0: packet too large %d\n", len); ++ goto ifxmips_mii_hw_receive_err_exit; ++ } ++ ++ /* remove CRC */ ++ len -= 4; ++ if (skb == NULL) { ++ printk(KERN_INFO "ifxmips_mii0: cannot restore pointer\n"); ++ goto ifxmips_mii_hw_receive_err_exit; ++ } ++ ++ if (len > (skb->end - skb->tail)) { ++ printk(KERN_INFO "ifxmips_mii0: BUG, len:%d end:%p tail:%p\n", ++ (len+4), skb->end, skb->tail); ++ goto ifxmips_mii_hw_receive_err_exit; ++ } ++ ++ skb_put(skb, len); ++ skb->dev = dev; ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ ++ priv->stats.rx_packets++; ++ priv->stats.rx_bytes += len; ++ return 0; ++ ++ifxmips_mii_hw_receive_err_exit: ++ if (len == 0) { ++ if (skb) ++ dev_kfree_skb_any(skb); ++ priv->stats.rx_errors++; ++ priv->stats.rx_dropped++; ++ return -EIO; ++ } else { ++ return len; ++ } ++} ++ ++int ifxmips_mii_hw_tx(char *buf, int len, struct net_device *dev) ++{ ++ int ret = 0; ++ struct ifxmips_mii_priv *priv = netdev_priv(dev); ++ struct dma_device_info *dma_dev = priv->dma_device; ++ ret = dma_device_write(dma_dev, buf, len, priv->skb); ++ return ret; ++} ++ ++int ifxmips_mii_tx(struct sk_buff *skb, struct net_device *dev) ++{ ++ int len; ++ char *data; ++ struct ifxmips_mii_priv *priv = netdev_priv(dev); ++ struct dma_device_info *dma_dev = priv->dma_device; ++ ++ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; ++ data = skb->data; ++ priv->skb = skb; ++ dev->trans_start = jiffies; ++ /* TODO: we got more than 1 dma channel, ++ so we should do something intelligent here to select one */ ++ dma_dev->current_tx_chan = 0; ++ ++ wmb(); ++ ++ if (ifxmips_mii_hw_tx(data, len, dev) != len) { ++ dev_kfree_skb_any(skb); ++ priv->stats.tx_errors++; ++ priv->stats.tx_dropped++; ++ } else { ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += len; ++ } ++ ++ return 0; ++} ++ ++void ifxmips_mii_tx_timeout(struct net_device *dev) ++{ ++ int i; ++ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev); ++ ++ priv->stats.tx_errors++; ++ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) ++ priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]); ++ netif_wake_queue(dev); ++ return; ++} ++ ++int dma_intr_handler(struct dma_device_info *dma_dev, int status) ++{ ++ int i; ++ ++ switch (status) { ++ case RCV_INT: ++ ifxmips_mii_hw_receive(ifxmips_mii0_dev, dma_dev); ++ break; ++ ++ case TX_BUF_FULL_INT: ++ printk(KERN_INFO "ifxmips_mii0: tx buffer full\n"); ++ netif_stop_queue(ifxmips_mii0_dev); ++ for (i = 0; i < dma_dev->max_tx_chan_num; i++) { ++ if ((dma_dev->tx_chan[i])->control == IFXMIPS_DMA_CH_ON) ++ dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]); ++ } ++ break; ++ ++ case TRANSMIT_CPT_INT: ++ for (i = 0; i < dma_dev->max_tx_chan_num; i++) ++ dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); ++ ++ netif_wake_queue(ifxmips_mii0_dev); ++ break; ++ } ++ ++ return 0; ++} ++ ++unsigned char *ifxmips_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt) ++{ ++ unsigned char *buffer = NULL; ++ struct sk_buff *skb = NULL; ++ ++ skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); ++ if (skb == NULL) ++ return NULL; ++ ++ buffer = (unsigned char *)(skb->data); ++ skb_reserve(skb, 2); ++ *(int *)opt = (int)skb; ++ *byte_offset = 2; ++ ++ return buffer; ++} ++ ++void ifxmips_etop_dma_buffer_free(unsigned char *dataptr, void *opt) ++{ ++ struct sk_buff *skb = NULL; ++ ++ if (opt == NULL) { ++ kfree(dataptr); ++ } else { ++ skb = (struct sk_buff *)opt; ++ dev_kfree_skb_any(skb); ++ } ++} ++ ++static struct net_device_stats *ifxmips_get_stats(struct net_device *dev) ++{ ++ return &((struct ifxmips_mii_priv *)netdev_priv(dev))->stats; ++} ++ ++static void ++ifxmips_adjust_link(struct net_device *dev) ++{ ++ struct ifxmips_mii_priv *priv = netdev_priv(dev); ++ struct phy_device *phydev = priv->phydev; ++ int new_state = 0; ++ ++ /* Did anything change? */ ++ if (priv->oldlink != phydev->link || ++ priv->oldduplex != phydev->duplex || ++ priv->oldspeed != phydev->speed) { ++ /* Yes, so update status and mark as changed */ ++ new_state = 1; ++ priv->oldduplex = phydev->duplex; ++ priv->oldspeed = phydev->speed; ++ priv->oldlink = phydev->link; ++ } ++ ++ /* If link status changed, show new status */ ++ if (new_state) ++ phy_print_status(phydev); ++} ++ ++static int mii_probe(struct net_device *dev) ++{ ++ struct ifxmips_mii_priv *priv = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int phy_addr; ++ ++ priv->oldlink = 0; ++ priv->oldspeed = 0; ++ priv->oldduplex = -1; ++ ++ /* find the first (lowest address) PHY on the current MAC's MII bus */ ++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { ++ if (priv->mii_bus->phy_map[phy_addr]) { ++ phydev = priv->mii_bus->phy_map[phy_addr]; ++ break; /* break out with first one found */ ++ } ++ } ++ ++ if (!phydev) { ++ printk (KERN_ERR "%s: no PHY found\n", dev->name); ++ return -ENODEV; ++ } ++ ++ /* now we are supposed to have a proper phydev, to attach to... */ ++ BUG_ON(!phydev); ++ BUG_ON(phydev->attached_dev); ++ ++ phydev = phy_connect(dev, dev_name(&phydev->dev), &ifxmips_adjust_link, ++ 0, PHY_INTERFACE_MODE_MII); ++ ++ if (IS_ERR(phydev)) { ++ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); ++ return PTR_ERR(phydev); ++ } ++ ++ /* mask with MAC supported features */ ++ phydev->supported &= (SUPPORTED_10baseT_Half ++ | SUPPORTED_10baseT_Full ++ | SUPPORTED_100baseT_Half ++ | SUPPORTED_100baseT_Full ++ | SUPPORTED_Autoneg ++ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */ ++ | SUPPORTED_MII ++ | SUPPORTED_TP); ++ ++ phydev->advertising = phydev->supported; ++ ++ priv->phydev = phydev; ++ ++ printk(KERN_INFO "%s: attached PHY driver [%s] " ++ "(mii_bus:phy_addr=%s, irq=%d)\n", ++ dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq); ++ ++ return 0; ++} ++ ++ ++static int ifxmips_mii_dev_init(struct net_device *dev) ++{ ++ int i; ++ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(dev); ++ ether_setup(dev); ++ dev->open = ifxmips_ifxmips_mii_open; ++ dev->stop = ifxmips_mii_release; ++ dev->hard_start_xmit = ifxmips_mii_tx; ++ dev->get_stats = ifxmips_get_stats; ++ dev->tx_timeout = ifxmips_mii_tx_timeout; ++ dev->watchdog_timeo = 10 * HZ; ++ memset(priv, 0, sizeof(struct ifxmips_mii_priv)); ++ priv->dma_device = dma_device_reserve("PPE"); ++ if (!priv->dma_device) { ++ BUG(); ++ return -ENODEV; ++ } ++ priv->dma_device->buffer_alloc = &ifxmips_etop_dma_buffer_alloc; ++ priv->dma_device->buffer_free = &ifxmips_etop_dma_buffer_free; ++ priv->dma_device->intr_handler = &dma_intr_handler; ++ priv->dma_device->max_rx_chan_num = 4; ++ ++ for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) { ++ priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE; ++ priv->dma_device->rx_chan[i]->control = IFXMIPS_DMA_CH_ON; ++ } ++ ++ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) ++ if (i == 0) ++ priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_ON; ++ else ++ priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_OFF; ++ ++ dma_device_register(priv->dma_device); ++ ++ printk(KERN_INFO "%s: using mac=", dev->name); ++ for (i = 0; i < 6; i++) { ++ dev->dev_addr[i] = mac_addr[i]; ++ printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':')); ++ } ++ ++ priv->mii_bus = mdiobus_alloc(); ++ if (priv->mii_bus == NULL) ++ return -ENOMEM; ++ ++ priv->mii_bus->priv = dev; ++ priv->mii_bus->read = ifxmips_mdiobus_read; ++ priv->mii_bus->write = ifxmips_mdiobus_write; ++ priv->mii_bus->name = "ifxmips_mii"; ++ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); ++ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); ++ for(i = 0; i < PHY_MAX_ADDR; ++i) ++ priv->mii_bus->irq[i] = PHY_POLL; ++ ++ mdiobus_register(priv->mii_bus); ++ ++ return mii_probe(dev); ++} ++ ++static void ifxmips_mii_chip_init(int mode) ++{ ++ ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_DMA); ++ ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_PPE); ++ ++ if (mode == REV_MII_MODE) ++ ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, IFXMIPS_PPE32_CFG); ++ else if (mode == MII_MODE) ++ ifxmips_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, IFXMIPS_PPE32_CFG); ++ ifxmips_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, IFXMIPS_PPE32_IG_PLEN_CTRL); ++ ifxmips_w32(PPE32_CGEN, IFXMIPS_PPE32_ENET_MAC_CFG); ++ wmb(); ++} ++ ++static int ifxmips_mii_probe(struct platform_device *dev) ++{ ++ int result = 0; ++ unsigned char *mac = (unsigned char *)dev->dev.platform_data; ++ ifxmips_mii0_dev = alloc_etherdev(sizeof(struct ifxmips_mii_priv)); ++ ifxmips_mii0_dev->init = ifxmips_mii_dev_init; ++ memcpy(mac_addr, mac, 6); ++ strcpy(ifxmips_mii0_dev->name, "eth%d"); ++ ifxmips_mii_chip_init(REV_MII_MODE); ++ result = register_netdev(ifxmips_mii0_dev); ++ if (result) { ++ printk(KERN_INFO "ifxmips_mii0: error %i registering device \"%s\"\n", result, ifxmips_mii0_dev->name); ++ goto out; ++ } ++ ++ printk(KERN_INFO "ifxmips_mii0: driver loaded!\n"); ++ ++out: ++ return result; ++} ++ ++static int ifxmips_mii_remove(struct platform_device *dev) ++{ ++ struct ifxmips_mii_priv *priv = (struct ifxmips_mii_priv *)netdev_priv(ifxmips_mii0_dev); ++ ++ printk(KERN_INFO "ifxmips_mii0: ifxmips_mii0 cleanup\n"); ++ ++ dma_device_unregister(priv->dma_device); ++ dma_device_release(priv->dma_device); ++ kfree(priv->dma_device); ++ unregister_netdev(ifxmips_mii0_dev); ++ return 0; ++} ++ ++static struct platform_driver ifxmips_mii_driver = { ++ .probe = ifxmips_mii_probe, ++ .remove = ifxmips_mii_remove, ++ .driver = { ++ .name = "ifxmips_mii0", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ifxmips_mii_init(void) ++{ ++ int ret = platform_driver_register(&ifxmips_mii_driver); ++ if (ret) ++ printk(KERN_INFO "ifxmips_mii0: Error registering platfom driver!"); ++ return ret; ++} ++ ++static void __exit ifxmips_mii_cleanup(void) ++{ ++ platform_driver_unregister(&ifxmips_mii_driver); ++} ++ ++module_init(ifxmips_mii_init); ++module_exit(ifxmips_mii_cleanup); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("John Crispin "); ++MODULE_DESCRIPTION("ethernet driver for IFXMIPS boards"); ++