diff options
author | Vince Bridgers <vbridger@altera.com> | 2014-04-24 17:58:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-04-26 12:26:26 -0400 |
commit | a76420092d3d9f2e52ad7469c210c0e2fa962fe4 (patch) | |
tree | 65c8efdbdc2618ae5f892ca99d5daaa7141a224f /drivers/net | |
parent | 5aec4ee3724ad93ee63cafc6f6b5f9cd40adda52 (diff) |
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: Vince Bridgers <vbridgers2013@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/altera/altera_tse_main.c | 45 |
1 files changed, 24 insertions, 21 deletions
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 63712830b333..e44a4aeb9701 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c | |||
@@ -1245,7 +1245,7 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1245 | /* Get the mapped address to the SGDMA descriptor memory */ | 1245 | /* Get the mapped address to the SGDMA descriptor memory */ |
1246 | ret = request_and_map(pdev, "s1", &dma_res, &descmap); | 1246 | ret = request_and_map(pdev, "s1", &dma_res, &descmap); |
1247 | if (ret) | 1247 | if (ret) |
1248 | goto out_free; | 1248 | goto err_free_netdev; |
1249 | 1249 | ||
1250 | /* Start of that memory is for transmit descriptors */ | 1250 | /* Start of that memory is for transmit descriptors */ |
1251 | priv->tx_dma_desc = descmap; | 1251 | priv->tx_dma_desc = descmap; |
@@ -1264,24 +1264,24 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1264 | if (upper_32_bits(priv->rxdescmem_busaddr)) { | 1264 | if (upper_32_bits(priv->rxdescmem_busaddr)) { |
1265 | dev_dbg(priv->device, | 1265 | dev_dbg(priv->device, |
1266 | "SGDMA bus addresses greater than 32-bits\n"); | 1266 | "SGDMA bus addresses greater than 32-bits\n"); |
1267 | goto out_free; | 1267 | goto err_free_netdev; |
1268 | } | 1268 | } |
1269 | if (upper_32_bits(priv->txdescmem_busaddr)) { | 1269 | if (upper_32_bits(priv->txdescmem_busaddr)) { |
1270 | dev_dbg(priv->device, | 1270 | dev_dbg(priv->device, |
1271 | "SGDMA bus addresses greater than 32-bits\n"); | 1271 | "SGDMA bus addresses greater than 32-bits\n"); |
1272 | goto out_free; | 1272 | goto err_free_netdev; |
1273 | } | 1273 | } |
1274 | } else if (priv->dmaops && | 1274 | } else if (priv->dmaops && |
1275 | priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) { | 1275 | priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) { |
1276 | ret = request_and_map(pdev, "rx_resp", &dma_res, | 1276 | ret = request_and_map(pdev, "rx_resp", &dma_res, |
1277 | &priv->rx_dma_resp); | 1277 | &priv->rx_dma_resp); |
1278 | if (ret) | 1278 | if (ret) |
1279 | goto out_free; | 1279 | goto err_free_netdev; |
1280 | 1280 | ||
1281 | ret = request_and_map(pdev, "tx_desc", &dma_res, | 1281 | ret = request_and_map(pdev, "tx_desc", &dma_res, |
1282 | &priv->tx_dma_desc); | 1282 | &priv->tx_dma_desc); |
1283 | if (ret) | 1283 | if (ret) |
1284 | goto out_free; | 1284 | goto err_free_netdev; |
1285 | 1285 | ||
1286 | priv->txdescmem = resource_size(dma_res); | 1286 | priv->txdescmem = resource_size(dma_res); |
1287 | priv->txdescmem_busaddr = dma_res->start; | 1287 | priv->txdescmem_busaddr = dma_res->start; |
@@ -1289,13 +1289,13 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1289 | ret = request_and_map(pdev, "rx_desc", &dma_res, | 1289 | ret = request_and_map(pdev, "rx_desc", &dma_res, |
1290 | &priv->rx_dma_desc); | 1290 | &priv->rx_dma_desc); |
1291 | if (ret) | 1291 | if (ret) |
1292 | goto out_free; | 1292 | goto err_free_netdev; |
1293 | 1293 | ||
1294 | priv->rxdescmem = resource_size(dma_res); | 1294 | priv->rxdescmem = resource_size(dma_res); |
1295 | priv->rxdescmem_busaddr = dma_res->start; | 1295 | priv->rxdescmem_busaddr = dma_res->start; |
1296 | 1296 | ||
1297 | } else { | 1297 | } else { |
1298 | goto out_free; | 1298 | goto err_free_netdev; |
1299 | } | 1299 | } |
1300 | 1300 | ||
1301 | if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask))) | 1301 | 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 | else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) | 1304 | else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) |
1305 | dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32)); | 1305 | dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32)); |
1306 | else | 1306 | else |
1307 | goto out_free; | 1307 | goto err_free_netdev; |
1308 | 1308 | ||
1309 | /* MAC address space */ | 1309 | /* MAC address space */ |
1310 | ret = request_and_map(pdev, "control_port", &control_port, | 1310 | ret = request_and_map(pdev, "control_port", &control_port, |
1311 | (void __iomem **)&priv->mac_dev); | 1311 | (void __iomem **)&priv->mac_dev); |
1312 | if (ret) | 1312 | if (ret) |
1313 | goto out_free; | 1313 | goto err_free_netdev; |
1314 | 1314 | ||
1315 | /* xSGDMA Rx Dispatcher address space */ | 1315 | /* xSGDMA Rx Dispatcher address space */ |
1316 | ret = request_and_map(pdev, "rx_csr", &dma_res, | 1316 | ret = request_and_map(pdev, "rx_csr", &dma_res, |
1317 | &priv->rx_dma_csr); | 1317 | &priv->rx_dma_csr); |
1318 | if (ret) | 1318 | if (ret) |
1319 | goto out_free; | 1319 | goto err_free_netdev; |
1320 | 1320 | ||
1321 | 1321 | ||
1322 | /* xSGDMA Tx Dispatcher address space */ | 1322 | /* xSGDMA Tx Dispatcher address space */ |
1323 | ret = request_and_map(pdev, "tx_csr", &dma_res, | 1323 | ret = request_and_map(pdev, "tx_csr", &dma_res, |
1324 | &priv->tx_dma_csr); | 1324 | &priv->tx_dma_csr); |
1325 | if (ret) | 1325 | if (ret) |
1326 | goto out_free; | 1326 | goto err_free_netdev; |
1327 | 1327 | ||
1328 | 1328 | ||
1329 | /* Rx IRQ */ | 1329 | /* Rx IRQ */ |
@@ -1331,7 +1331,7 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1331 | if (priv->rx_irq == -ENXIO) { | 1331 | if (priv->rx_irq == -ENXIO) { |
1332 | dev_err(&pdev->dev, "cannot obtain Rx IRQ\n"); | 1332 | dev_err(&pdev->dev, "cannot obtain Rx IRQ\n"); |
1333 | ret = -ENXIO; | 1333 | ret = -ENXIO; |
1334 | goto out_free; | 1334 | goto err_free_netdev; |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | /* Tx IRQ */ | 1337 | /* Tx IRQ */ |
@@ -1339,7 +1339,7 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1339 | if (priv->tx_irq == -ENXIO) { | 1339 | if (priv->tx_irq == -ENXIO) { |
1340 | dev_err(&pdev->dev, "cannot obtain Tx IRQ\n"); | 1340 | dev_err(&pdev->dev, "cannot obtain Tx IRQ\n"); |
1341 | ret = -ENXIO; | 1341 | ret = -ENXIO; |
1342 | goto out_free; | 1342 | goto err_free_netdev; |
1343 | } | 1343 | } |
1344 | 1344 | ||
1345 | /* get FIFO depths from device tree */ | 1345 | /* get FIFO depths from device tree */ |
@@ -1347,14 +1347,14 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1347 | &priv->rx_fifo_depth)) { | 1347 | &priv->rx_fifo_depth)) { |
1348 | dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n"); | 1348 | dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n"); |
1349 | ret = -ENXIO; | 1349 | ret = -ENXIO; |
1350 | goto out_free; | 1350 | goto err_free_netdev; |
1351 | } | 1351 | } |
1352 | 1352 | ||
1353 | if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", | 1353 | if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", |
1354 | &priv->rx_fifo_depth)) { | 1354 | &priv->rx_fifo_depth)) { |
1355 | dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n"); | 1355 | dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n"); |
1356 | ret = -ENXIO; | 1356 | ret = -ENXIO; |
1357 | goto out_free; | 1357 | goto err_free_netdev; |
1358 | } | 1358 | } |
1359 | 1359 | ||
1360 | /* get hash filter settings for this instance */ | 1360 | /* get hash filter settings for this instance */ |
@@ -1403,7 +1403,7 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1403 | ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) { | 1403 | ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) { |
1404 | dev_err(&pdev->dev, "invalid phy-addr specified %d\n", | 1404 | dev_err(&pdev->dev, "invalid phy-addr specified %d\n", |
1405 | priv->phy_addr); | 1405 | priv->phy_addr); |
1406 | goto out_free; | 1406 | goto err_free_netdev; |
1407 | } | 1407 | } |
1408 | 1408 | ||
1409 | /* Create/attach to MDIO bus */ | 1409 | /* Create/attach to MDIO bus */ |
@@ -1411,7 +1411,7 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1411 | atomic_add_return(1, &instance_count)); | 1411 | atomic_add_return(1, &instance_count)); |
1412 | 1412 | ||
1413 | if (ret) | 1413 | if (ret) |
1414 | goto out_free; | 1414 | goto err_free_netdev; |
1415 | 1415 | ||
1416 | /* initialize netdev */ | 1416 | /* initialize netdev */ |
1417 | ether_setup(ndev); | 1417 | ether_setup(ndev); |
@@ -1448,7 +1448,7 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1448 | ret = register_netdev(ndev); | 1448 | ret = register_netdev(ndev); |
1449 | if (ret) { | 1449 | if (ret) { |
1450 | dev_err(&pdev->dev, "failed to register TSE net device\n"); | 1450 | dev_err(&pdev->dev, "failed to register TSE net device\n"); |
1451 | goto out_free_mdio; | 1451 | goto err_register_netdev; |
1452 | } | 1452 | } |
1453 | 1453 | ||
1454 | platform_set_drvdata(pdev, ndev); | 1454 | platform_set_drvdata(pdev, ndev); |
@@ -1465,13 +1465,16 @@ static int altera_tse_probe(struct platform_device *pdev) | |||
1465 | ret = init_phy(ndev); | 1465 | ret = init_phy(ndev); |
1466 | if (ret != 0) { | 1466 | if (ret != 0) { |
1467 | netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret); | 1467 | netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret); |
1468 | goto out_free_mdio; | 1468 | goto err_init_phy; |
1469 | } | 1469 | } |
1470 | return 0; | 1470 | return 0; |
1471 | 1471 | ||
1472 | out_free_mdio: | 1472 | err_init_phy: |
1473 | unregister_netdev(ndev); | ||
1474 | err_register_netdev: | ||
1475 | netif_napi_del(&priv->napi); | ||
1473 | altera_tse_mdio_destroy(ndev); | 1476 | altera_tse_mdio_destroy(ndev); |
1474 | out_free: | 1477 | err_free_netdev: |
1475 | free_netdev(ndev); | 1478 | free_netdev(ndev); |
1476 | return ret; | 1479 | return ret; |
1477 | } | 1480 | } |