[kernel] update to 2.6.27.32
[openwrt.git] / target / linux / brcm63xx / files / drivers / net / bcm63xx_enet.c
index 3dd170d..d338bbc 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/if_vlan.h>
+#include <linux/version.h>
 
 #include <bcm63xx_dev_enet.h>
 #include "bcm63xx_enet.h"
@@ -189,18 +191,18 @@ static int bcm_enet_refill_rx(struct net_device *dev)
                desc = &priv->rx_desc_cpu[desc_idx];
 
                if (!priv->rx_skb[desc_idx]) {
-                       skb = netdev_alloc_skb(dev, BCMENET_MAX_RX_SIZE);
+                       skb = netdev_alloc_skb(dev, priv->rx_skb_size);
                        if (!skb)
                                break;
                        priv->rx_skb[desc_idx] = skb;
 
                        p = dma_map_single(&priv->pdev->dev, skb->data,
-                                          BCMENET_MAX_RX_SIZE,
+                                          priv->rx_skb_size,
                                           DMA_FROM_DEVICE);
                        desc->address = p;
                }
 
-               len_stat = BCMENET_MAX_RX_SIZE << DMADESC_LENGTH_SHIFT;
+               len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT;
                len_stat |= DMADESC_OWNER_MASK;
                if (priv->rx_dirty_desc == priv->rx_ring_size - 1) {
                        len_stat |= DMADESC_WRAP_MASK;
@@ -337,7 +339,7 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
                        skb = nskb;
                } else {
                        dma_unmap_single(&priv->pdev->dev, desc->address,
-                                        BCMENET_MAX_RX_SIZE, DMA_FROM_DEVICE);
+                                        priv->rx_skb_size, DMA_FROM_DEVICE);
                        priv->rx_skb[desc_idx] = NULL;
                }
 
@@ -450,7 +452,11 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
 
        /* 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,
@@ -502,7 +508,11 @@ static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id)
        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;
 }
@@ -949,8 +959,8 @@ static int bcm_enet_open(struct net_device *dev)
        enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->tx_chan));
 
        /* set max rx/tx length */
-       enet_writel(priv, BCMENET_MAX_RX_SIZE, ENET_RXMAXLEN_REG);
-       enet_writel(priv, BCMENET_MAX_TX_SIZE, ENET_TXMAXLEN_REG);
+       enet_writel(priv, priv->hw_mtu, ENET_RXMAXLEN_REG);
+       enet_writel(priv, priv->hw_mtu, ENET_TXMAXLEN_REG);
 
        /* set dma maximum burst len */
        enet_dma_writel(priv, BCMENET_DMA_MAXBURST,
@@ -1016,7 +1026,7 @@ out:
                        continue;
 
                desc = &priv->rx_desc_cpu[i];
-               dma_unmap_single(kdev, desc->address, BCMENET_MAX_RX_SIZE,
+               dma_unmap_single(kdev, desc->address, priv->rx_skb_size,
                                 DMA_FROM_DEVICE);
                kfree_skb(priv->rx_skb[i]);
        }
@@ -1116,7 +1126,7 @@ static int bcm_enet_stop(struct net_device *dev)
                        continue;
 
                desc = &priv->rx_desc_cpu[i];
-               dma_unmap_single(kdev, desc->address, BCMENET_MAX_RX_SIZE,
+               dma_unmap_single(kdev, desc->address, priv->rx_skb_size,
                                 DMA_FROM_DEVICE);
                kfree_skb(priv->rx_skb[i]);
        }
@@ -1505,6 +1515,55 @@ static int bcm_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        }
 }
 
+/*
+ * calculate actual hardware mtu
+ */
+static int compute_hw_mtu(struct bcm_enet_priv *priv, int mtu)
+{
+       int actual_mtu;
+
+       actual_mtu = mtu;
+
+       /* add ethernet header + vlan tag size */
+       actual_mtu += VLAN_ETH_HLEN;
+
+       if (actual_mtu < 64 || actual_mtu > BCMENET_MAX_MTU)
+               return -EINVAL;
+
+       /*
+        * setup maximum size before we get overflow mark in
+        * descriptor, note that this will not prevent reception of
+        * big frames, they will be split into multiple buffers
+        * anyway
+        */
+       priv->hw_mtu = actual_mtu;
+
+       /*
+        * align rx buffer size to dma burst len, account FCS since
+        * it's appended
+        */
+       priv->rx_skb_size = ALIGN(actual_mtu + ETH_FCS_LEN,
+                                 BCMENET_DMA_MAXBURST * 4);
+       return 0;
+}
+
+/*
+ * adjust mtu, can't be called while device is running
+ */
+static int bcm_enet_change_mtu(struct net_device *dev, int new_mtu)
+{
+       int ret;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       ret = compute_hw_mtu(netdev_priv(dev), new_mtu);
+       if (ret)
+               return ret;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 /*
  * preinit hardware to allow mii operation while device is down
  */
@@ -1582,6 +1641,10 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
        priv = netdev_priv(dev);
        memset(priv, 0, sizeof(*priv));
 
+       ret = compute_hw_mtu(priv, dev->mtu);
+       if (ret)
+               goto out;
+
        iomem_size = res_mem->end - res_mem->start + 1;
        if (!request_mem_region(res_mem->start, iomem_size, "bcm63xx_enet")) {
                ret = -EBUSY;
@@ -1655,7 +1718,11 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
        if (priv->has_phy) {
                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;
@@ -1721,8 +1788,10 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
 #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)
@@ -1731,7 +1800,6 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, dev);
        priv->pdev = pdev;
        priv->net_dev = dev;
-       SET_NETDEV_DEV(dev, &pdev->dev);
 
        return 0;
 
@@ -1754,6 +1822,7 @@ err:
                enet_writel(priv, 0, ENET_MIISC_REG);
                iounmap(priv->base);
        }
+out:
        free_netdev(dev);
        return ret;
 }
@@ -1801,6 +1870,7 @@ static int __devexit bcm_enet_remove(struct platform_device *pdev)
        clk_disable(priv->mac_clk);
        clk_put(priv->mac_clk);
 
+       platform_set_drvdata(pdev, NULL);
        free_netdev(dev);
        return 0;
 }
This page took 0.032739 seconds and 4 git commands to generate.