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 6474c4973d3..b5c6279cc5a 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);  |