X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/7fb1c80f6cbfc37ae625f234e5dcaa8257e0e930..43bb8183eb10d86dffd1f9413b8db1a3ea5de0a3:/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c?ds=sidebyside diff --git a/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c b/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c index 3dd170d68..7dad43db9 100644 --- a/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c +++ b/target/linux/brcm63xx/files/drivers/net/bcm63xx_enet.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "bcm63xx_enet.h" @@ -189,18 +190,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 +338,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; } @@ -949,8 +950,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 +1017,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 +1117,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 +1506,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 +1632,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; @@ -1721,8 +1775,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 +1787,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 +1809,7 @@ err: enet_writel(priv, 0, ENET_MIISC_REG); iounmap(priv->base); } +out: free_netdev(dev); return ret; } @@ -1801,6 +1857,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; }