diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2012-02-28 18:40:21 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2012-03-06 13:14:15 -0500 |
commit | dd40781e3a4e9d3177a548c389232ee9496dae8e (patch) | |
tree | 6308028fab5fa47ec105eb77888e3cc8a59b4323 /drivers/net | |
parent | eee6f6a9e0c83811de77a137989d4a3289e297cc (diff) |
sfc: Run event/IRQ self-test asynchronously when interface is brought up
Generate a test event on each event queue whenever the interface is
brought up, then after 1 second check that we have either handled a
test event or handled another IRQ for each event queue.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/selftest.c | 35 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/selftest.h | 3 |
7 files changed, 51 insertions, 7 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 00e13ab080e6..7683e53fda1d 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "net_driver.h" | 25 | #include "net_driver.h" |
26 | #include "efx.h" | 26 | #include "efx.h" |
27 | #include "nic.h" | 27 | #include "nic.h" |
28 | #include "selftest.h" | ||
28 | 29 | ||
29 | #include "mcdi.h" | 30 | #include "mcdi.h" |
30 | #include "workarounds.h" | 31 | #include "workarounds.h" |
@@ -1564,8 +1565,9 @@ static void efx_start_all(struct efx_nic *efx) | |||
1564 | * since we're holding the rtnl_lock at this point. */ | 1565 | * since we're holding the rtnl_lock at this point. */ |
1565 | static void efx_flush_all(struct efx_nic *efx) | 1566 | static void efx_flush_all(struct efx_nic *efx) |
1566 | { | 1567 | { |
1567 | /* Make sure the hardware monitor is stopped */ | 1568 | /* Make sure the hardware monitor and event self-test are stopped */ |
1568 | cancel_delayed_work_sync(&efx->monitor_work); | 1569 | cancel_delayed_work_sync(&efx->monitor_work); |
1570 | efx_selftest_async_cancel(efx); | ||
1569 | /* Stop scheduled port reconfigurations */ | 1571 | /* Stop scheduled port reconfigurations */ |
1570 | cancel_work_sync(&efx->mac_work); | 1572 | cancel_work_sync(&efx->mac_work); |
1571 | } | 1573 | } |
@@ -1825,6 +1827,7 @@ static int efx_net_open(struct net_device *net_dev) | |||
1825 | efx_link_status_changed(efx); | 1827 | efx_link_status_changed(efx); |
1826 | 1828 | ||
1827 | efx_start_all(efx); | 1829 | efx_start_all(efx); |
1830 | efx_selftest_async_start(efx); | ||
1828 | return 0; | 1831 | return 0; |
1829 | } | 1832 | } |
1830 | 1833 | ||
@@ -2375,6 +2378,7 @@ static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, | |||
2375 | #endif | 2378 | #endif |
2376 | INIT_WORK(&efx->reset_work, efx_reset_work); | 2379 | INIT_WORK(&efx->reset_work, efx_reset_work); |
2377 | INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); | 2380 | INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); |
2381 | INIT_DELAYED_WORK(&efx->selftest_work, efx_selftest_async_work); | ||
2378 | efx->pci_dev = pci_dev; | 2382 | efx->pci_dev = pci_dev; |
2379 | efx->msg_enable = debug; | 2383 | efx->msg_enable = debug; |
2380 | efx->state = STATE_INIT; | 2384 | efx->state = STATE_INIT; |
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 4debfe07fb88..be8f9158a714 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h | |||
@@ -148,7 +148,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel) | |||
148 | 148 | ||
149 | static inline void efx_schedule_channel_irq(struct efx_channel *channel) | 149 | static inline void efx_schedule_channel_irq(struct efx_channel *channel) |
150 | { | 150 | { |
151 | channel->last_irq_cpu = raw_smp_processor_id(); | 151 | channel->event_test_cpu = raw_smp_processor_id(); |
152 | efx_schedule_channel(channel); | 152 | efx_schedule_channel(channel); |
153 | } | 153 | } |
154 | 154 | ||
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 0b95505e8968..27fe85fd4ba3 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h | |||
@@ -325,7 +325,7 @@ enum efx_rx_alloc_method { | |||
325 | * @eventq_mask: Event queue pointer mask | 325 | * @eventq_mask: Event queue pointer mask |
326 | * @eventq_read_ptr: Event queue read pointer | 326 | * @eventq_read_ptr: Event queue read pointer |
327 | * @last_eventq_read_ptr: Last event queue read pointer value. | 327 | * @last_eventq_read_ptr: Last event queue read pointer value. |
328 | * @last_irq_cpu: Last CPU to handle interrupt for this channel | 328 | * @event_test_cpu: Last CPU to handle interrupt or test event for this channel |
329 | * @irq_count: Number of IRQs since last adaptive moderation decision | 329 | * @irq_count: Number of IRQs since last adaptive moderation decision |
330 | * @irq_mod_score: IRQ moderation score | 330 | * @irq_mod_score: IRQ moderation score |
331 | * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors | 331 | * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors |
@@ -356,8 +356,8 @@ struct efx_channel { | |||
356 | unsigned int eventq_mask; | 356 | unsigned int eventq_mask; |
357 | unsigned int eventq_read_ptr; | 357 | unsigned int eventq_read_ptr; |
358 | unsigned int last_eventq_read_ptr; | 358 | unsigned int last_eventq_read_ptr; |
359 | int event_test_cpu; | ||
359 | 360 | ||
360 | int last_irq_cpu; | ||
361 | unsigned int irq_count; | 361 | unsigned int irq_count; |
362 | unsigned int irq_mod_score; | 362 | unsigned int irq_mod_score; |
363 | #ifdef CONFIG_RFS_ACCEL | 363 | #ifdef CONFIG_RFS_ACCEL |
@@ -678,6 +678,7 @@ struct vfdi_status; | |||
678 | * @irq_status: Interrupt status buffer | 678 | * @irq_status: Interrupt status buffer |
679 | * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0 | 679 | * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0 |
680 | * @irq_level: IRQ level/index for IRQs not triggered by an event queue | 680 | * @irq_level: IRQ level/index for IRQs not triggered by an event queue |
681 | * @selftest_work: Work item for asynchronous self-test | ||
681 | * @mtd_list: List of MTDs attached to the NIC | 682 | * @mtd_list: List of MTDs attached to the NIC |
682 | * @nic_data: Hardware dependent state | 683 | * @nic_data: Hardware dependent state |
683 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, | 684 | * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, |
@@ -791,6 +792,7 @@ struct efx_nic { | |||
791 | struct efx_buffer irq_status; | 792 | struct efx_buffer irq_status; |
792 | unsigned irq_zero_count; | 793 | unsigned irq_zero_count; |
793 | unsigned irq_level; | 794 | unsigned irq_level; |
795 | struct delayed_work selftest_work; | ||
794 | 796 | ||
795 | #ifdef CONFIG_SFC_MTD | 797 | #ifdef CONFIG_SFC_MTD |
796 | struct list_head mtd_list; | 798 | struct list_head mtd_list; |
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 4c47b7569145..4a9a5beec8fc 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c | |||
@@ -1083,7 +1083,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) | |||
1083 | code = _EFX_CHANNEL_MAGIC_CODE(magic); | 1083 | code = _EFX_CHANNEL_MAGIC_CODE(magic); |
1084 | 1084 | ||
1085 | if (magic == EFX_CHANNEL_MAGIC_TEST(channel)) { | 1085 | if (magic == EFX_CHANNEL_MAGIC_TEST(channel)) { |
1086 | /* ignore */ | 1086 | channel->event_test_cpu = raw_smp_processor_id(); |
1087 | } else if (rx_queue && magic == EFX_CHANNEL_MAGIC_FILL(rx_queue)) { | 1087 | } else if (rx_queue && magic == EFX_CHANNEL_MAGIC_FILL(rx_queue)) { |
1088 | /* The queue must be empty, so we won't receive any rx | 1088 | /* The queue must be empty, so we won't receive any rx |
1089 | * events, so efx_process_channel() won't refill the | 1089 | * events, so efx_process_channel() won't refill the |
@@ -1334,7 +1334,7 @@ void efx_nic_remove_eventq(struct efx_channel *channel) | |||
1334 | 1334 | ||
1335 | void efx_nic_event_test_start(struct efx_channel *channel) | 1335 | void efx_nic_event_test_start(struct efx_channel *channel) |
1336 | { | 1336 | { |
1337 | channel->last_irq_cpu = -1; | 1337 | channel->event_test_cpu = -1; |
1338 | smp_wmb(); | 1338 | smp_wmb(); |
1339 | efx_magic_event(channel, EFX_CHANNEL_MAGIC_TEST(channel)); | 1339 | efx_magic_event(channel, EFX_CHANNEL_MAGIC_TEST(channel)); |
1340 | } | 1340 | } |
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index e0e8596f4d10..f46e2cea8ca9 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h | |||
@@ -311,7 +311,7 @@ extern void falcon_irq_ack_a1(struct efx_nic *efx); | |||
311 | 311 | ||
312 | static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel) | 312 | static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel) |
313 | { | 313 | { |
314 | return ACCESS_ONCE(channel->last_irq_cpu); | 314 | return ACCESS_ONCE(channel->event_test_cpu); |
315 | } | 315 | } |
316 | static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx) | 316 | static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx) |
317 | { | 317 | { |
diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index aa4ab53cac57..de4c0069f5b2 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c | |||
@@ -702,6 +702,8 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
702 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; | 702 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; |
703 | int rc_test = 0, rc_reset = 0, rc; | 703 | int rc_test = 0, rc_reset = 0, rc; |
704 | 704 | ||
705 | efx_selftest_async_cancel(efx); | ||
706 | |||
705 | /* Online (i.e. non-disruptive) testing | 707 | /* Online (i.e. non-disruptive) testing |
706 | * This checks interrupt generation, event delivery and PHY presence. */ | 708 | * This checks interrupt generation, event delivery and PHY presence. */ |
707 | 709 | ||
@@ -794,3 +796,36 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
794 | return rc_test; | 796 | return rc_test; |
795 | } | 797 | } |
796 | 798 | ||
799 | void efx_selftest_async_start(struct efx_nic *efx) | ||
800 | { | ||
801 | struct efx_channel *channel; | ||
802 | |||
803 | efx_for_each_channel(channel, efx) | ||
804 | efx_nic_event_test_start(channel); | ||
805 | schedule_delayed_work(&efx->selftest_work, IRQ_TIMEOUT); | ||
806 | } | ||
807 | |||
808 | void efx_selftest_async_cancel(struct efx_nic *efx) | ||
809 | { | ||
810 | cancel_delayed_work_sync(&efx->selftest_work); | ||
811 | } | ||
812 | |||
813 | void efx_selftest_async_work(struct work_struct *data) | ||
814 | { | ||
815 | struct efx_nic *efx = container_of(data, struct efx_nic, | ||
816 | selftest_work.work); | ||
817 | struct efx_channel *channel; | ||
818 | int cpu; | ||
819 | |||
820 | efx_for_each_channel(channel, efx) { | ||
821 | cpu = efx_nic_event_test_irq_cpu(channel); | ||
822 | if (cpu < 0) | ||
823 | netif_err(efx, ifup, efx->net_dev, | ||
824 | "channel %d failed to trigger an interrupt\n", | ||
825 | channel->channel); | ||
826 | else | ||
827 | netif_dbg(efx, ifup, efx->net_dev, | ||
828 | "channel %d triggered interrupt on CPU %d\n", | ||
829 | channel->channel, cpu); | ||
830 | } | ||
831 | } | ||
diff --git a/drivers/net/ethernet/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h index 87abe2a53846..aed24b736059 100644 --- a/drivers/net/ethernet/sfc/selftest.h +++ b/drivers/net/ethernet/sfc/selftest.h | |||
@@ -48,5 +48,8 @@ extern void efx_loopback_rx_packet(struct efx_nic *efx, | |||
48 | extern int efx_selftest(struct efx_nic *efx, | 48 | extern int efx_selftest(struct efx_nic *efx, |
49 | struct efx_self_tests *tests, | 49 | struct efx_self_tests *tests, |
50 | unsigned flags); | 50 | unsigned flags); |
51 | extern void efx_selftest_async_start(struct efx_nic *efx); | ||
52 | extern void efx_selftest_async_cancel(struct efx_nic *efx); | ||
53 | extern void efx_selftest_async_work(struct work_struct *data); | ||
51 | 54 | ||
52 | #endif /* EFX_SELFTEST_H */ | 55 | #endif /* EFX_SELFTEST_H */ |