diff options
Diffstat (limited to 'drivers/net/ll_temac_main.c')
-rw-r--r-- | drivers/net/ll_temac_main.c | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 6474c49..b5c6279 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -193,6 +193,35 @@ static int temac_dcr_setup(struct temac_local *lp, struct of_device *op, #endif /** + * * temac_dma_bd_release - Release buffer descriptor rings + */ +static void temac_dma_bd_release(struct net_device *ndev) +{ + struct temac_local *lp = netdev_priv(ndev); + int i; + + for (i = 0; i < RX_BD_NUM; i++) { + if (!lp->rx_skb[i]) + break; + else { + dma_unmap_single(ndev->dev.parent, lp->rx_bd_v[i].phys, + XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE); + dev_kfree_skb(lp->rx_skb[i]); + } + } + if (lp->rx_bd_v) + dma_free_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + lp->rx_bd_v, lp->rx_bd_p); + if (lp->tx_bd_v) + dma_free_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + lp->tx_bd_v, lp->tx_bd_p); + if (lp->rx_skb) + kfree(lp->rx_skb); +} + +/** * temac_dma_bd_init - Setup buffer descriptor rings */ static int temac_dma_bd_init(struct net_device *ndev) @@ -202,14 +231,29 @@ static int temac_dma_bd_init(struct net_device *ndev) int i; lp->rx_skb = kzalloc(sizeof(*lp->rx_skb) * RX_BD_NUM, GFP_KERNEL); + if (!lp->rx_skb) { + dev_err(&ndev->dev, + "can't allocate memory for DMA RX buffer\n"); + goto out; + } /* allocate the tx and rx ring buffer descriptors. */ /* returns a virtual addres and a physical address. */ lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, sizeof(*lp->tx_bd_v) * TX_BD_NUM, &lp->tx_bd_p, GFP_KERNEL); + if (!lp->tx_bd_v) { + dev_err(&ndev->dev, + "unable to allocate DMA TX buffer descriptors"); + goto out; + } lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, sizeof(*lp->rx_bd_v) * RX_BD_NUM, &lp->rx_bd_p, GFP_KERNEL); + if (!lp->rx_bd_v) { + dev_err(&ndev->dev, + "unable to allocate DMA RX buffer descriptors"); + goto out; + } memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM); for (i = 0; i < TX_BD_NUM; i++) { @@ -227,7 +271,7 @@ static int temac_dma_bd_init(struct net_device *ndev) if (skb == 0) { dev_err(&ndev->dev, "alloc_skb error %d\n", i); - return -1; + goto out; } lp->rx_skb[i] = skb; /* returns physical address of skb->data */ @@ -258,6 +302,10 @@ static int temac_dma_bd_init(struct net_device *ndev) lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p); return 0; + +out: + temac_dma_bd_release(ndev); + return -ENOMEM; } /* --------------------------------------------------------------------- @@ -505,7 +553,10 @@ static void temac_device_reset(struct net_device *ndev) } lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE); - temac_dma_bd_init(ndev); + if (temac_dma_bd_init(ndev)) { + dev_err(&ndev->dev, + "temac_device_reset descriptor allocation failed\n"); + } temac_indirect_out32(lp, XTE_RXC0_OFFSET, 0); temac_indirect_out32(lp, XTE_RXC1_OFFSET, 0); @@ -837,6 +888,8 @@ static int temac_stop(struct net_device *ndev) phy_disconnect(lp->phy_dev); lp->phy_dev = NULL; + temac_dma_bd_release(ndev); + return 0; } @@ -862,6 +915,7 @@ static const struct net_device_ops temac_netdev_ops = { .ndo_stop = temac_stop, .ndo_start_xmit = temac_start_xmit, .ndo_set_mac_address = netdev_set_mac_address, + .ndo_validate_addr = eth_validate_addr, //.ndo_set_multicast_list = temac_set_multicast_list, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = temac_poll_controller, @@ -978,19 +1032,22 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match) dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs); } else { dev_err(&op->dev, "unable to map DMA registers\n"); + of_node_put(np); goto err_iounmap; } } lp->rx_irq = irq_of_parse_and_map(np, 0); lp->tx_irq = irq_of_parse_and_map(np, 1); + + of_node_put(np); /* Finished with the DMA node; drop the reference */ + if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) { dev_err(&op->dev, "could not determine irqs\n"); rc = -ENOMEM; goto err_iounmap_2; } - of_node_put(np); /* Finished with the DMA node; drop the reference */ /* Retrieve the MAC address */ addr = of_get_property(op->dev.of_node, "local-mac-address", &size); |