diff --git a/target/linux/brcm63xx/patches-2.6.30/060-bcm63xx_enet_upstream_fixes.patch b/target/linux/brcm63xx/patches-2.6.30/060-bcm63xx_enet_upstream_fixes.patch new file mode 100644 index 0000000000..0271aa6c91 --- /dev/null +++ b/target/linux/brcm63xx/patches-2.6.30/060-bcm63xx_enet_upstream_fixes.patch @@ -0,0 +1,439 @@ +--- a/drivers/net/bcm63xx_enet.c 2009-07-31 22:06:20.000000000 +0200 ++++ b/drivers/net/bcm63xx_enet.c 2009-08-05 10:02:28.000000000 +0200 +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + + #include + #include "bcm63xx_enet.h" +@@ -321,7 +320,7 @@ + if (len < copybreak) { + struct sk_buff *nskb; + +- nskb = netdev_alloc_skb(dev, len + 2); ++ nskb = netdev_alloc_skb(dev, len + NET_IP_ALIGN); + if (!nskb) { + /* forget packet, just rearm desc */ + priv->stats.rx_dropped++; +@@ -452,11 +451,7 @@ + + /* no more packet in rx/tx queue, remove device from poll + * queue */ +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +- netif_rx_complete(dev, napi); +-#else + napi_complete(napi); +-#endif + + /* restore rx/tx interrupt */ + enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK, +@@ -508,11 +503,7 @@ + enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); + enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); + +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +- netif_rx_schedule(dev, &priv->napi); +-#else + napi_schedule(&priv->napi); +-#endif + + return IRQ_HANDLED; + } +@@ -764,11 +755,11 @@ + pr_info("%s: link %s", dev->name, phydev->link ? + "UP" : "DOWN"); + if (phydev->link) +- printk(" - %d/%s - flow control %s", phydev->speed, ++ pr_cont(" - %d/%s - flow control %s", phydev->speed, + DUPLEX_FULL == phydev->duplex ? "full" : "half", + phydev->pause == 1 ? "rx&tx" : "off"); + +- printk("\n"); ++ pr_cont("\n"); + } + } + +@@ -782,6 +773,7 @@ + priv = netdev_priv(dev); + bcm_enet_set_duplex(priv, priv->force_duplex_full); + bcm_enet_set_flow(priv, priv->pause_rx, priv->pause_tx); ++ netif_carrier_on(dev); + + pr_info("%s: link forced UP - %d/%s - flow control %s/%s\n", + dev->name, +@@ -800,21 +792,18 @@ + struct sockaddr addr; + struct device *kdev; + struct phy_device *phydev; +- int irq_requested, i, ret; ++ int i, ret; + unsigned int size; +- char phy_id[BUS_ID_SIZE]; ++ char phy_id[MII_BUS_ID_SIZE + 3]; + void *p; + u32 val; + + priv = netdev_priv(dev); +- priv->rx_desc_cpu = priv->tx_desc_cpu = NULL; +- priv->rx_skb = priv->tx_skb = NULL; +- + kdev = &priv->pdev->dev; + + if (priv->has_phy) { + /* connect to PHY */ +- snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, ++ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, + priv->mac_id ? "1" : "0", priv->phy_id); + + phydev = phy_connect(dev, phy_id, &bcm_enet_adjust_phy_link, 0, +@@ -854,23 +843,19 @@ + enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan)); + enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan)); + +- irq_requested = 0; + ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev); + if (ret) +- goto out; +- irq_requested++; ++ goto out_phy_disconnect; + + ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, + IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev); + if (ret) +- goto out; +- irq_requested++; ++ goto out_freeirq; + + ret = request_irq(priv->irq_tx, bcm_enet_isr_dma, + IRQF_DISABLED, dev->name, dev); + if (ret) +- goto out; +- irq_requested++; ++ goto out_freeirq_rx; + + /* initialize perfect match registers */ + for (i = 0; i < 4; i++) { +@@ -888,7 +873,7 @@ + if (!p) { + dev_err(kdev, "cannot allocate rx ring %u\n", size); + ret = -ENOMEM; +- goto out; ++ goto out_freeirq_tx; + } + + memset(p, 0, size); +@@ -901,7 +886,7 @@ + if (!p) { + dev_err(kdev, "cannot allocate tx ring\n"); + ret = -ENOMEM; +- goto out; ++ goto out_free_rx_ring; + } + + memset(p, 0, size); +@@ -913,7 +898,7 @@ + if (!priv->tx_skb) { + dev_err(kdev, "cannot allocate rx skb queue\n"); + ret = -ENOMEM; +- goto out; ++ goto out_free_tx_ring; + } + + priv->tx_desc_count = priv->tx_ring_size; +@@ -927,7 +912,7 @@ + if (!priv->rx_skb) { + dev_err(kdev, "cannot allocate rx skb queue\n"); + ret = -ENOMEM; +- goto out; ++ goto out_free_tx_skb; + } + + priv->rx_desc_count = 0; +@@ -1012,13 +997,6 @@ + return 0; + + out: +- phy_disconnect(priv->phydev); +- if (irq_requested > 2) +- free_irq(priv->irq_tx, dev); +- if (irq_requested > 1) +- free_irq(priv->irq_rx, dev); +- if (irq_requested > 0) +- free_irq(dev->irq, dev); + for (i = 0; i < priv->rx_ring_size; i++) { + struct bcm_enet_desc *desc; + +@@ -1030,14 +1008,31 @@ + DMA_FROM_DEVICE); + kfree_skb(priv->rx_skb[i]); + } +- if (priv->rx_desc_cpu) +- dma_free_coherent(kdev, priv->rx_desc_alloc_size, +- priv->rx_desc_cpu, priv->rx_desc_dma); +- if (priv->tx_desc_cpu) +- dma_free_coherent(kdev, priv->tx_desc_alloc_size, +- priv->tx_desc_cpu, priv->tx_desc_dma); + kfree(priv->rx_skb); ++ ++out_free_tx_skb: + kfree(priv->tx_skb); ++ ++out_free_tx_ring: ++ dma_free_coherent(kdev, priv->tx_desc_alloc_size, ++ priv->tx_desc_cpu, priv->tx_desc_dma); ++ ++out_free_rx_ring: ++ dma_free_coherent(kdev, priv->rx_desc_alloc_size, ++ priv->rx_desc_cpu, priv->rx_desc_dma); ++ ++out_freeirq_tx: ++ free_irq(priv->irq_tx, dev); ++ ++out_freeirq_rx: ++ free_irq(priv->irq_rx, dev); ++ ++out_freeirq: ++ free_irq(dev->irq, dev); ++ ++out_phy_disconnect: ++ phy_disconnect(priv->phydev); ++ + return ret; + } + +@@ -1606,6 +1601,20 @@ + enet_writel(priv, val, ENET_MIBCTL_REG); + } + ++static const struct net_device_ops bcm_enet_ops = { ++ .ndo_open = bcm_enet_open, ++ .ndo_stop = bcm_enet_stop, ++ .ndo_start_xmit = bcm_enet_start_xmit, ++ .ndo_get_stats = bcm_enet_get_stats, ++ .ndo_set_mac_address = bcm_enet_set_mac_address, ++ .ndo_set_multicast_list = bcm_enet_set_multicast_list, ++ .ndo_do_ioctl = bcm_enet_ioctl, ++ .ndo_change_mtu = bcm_enet_change_mtu, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = bcm_enet_netpoll, ++#endif ++}; ++ + /* + * allocate netdevice, request register memory and register device. + */ +@@ -1618,15 +1627,13 @@ + struct mii_bus *bus; + const char *clk_name; + unsigned int iomem_size; +- int i, ret, mdio_registered, mem_requested; ++ int i, ret; + + /* stop if shared driver failed, assume driver->probe will be + * called in the same order we register devices (correct ?) */ + if (!bcm_enet_shared_base) + return -ENODEV; + +- mdio_registered = mem_requested = 0; +- + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1); +@@ -1648,14 +1655,13 @@ + iomem_size = res_mem->end - res_mem->start + 1; + if (!request_mem_region(res_mem->start, iomem_size, "bcm63xx_enet")) { + ret = -EBUSY; +- goto err; ++ goto out; + } +- mem_requested = 1; + + priv->base = ioremap(res_mem->start, iomem_size); + if (priv->base == NULL) { + ret = -ENOMEM; +- goto err; ++ goto out_release_mem; + } + dev->irq = priv->irq = res_irq->start; + priv->irq_rx = res_irq_rx->start; +@@ -1676,8 +1682,7 @@ + priv->mac_clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(priv->mac_clk)) { + ret = PTR_ERR(priv->mac_clk); +- priv->mac_clk = NULL; +- goto err; ++ goto out_unmap; + } + clk_enable(priv->mac_clk); + +@@ -1706,7 +1711,7 @@ + if (IS_ERR(priv->phy_clk)) { + ret = PTR_ERR(priv->phy_clk); + priv->phy_clk = NULL; +- goto err; ++ goto out_put_clk_mac; + } + clk_enable(priv->phy_clk); + } +@@ -1716,13 +1721,16 @@ + + /* MII bus registration */ + if (priv->has_phy) { +- bus = &priv->mii_bus; ++ ++ priv->mii_bus = mdiobus_alloc(); ++ if (!priv->mii_bus) { ++ ret = -ENOMEM; ++ goto out_uninit_hw; ++ } ++ ++ bus = priv->mii_bus; + bus->name = "bcm63xx_enet MII bus"; +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) +- bus->dev = &pdev->dev; +-#else + bus->parent = &pdev->dev; +-#endif + bus->priv = priv; + bus->read = bcm_enet_mdio_read_phylib; + bus->write = bcm_enet_mdio_write_phylib; +@@ -1736,7 +1744,7 @@ + bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!bus->irq) { + ret = -ENOMEM; +- goto err; ++ goto out_free_mdio; + } + + if (priv->has_phy_interrupt) +@@ -1747,9 +1755,8 @@ + ret = mdiobus_register(bus); + if (ret) { + dev_err(&pdev->dev, "unable to register mdio bus\n"); +- goto err; ++ goto out_free_mdio; + } +- mdio_registered = 1; + } else { + + /* run platform code to initialize PHY device */ +@@ -1757,7 +1764,7 @@ + pd->mii_config(dev, 1, bcm_enet_mdio_read_mii, + bcm_enet_mdio_write_mii)) { + dev_err(&pdev->dev, "unable to configure mdio bus\n"); +- goto err; ++ goto out_uninit_hw; + } + } + +@@ -1777,51 +1784,50 @@ + enet_writel(priv, 0, ENET_MIB_REG(i)); + + /* register netdevice */ +- dev->open = bcm_enet_open; +- dev->stop = bcm_enet_stop; +- dev->hard_start_xmit = bcm_enet_start_xmit; +- dev->get_stats = bcm_enet_get_stats; +- dev->set_mac_address = bcm_enet_set_mac_address; +- dev->set_multicast_list = bcm_enet_set_multicast_list; ++ dev->netdev_ops = &bcm_enet_ops; + netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16); +- dev->do_ioctl = bcm_enet_ioctl; +-#ifdef CONFIG_NET_POLL_CONTROLLER +- dev->poll_controller = bcm_enet_netpoll; +-#endif +- dev->change_mtu = bcm_enet_change_mtu; + + SET_ETHTOOL_OPS(dev, &bcm_enet_ethtool_ops); +- SET_NETDEV_DEV(dev, &pdev->dev); + + ret = register_netdev(dev); + if (ret) +- goto err; ++ goto out_unregister_mdio; + ++ netif_carrier_off(dev); + platform_set_drvdata(pdev, dev); + priv->pdev = pdev; + priv->net_dev = dev; ++ SET_NETDEV_DEV(dev, &pdev->dev); + + return 0; + +-err: +- if (mem_requested) +- release_mem_region(res_mem->start, iomem_size); +- if (mdio_registered) +- mdiobus_unregister(&priv->mii_bus); +- kfree(priv->mii_bus.irq); +- if (priv->mac_clk) { +- clk_disable(priv->mac_clk); +- clk_put(priv->mac_clk); ++out_unregister_mdio: ++ if (priv->mii_bus) { ++ mdiobus_unregister(priv->mii_bus); ++ kfree(priv->mii_bus->irq); + } ++ ++out_free_mdio: ++ if (priv->mii_bus) ++ mdiobus_free(priv->mii_bus); ++ ++out_uninit_hw: ++ /* turn off mdc clock */ ++ enet_writel(priv, 0, ENET_MIISC_REG); + if (priv->phy_clk) { + clk_disable(priv->phy_clk); + clk_put(priv->phy_clk); + } +- if (priv->base) { +- /* turn off mdc clock */ +- enet_writel(priv, 0, ENET_MIISC_REG); +- iounmap(priv->base); +- } ++ ++out_put_clk_mac: ++ clk_disable(priv->mac_clk); ++ clk_put(priv->mac_clk); ++ ++out_unmap: ++ iounmap(priv->base); ++ ++out_release_mem: ++ release_mem_region(res_mem->start, iomem_size); + out: + free_netdev(dev); + return ret; +@@ -1846,8 +1852,9 @@ + enet_writel(priv, 0, ENET_MIISC_REG); + + if (priv->has_phy) { +- mdiobus_unregister(&priv->mii_bus); +- kfree(priv->mii_bus.irq); ++ mdiobus_unregister(priv->mii_bus); ++ kfree(priv->mii_bus->irq); ++ mdiobus_free(priv->mii_bus); + } else { + struct bcm63xx_enet_platform_data *pd; + +@@ -1870,7 +1877,6 @@ + clk_disable(priv->mac_clk); + clk_put(priv->mac_clk); + +- platform_set_drvdata(pdev, NULL); + free_netdev(dev); + return 0; + } +--- a/drivers/net/bcm63xx_enet.h 2009-06-07 11:25:51.000000000 +0200 ++++ b/drivers/net/bcm63xx_enet.h 2009-08-05 10:02:28.000000000 +0200 +@@ -258,7 +258,7 @@ + int phy_interrupt; + + /* used when a phy is connected (phylib used) */ +- struct mii_bus mii_bus; ++ struct mii_bus *mii_bus; + struct phy_device *phydev; + int old_link; + int old_duplex;