Commit a7642009 authored by Vince Bridgers's avatar Vince Bridgers Committed by David S. Miller

Altera TSE: Fix Panic in probe routine when phy probe fails

This patch addresses a fault in the error recovery path of the probe
routine where the netdev structure was not being unregistered properly
leading to a panic only when the phy probe failed.

Abbreviated panic stack seen is as follows:

(free_netdev+0xXX) from (altera_tse_probe+0xXX)
(altera_tse_probe+0xXX) from (platform_drv_probe+0xXX)
(platform_drv_probe+0xXX) from (driver_probe_device+0xXX)
(driver_probe_device+0xXX) from (__driver_attach+0xXX)
(__driver_attach+0xXX) from (bus_for_each_dev+0xXX)
(bus_for_each_dev+0xXX) from (driver_attach+0xXX)
(driver_attach+0xXX) from (bus_add_driver+0xXX)
(bus_add_driver+0xXX) from (driver_register+0xXX)
(driver_register+0xXX) from (__platform_driver_register+0xXX)
(__platform_driver_register+0xXX) from (altera_tse_driver_init+0xXX)
(altera_tse_driver_init+0xXX) from (do_one_initcall+0xXX)
(do_one_initcall+0xXX) from (kernel_init_freeable+0xXX)
(kernel_init_freeable+0xXX) from (kernel_init+0xXX)
(kernel_init+0xXX) from (ret_from_fork+0xXX)
Signed-off-by: default avatarVince Bridgers <vbridgers2013@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5aec4ee3
...@@ -1245,7 +1245,7 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1245,7 +1245,7 @@ static int altera_tse_probe(struct platform_device *pdev)
/* Get the mapped address to the SGDMA descriptor memory */ /* Get the mapped address to the SGDMA descriptor memory */
ret = request_and_map(pdev, "s1", &dma_res, &descmap); ret = request_and_map(pdev, "s1", &dma_res, &descmap);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
/* Start of that memory is for transmit descriptors */ /* Start of that memory is for transmit descriptors */
priv->tx_dma_desc = descmap; priv->tx_dma_desc = descmap;
...@@ -1264,24 +1264,24 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1264,24 +1264,24 @@ static int altera_tse_probe(struct platform_device *pdev)
if (upper_32_bits(priv->rxdescmem_busaddr)) { if (upper_32_bits(priv->rxdescmem_busaddr)) {
dev_dbg(priv->device, dev_dbg(priv->device,
"SGDMA bus addresses greater than 32-bits\n"); "SGDMA bus addresses greater than 32-bits\n");
goto out_free; goto err_free_netdev;
} }
if (upper_32_bits(priv->txdescmem_busaddr)) { if (upper_32_bits(priv->txdescmem_busaddr)) {
dev_dbg(priv->device, dev_dbg(priv->device,
"SGDMA bus addresses greater than 32-bits\n"); "SGDMA bus addresses greater than 32-bits\n");
goto out_free; goto err_free_netdev;
} }
} else if (priv->dmaops && } else if (priv->dmaops &&
priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) { priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) {
ret = request_and_map(pdev, "rx_resp", &dma_res, ret = request_and_map(pdev, "rx_resp", &dma_res,
&priv->rx_dma_resp); &priv->rx_dma_resp);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
ret = request_and_map(pdev, "tx_desc", &dma_res, ret = request_and_map(pdev, "tx_desc", &dma_res,
&priv->tx_dma_desc); &priv->tx_dma_desc);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
priv->txdescmem = resource_size(dma_res); priv->txdescmem = resource_size(dma_res);
priv->txdescmem_busaddr = dma_res->start; priv->txdescmem_busaddr = dma_res->start;
...@@ -1289,13 +1289,13 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1289,13 +1289,13 @@ static int altera_tse_probe(struct platform_device *pdev)
ret = request_and_map(pdev, "rx_desc", &dma_res, ret = request_and_map(pdev, "rx_desc", &dma_res,
&priv->rx_dma_desc); &priv->rx_dma_desc);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
priv->rxdescmem = resource_size(dma_res); priv->rxdescmem = resource_size(dma_res);
priv->rxdescmem_busaddr = dma_res->start; priv->rxdescmem_busaddr = dma_res->start;
} else { } else {
goto out_free; goto err_free_netdev;
} }
if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask))) if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
...@@ -1304,26 +1304,26 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1304,26 +1304,26 @@ static int altera_tse_probe(struct platform_device *pdev)
else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32)); dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
else else
goto out_free; goto err_free_netdev;
/* MAC address space */ /* MAC address space */
ret = request_and_map(pdev, "control_port", &control_port, ret = request_and_map(pdev, "control_port", &control_port,
(void __iomem **)&priv->mac_dev); (void __iomem **)&priv->mac_dev);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
/* xSGDMA Rx Dispatcher address space */ /* xSGDMA Rx Dispatcher address space */
ret = request_and_map(pdev, "rx_csr", &dma_res, ret = request_and_map(pdev, "rx_csr", &dma_res,
&priv->rx_dma_csr); &priv->rx_dma_csr);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
/* xSGDMA Tx Dispatcher address space */ /* xSGDMA Tx Dispatcher address space */
ret = request_and_map(pdev, "tx_csr", &dma_res, ret = request_and_map(pdev, "tx_csr", &dma_res,
&priv->tx_dma_csr); &priv->tx_dma_csr);
if (ret) if (ret)
goto out_free; goto err_free_netdev;
/* Rx IRQ */ /* Rx IRQ */
...@@ -1331,7 +1331,7 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1331,7 +1331,7 @@ static int altera_tse_probe(struct platform_device *pdev)
if (priv->rx_irq == -ENXIO) { if (priv->rx_irq == -ENXIO) {
dev_err(&pdev->dev, "cannot obtain Rx IRQ\n"); dev_err(&pdev->dev, "cannot obtain Rx IRQ\n");
ret = -ENXIO; ret = -ENXIO;
goto out_free; goto err_free_netdev;
} }
/* Tx IRQ */ /* Tx IRQ */
...@@ -1339,7 +1339,7 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1339,7 +1339,7 @@ static int altera_tse_probe(struct platform_device *pdev)
if (priv->tx_irq == -ENXIO) { if (priv->tx_irq == -ENXIO) {
dev_err(&pdev->dev, "cannot obtain Tx IRQ\n"); dev_err(&pdev->dev, "cannot obtain Tx IRQ\n");
ret = -ENXIO; ret = -ENXIO;
goto out_free; goto err_free_netdev;
} }
/* get FIFO depths from device tree */ /* get FIFO depths from device tree */
...@@ -1347,14 +1347,14 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1347,14 +1347,14 @@ static int altera_tse_probe(struct platform_device *pdev)
&priv->rx_fifo_depth)) { &priv->rx_fifo_depth)) {
dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n"); dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n");
ret = -ENXIO; ret = -ENXIO;
goto out_free; goto err_free_netdev;
} }
if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
&priv->rx_fifo_depth)) { &priv->rx_fifo_depth)) {
dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n"); dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
ret = -ENXIO; ret = -ENXIO;
goto out_free; goto err_free_netdev;
} }
/* get hash filter settings for this instance */ /* get hash filter settings for this instance */
...@@ -1403,7 +1403,7 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1403,7 +1403,7 @@ static int altera_tse_probe(struct platform_device *pdev)
((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) { ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) {
dev_err(&pdev->dev, "invalid phy-addr specified %d\n", dev_err(&pdev->dev, "invalid phy-addr specified %d\n",
priv->phy_addr); priv->phy_addr);
goto out_free; goto err_free_netdev;
} }
/* Create/attach to MDIO bus */ /* Create/attach to MDIO bus */
...@@ -1411,7 +1411,7 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1411,7 +1411,7 @@ static int altera_tse_probe(struct platform_device *pdev)
atomic_add_return(1, &instance_count)); atomic_add_return(1, &instance_count));
if (ret) if (ret)
goto out_free; goto err_free_netdev;
/* initialize netdev */ /* initialize netdev */
ether_setup(ndev); ether_setup(ndev);
...@@ -1448,7 +1448,7 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1448,7 +1448,7 @@ static int altera_tse_probe(struct platform_device *pdev)
ret = register_netdev(ndev); ret = register_netdev(ndev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register TSE net device\n"); dev_err(&pdev->dev, "failed to register TSE net device\n");
goto out_free_mdio; goto err_register_netdev;
} }
platform_set_drvdata(pdev, ndev); platform_set_drvdata(pdev, ndev);
...@@ -1465,13 +1465,16 @@ static int altera_tse_probe(struct platform_device *pdev) ...@@ -1465,13 +1465,16 @@ static int altera_tse_probe(struct platform_device *pdev)
ret = init_phy(ndev); ret = init_phy(ndev);
if (ret != 0) { if (ret != 0) {
netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret); netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret);
goto out_free_mdio; goto err_init_phy;
} }
return 0; return 0;
out_free_mdio: err_init_phy:
unregister_netdev(ndev);
err_register_netdev:
netif_napi_del(&priv->napi);
altera_tse_mdio_destroy(ndev); altera_tse_mdio_destroy(ndev);
out_free: err_free_netdev:
free_netdev(ndev); free_netdev(ndev);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment