diff options
author | Jon Cooper <jcooper@solarflare.com> | 2013-04-15 13:51:54 -0400 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2013-08-29 13:12:08 -0400 |
commit | 261e4d96b45476fa7386130a309bc15af9eca2e0 (patch) | |
tree | 51f4a3d2a08085c5ea2ec2fc5c39c46bf4568cda | |
parent | b883d0bd4ae91059242fd2f8c2a70f308ef63dc1 (diff) |
sfc: Allow event queue initialisation to fail
On EF10, event queue initialisation requires an MCDI request which
may return failure.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 111 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/farch.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 6 |
4 files changed, 95 insertions, 28 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 69150fa1459b..84c47d3f2b53 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -189,7 +189,7 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); | |||
189 | * | 189 | * |
190 | *************************************************************************/ | 190 | *************************************************************************/ |
191 | 191 | ||
192 | static void efx_soft_enable_interrupts(struct efx_nic *efx); | 192 | static int efx_soft_enable_interrupts(struct efx_nic *efx); |
193 | static void efx_soft_disable_interrupts(struct efx_nic *efx); | 193 | static void efx_soft_disable_interrupts(struct efx_nic *efx); |
194 | static void efx_remove_channel(struct efx_channel *channel); | 194 | static void efx_remove_channel(struct efx_channel *channel); |
195 | static void efx_remove_channels(struct efx_nic *efx); | 195 | static void efx_remove_channels(struct efx_nic *efx); |
@@ -329,15 +329,21 @@ static int efx_probe_eventq(struct efx_channel *channel) | |||
329 | } | 329 | } |
330 | 330 | ||
331 | /* Prepare channel's event queue */ | 331 | /* Prepare channel's event queue */ |
332 | static void efx_init_eventq(struct efx_channel *channel) | 332 | static int efx_init_eventq(struct efx_channel *channel) |
333 | { | 333 | { |
334 | int rc; | ||
335 | |||
336 | EFX_WARN_ON_PARANOID(channel->eventq_init); | ||
337 | |||
334 | netif_dbg(channel->efx, drv, channel->efx->net_dev, | 338 | netif_dbg(channel->efx, drv, channel->efx->net_dev, |
335 | "chan %d init event queue\n", channel->channel); | 339 | "chan %d init event queue\n", channel->channel); |
336 | 340 | ||
337 | channel->eventq_read_ptr = 0; | 341 | rc = efx_nic_init_eventq(channel); |
338 | 342 | if (rc == 0) { | |
339 | efx_nic_init_eventq(channel); | 343 | channel->eventq_read_ptr = 0; |
340 | channel->eventq_init = true; | 344 | channel->eventq_init = true; |
345 | } | ||
346 | return rc; | ||
341 | } | 347 | } |
342 | 348 | ||
343 | /* Enable event queue processing and NAPI */ | 349 | /* Enable event queue processing and NAPI */ |
@@ -722,7 +728,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) | |||
722 | struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; | 728 | struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; |
723 | u32 old_rxq_entries, old_txq_entries; | 729 | u32 old_rxq_entries, old_txq_entries; |
724 | unsigned i, next_buffer_table = 0; | 730 | unsigned i, next_buffer_table = 0; |
725 | int rc; | 731 | int rc, rc2; |
726 | 732 | ||
727 | rc = efx_check_disabled(efx); | 733 | rc = efx_check_disabled(efx); |
728 | if (rc) | 734 | if (rc) |
@@ -802,9 +808,16 @@ out: | |||
802 | } | 808 | } |
803 | } | 809 | } |
804 | 810 | ||
805 | efx_soft_enable_interrupts(efx); | 811 | rc2 = efx_soft_enable_interrupts(efx); |
806 | efx_start_all(efx); | 812 | if (rc2) { |
807 | netif_device_attach(efx->net_dev); | 813 | rc = rc ? rc : rc2; |
814 | netif_err(efx, drv, efx->net_dev, | ||
815 | "unable to restart interrupts on channel reallocation\n"); | ||
816 | efx_schedule_reset(efx, RESET_TYPE_DISABLE); | ||
817 | } else { | ||
818 | efx_start_all(efx); | ||
819 | netif_device_attach(efx->net_dev); | ||
820 | } | ||
808 | return rc; | 821 | return rc; |
809 | 822 | ||
810 | rollback: | 823 | rollback: |
@@ -1327,9 +1340,10 @@ static int efx_probe_interrupts(struct efx_nic *efx) | |||
1327 | return 0; | 1340 | return 0; |
1328 | } | 1341 | } |
1329 | 1342 | ||
1330 | static void efx_soft_enable_interrupts(struct efx_nic *efx) | 1343 | static int efx_soft_enable_interrupts(struct efx_nic *efx) |
1331 | { | 1344 | { |
1332 | struct efx_channel *channel; | 1345 | struct efx_channel *channel, *end_channel; |
1346 | int rc; | ||
1333 | 1347 | ||
1334 | BUG_ON(efx->state == STATE_DISABLED); | 1348 | BUG_ON(efx->state == STATE_DISABLED); |
1335 | 1349 | ||
@@ -1337,12 +1351,28 @@ static void efx_soft_enable_interrupts(struct efx_nic *efx) | |||
1337 | smp_wmb(); | 1351 | smp_wmb(); |
1338 | 1352 | ||
1339 | efx_for_each_channel(channel, efx) { | 1353 | efx_for_each_channel(channel, efx) { |
1340 | if (!channel->type->keep_eventq) | 1354 | if (!channel->type->keep_eventq) { |
1341 | efx_init_eventq(channel); | 1355 | rc = efx_init_eventq(channel); |
1356 | if (rc) | ||
1357 | goto fail; | ||
1358 | } | ||
1342 | efx_start_eventq(channel); | 1359 | efx_start_eventq(channel); |
1343 | } | 1360 | } |
1344 | 1361 | ||
1345 | efx_mcdi_mode_event(efx); | 1362 | efx_mcdi_mode_event(efx); |
1363 | |||
1364 | return 0; | ||
1365 | fail: | ||
1366 | end_channel = channel; | ||
1367 | efx_for_each_channel(channel, efx) { | ||
1368 | if (channel == end_channel) | ||
1369 | break; | ||
1370 | efx_stop_eventq(channel); | ||
1371 | if (!channel->type->keep_eventq) | ||
1372 | efx_fini_eventq(channel); | ||
1373 | } | ||
1374 | |||
1375 | return rc; | ||
1346 | } | 1376 | } |
1347 | 1377 | ||
1348 | static void efx_soft_disable_interrupts(struct efx_nic *efx) | 1378 | static void efx_soft_disable_interrupts(struct efx_nic *efx) |
@@ -1373,9 +1403,10 @@ static void efx_soft_disable_interrupts(struct efx_nic *efx) | |||
1373 | efx_mcdi_flush_async(efx); | 1403 | efx_mcdi_flush_async(efx); |
1374 | } | 1404 | } |
1375 | 1405 | ||
1376 | static void efx_enable_interrupts(struct efx_nic *efx) | 1406 | static int efx_enable_interrupts(struct efx_nic *efx) |
1377 | { | 1407 | { |
1378 | struct efx_channel *channel; | 1408 | struct efx_channel *channel, *end_channel; |
1409 | int rc; | ||
1379 | 1410 | ||
1380 | BUG_ON(efx->state == STATE_DISABLED); | 1411 | BUG_ON(efx->state == STATE_DISABLED); |
1381 | 1412 | ||
@@ -1387,11 +1418,31 @@ static void efx_enable_interrupts(struct efx_nic *efx) | |||
1387 | efx->type->irq_enable_master(efx); | 1418 | efx->type->irq_enable_master(efx); |
1388 | 1419 | ||
1389 | efx_for_each_channel(channel, efx) { | 1420 | efx_for_each_channel(channel, efx) { |
1421 | if (channel->type->keep_eventq) { | ||
1422 | rc = efx_init_eventq(channel); | ||
1423 | if (rc) | ||
1424 | goto fail; | ||
1425 | } | ||
1426 | } | ||
1427 | |||
1428 | rc = efx_soft_enable_interrupts(efx); | ||
1429 | if (rc) | ||
1430 | goto fail; | ||
1431 | |||
1432 | return 0; | ||
1433 | |||
1434 | fail: | ||
1435 | end_channel = channel; | ||
1436 | efx_for_each_channel(channel, efx) { | ||
1437 | if (channel == end_channel) | ||
1438 | break; | ||
1390 | if (channel->type->keep_eventq) | 1439 | if (channel->type->keep_eventq) |
1391 | efx_init_eventq(channel); | 1440 | efx_fini_eventq(channel); |
1392 | } | 1441 | } |
1393 | 1442 | ||
1394 | efx_soft_enable_interrupts(efx); | 1443 | efx->type->irq_disable_non_ev(efx); |
1444 | |||
1445 | return rc; | ||
1395 | } | 1446 | } |
1396 | 1447 | ||
1397 | static void efx_disable_interrupts(struct efx_nic *efx) | 1448 | static void efx_disable_interrupts(struct efx_nic *efx) |
@@ -2205,7 +2256,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) | |||
2205 | "could not restore PHY settings\n"); | 2256 | "could not restore PHY settings\n"); |
2206 | } | 2257 | } |
2207 | 2258 | ||
2208 | efx_enable_interrupts(efx); | 2259 | rc = efx_enable_interrupts(efx); |
2260 | if (rc) | ||
2261 | goto fail; | ||
2209 | efx_restore_filters(efx); | 2262 | efx_restore_filters(efx); |
2210 | efx_sriov_reset(efx); | 2263 | efx_sriov_reset(efx); |
2211 | 2264 | ||
@@ -2649,10 +2702,14 @@ static int efx_pci_probe_main(struct efx_nic *efx) | |||
2649 | rc = efx_nic_init_interrupt(efx); | 2702 | rc = efx_nic_init_interrupt(efx); |
2650 | if (rc) | 2703 | if (rc) |
2651 | goto fail5; | 2704 | goto fail5; |
2652 | efx_enable_interrupts(efx); | 2705 | rc = efx_enable_interrupts(efx); |
2706 | if (rc) | ||
2707 | goto fail6; | ||
2653 | 2708 | ||
2654 | return 0; | 2709 | return 0; |
2655 | 2710 | ||
2711 | fail6: | ||
2712 | efx_nic_fini_interrupt(efx); | ||
2656 | fail5: | 2713 | fail5: |
2657 | efx_fini_port(efx); | 2714 | efx_fini_port(efx); |
2658 | fail4: | 2715 | fail4: |
@@ -2780,12 +2837,15 @@ static int efx_pm_freeze(struct device *dev) | |||
2780 | 2837 | ||
2781 | static int efx_pm_thaw(struct device *dev) | 2838 | static int efx_pm_thaw(struct device *dev) |
2782 | { | 2839 | { |
2840 | int rc; | ||
2783 | struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); | 2841 | struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); |
2784 | 2842 | ||
2785 | rtnl_lock(); | 2843 | rtnl_lock(); |
2786 | 2844 | ||
2787 | if (efx->state != STATE_DISABLED) { | 2845 | if (efx->state != STATE_DISABLED) { |
2788 | efx_enable_interrupts(efx); | 2846 | rc = efx_enable_interrupts(efx); |
2847 | if (rc) | ||
2848 | goto fail; | ||
2789 | 2849 | ||
2790 | mutex_lock(&efx->mac_lock); | 2850 | mutex_lock(&efx->mac_lock); |
2791 | efx->phy_op->reconfigure(efx); | 2851 | efx->phy_op->reconfigure(efx); |
@@ -2806,6 +2866,11 @@ static int efx_pm_thaw(struct device *dev) | |||
2806 | queue_work(reset_workqueue, &efx->reset_work); | 2866 | queue_work(reset_workqueue, &efx->reset_work); |
2807 | 2867 | ||
2808 | return 0; | 2868 | return 0; |
2869 | |||
2870 | fail: | ||
2871 | rtnl_unlock(); | ||
2872 | |||
2873 | return rc; | ||
2809 | } | 2874 | } |
2810 | 2875 | ||
2811 | static int efx_pm_poweroff(struct device *dev) | 2876 | static int efx_pm_poweroff(struct device *dev) |
@@ -2842,8 +2907,8 @@ static int efx_pm_resume(struct device *dev) | |||
2842 | rc = efx->type->init(efx); | 2907 | rc = efx->type->init(efx); |
2843 | if (rc) | 2908 | if (rc) |
2844 | return rc; | 2909 | return rc; |
2845 | efx_pm_thaw(dev); | 2910 | rc = efx_pm_thaw(dev); |
2846 | return 0; | 2911 | return rc; |
2847 | } | 2912 | } |
2848 | 2913 | ||
2849 | static int efx_pm_suspend(struct device *dev) | 2914 | static int efx_pm_suspend(struct device *dev) |
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index d21483dfea40..904af5c336b4 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c | |||
@@ -1325,7 +1325,7 @@ int efx_farch_ev_probe(struct efx_channel *channel) | |||
1325 | entries * sizeof(efx_qword_t)); | 1325 | entries * sizeof(efx_qword_t)); |
1326 | } | 1326 | } |
1327 | 1327 | ||
1328 | void efx_farch_ev_init(struct efx_channel *channel) | 1328 | int efx_farch_ev_init(struct efx_channel *channel) |
1329 | { | 1329 | { |
1330 | efx_oword_t reg; | 1330 | efx_oword_t reg; |
1331 | struct efx_nic *efx = channel->efx; | 1331 | struct efx_nic *efx = channel->efx; |
@@ -1358,6 +1358,8 @@ void efx_farch_ev_init(struct efx_channel *channel) | |||
1358 | channel->channel); | 1358 | channel->channel); |
1359 | 1359 | ||
1360 | efx->type->push_irq_moderation(channel); | 1360 | efx->type->push_irq_moderation(channel); |
1361 | |||
1362 | return 0; | ||
1361 | } | 1363 | } |
1362 | 1364 | ||
1363 | void efx_farch_ev_fini(struct efx_channel *channel) | 1365 | void efx_farch_ev_fini(struct efx_channel *channel) |
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index e85bed09b5e9..54900f3c83b1 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -1087,7 +1087,7 @@ struct efx_nic_type { | |||
1087 | void (*rx_write)(struct efx_rx_queue *rx_queue); | 1087 | void (*rx_write)(struct efx_rx_queue *rx_queue); |
1088 | void (*rx_defer_refill)(struct efx_rx_queue *rx_queue); | 1088 | void (*rx_defer_refill)(struct efx_rx_queue *rx_queue); |
1089 | int (*ev_probe)(struct efx_channel *channel); | 1089 | int (*ev_probe)(struct efx_channel *channel); |
1090 | void (*ev_init)(struct efx_channel *channel); | 1090 | int (*ev_init)(struct efx_channel *channel); |
1091 | void (*ev_fini)(struct efx_channel *channel); | 1091 | void (*ev_fini)(struct efx_channel *channel); |
1092 | void (*ev_remove)(struct efx_channel *channel); | 1092 | void (*ev_remove)(struct efx_channel *channel); |
1093 | int (*ev_process)(struct efx_channel *channel, int quota); | 1093 | int (*ev_process)(struct efx_channel *channel, int quota); |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 9afbf3616b4b..686ce7a677df 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -503,9 +503,9 @@ static inline int efx_nic_probe_eventq(struct efx_channel *channel) | |||
503 | { | 503 | { |
504 | return channel->efx->type->ev_probe(channel); | 504 | return channel->efx->type->ev_probe(channel); |
505 | } | 505 | } |
506 | static inline void efx_nic_init_eventq(struct efx_channel *channel) | 506 | static inline int efx_nic_init_eventq(struct efx_channel *channel) |
507 | { | 507 | { |
508 | channel->efx->type->ev_init(channel); | 508 | return channel->efx->type->ev_init(channel); |
509 | } | 509 | } |
510 | static inline void efx_nic_fini_eventq(struct efx_channel *channel) | 510 | static inline void efx_nic_fini_eventq(struct efx_channel *channel) |
511 | { | 511 | { |
@@ -539,7 +539,7 @@ extern void efx_farch_rx_remove(struct efx_rx_queue *rx_queue); | |||
539 | extern void efx_farch_rx_write(struct efx_rx_queue *rx_queue); | 539 | extern void efx_farch_rx_write(struct efx_rx_queue *rx_queue); |
540 | extern void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue); | 540 | extern void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue); |
541 | extern int efx_farch_ev_probe(struct efx_channel *channel); | 541 | extern int efx_farch_ev_probe(struct efx_channel *channel); |
542 | extern void efx_farch_ev_init(struct efx_channel *channel); | 542 | extern int efx_farch_ev_init(struct efx_channel *channel); |
543 | extern void efx_farch_ev_fini(struct efx_channel *channel); | 543 | extern void efx_farch_ev_fini(struct efx_channel *channel); |
544 | extern void efx_farch_ev_remove(struct efx_channel *channel); | 544 | extern void efx_farch_ev_remove(struct efx_channel *channel); |
545 | extern int efx_farch_ev_process(struct efx_channel *channel, int quota); | 545 | extern int efx_farch_ev_process(struct efx_channel *channel, int quota); |