X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/7fb1c80f6cbfc37ae625f234e5dcaa8257e0e930..07537ed74301efdc7c26faf1acb4aa175c463696:/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c diff --git a/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c b/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c index 3dd170d68..d338bbc08 100644 --- a/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c +++ b/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #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; }