aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2011-06-24 15:46:31 -0400
committerBen Hutchings <bhutchings@solarflare.com>2011-06-24 19:43:48 -0400
commita7d529ae2158b5300e4aa16c21f1828bc864449b (patch)
tree8a4442da3d52682945579ce76a9c075cf41a110b
parent4017dbdc14af1903dc9fcba4d08b89c02325069d (diff)
sfc: Allow resets to be upgraded; use atomic ops for safety
Currently an attempt to schedule any reset is ignored if a reset is already pending. This ignores the relative scopes - if the requested reset is greater in scope then the scheduled reset should be upgraded accordingly. There are also some race conditions which could lead to a reset request being lost. Deal with them by using atomic operations on a bitmask. This also makes tests on reset_pending easier to get right. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/sfc/efx.c38
-rw-r--r--drivers/net/sfc/enum.h3
-rw-r--r--drivers/net/sfc/falcon.c2
-rw-r--r--drivers/net/sfc/net_driver.h4
4 files changed, 22 insertions, 25 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index c914729f9554..9b4cfdb09516 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -229,8 +229,7 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
229 struct efx_nic *efx = channel->efx; 229 struct efx_nic *efx = channel->efx;
230 int spent; 230 int spent;
231 231
232 if (unlikely(efx->reset_pending != RESET_TYPE_NONE || 232 if (unlikely(efx->reset_pending || !channel->enabled))
233 !channel->enabled))
234 return 0; 233 return 0;
235 234
236 spent = efx_nic_process_eventq(channel, budget); 235 spent = efx_nic_process_eventq(channel, budget);
@@ -1461,7 +1460,7 @@ static void efx_start_all(struct efx_nic *efx)
1461 * reset_pending [modified from an atomic context], we instead guarantee 1460 * reset_pending [modified from an atomic context], we instead guarantee
1462 * that efx_mcdi_mode_poll() isn't reverted erroneously */ 1461 * that efx_mcdi_mode_poll() isn't reverted erroneously */
1463 efx_mcdi_mode_event(efx); 1462 efx_mcdi_mode_event(efx);
1464 if (efx->reset_pending != RESET_TYPE_NONE) 1463 if (efx->reset_pending)
1465 efx_mcdi_mode_poll(efx); 1464 efx_mcdi_mode_poll(efx);
1466 1465
1467 /* Start the hardware monitor if there is one. Otherwise (we're link 1466 /* Start the hardware monitor if there is one. Otherwise (we're link
@@ -2118,8 +2117,10 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
2118 goto out; 2117 goto out;
2119 } 2118 }
2120 2119
2121 /* Allow resets to be rescheduled. */ 2120 /* Clear flags for the scopes we covered. We assume the NIC and
2122 efx->reset_pending = RESET_TYPE_NONE; 2121 * driver are now quiescent so that there is no race here.
2122 */
2123 efx->reset_pending &= -(1 << (method + 1));
2123 2124
2124 /* Reinitialise bus-mastering, which may have been turned off before 2125 /* Reinitialise bus-mastering, which may have been turned off before
2125 * the reset was scheduled. This is still appropriate, even in the 2126 * the reset was scheduled. This is still appropriate, even in the
@@ -2154,12 +2155,13 @@ out:
2154static void efx_reset_work(struct work_struct *data) 2155static void efx_reset_work(struct work_struct *data)
2155{ 2156{
2156 struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); 2157 struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
2158 unsigned long pending = ACCESS_ONCE(efx->reset_pending);
2157 2159
2158 if (efx->reset_pending == RESET_TYPE_NONE) 2160 if (!pending)
2159 return; 2161 return;
2160 2162
2161 /* If we're not RUNNING then don't reset. Leave the reset_pending 2163 /* If we're not RUNNING then don't reset. Leave the reset_pending
2162 * flag set so that efx_pci_probe_main will be retried */ 2164 * flags set so that efx_pci_probe_main will be retried */
2163 if (efx->state != STATE_RUNNING) { 2165 if (efx->state != STATE_RUNNING) {
2164 netif_info(efx, drv, efx->net_dev, 2166 netif_info(efx, drv, efx->net_dev,
2165 "scheduled reset quenched. NIC not RUNNING\n"); 2167 "scheduled reset quenched. NIC not RUNNING\n");
@@ -2167,7 +2169,7 @@ static void efx_reset_work(struct work_struct *data)
2167 } 2169 }
2168 2170
2169 rtnl_lock(); 2171 rtnl_lock();
2170 (void)efx_reset(efx, efx->reset_pending); 2172 (void)efx_reset(efx, fls(pending) - 1);
2171 rtnl_unlock(); 2173 rtnl_unlock();
2172} 2174}
2173 2175
@@ -2175,12 +2177,6 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
2175{ 2177{
2176 enum reset_type method; 2178 enum reset_type method;
2177 2179
2178 if (efx->reset_pending != RESET_TYPE_NONE) {
2179 netif_info(efx, drv, efx->net_dev,
2180 "quenching already scheduled reset\n");
2181 return;
2182 }
2183
2184 switch (type) { 2180 switch (type) {
2185 case RESET_TYPE_INVISIBLE: 2181 case RESET_TYPE_INVISIBLE:
2186 case RESET_TYPE_ALL: 2182 case RESET_TYPE_ALL:
@@ -2208,7 +2204,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
2208 netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n", 2204 netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
2209 RESET_TYPE(method)); 2205 RESET_TYPE(method));
2210 2206
2211 efx->reset_pending = method; 2207 set_bit(method, &efx->reset_pending);
2212 2208
2213 /* efx_process_channel() will no longer read events once a 2209 /* efx_process_channel() will no longer read events once a
2214 * reset is scheduled. So switch back to poll'd MCDI completions. */ 2210 * reset is scheduled. So switch back to poll'd MCDI completions. */
@@ -2288,7 +2284,6 @@ static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type,
2288 efx->pci_dev = pci_dev; 2284 efx->pci_dev = pci_dev;
2289 efx->msg_enable = debug; 2285 efx->msg_enable = debug;
2290 efx->state = STATE_INIT; 2286 efx->state = STATE_INIT;
2291 efx->reset_pending = RESET_TYPE_NONE;
2292 strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); 2287 strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
2293 2288
2294 efx->net_dev = net_dev; 2289 efx->net_dev = net_dev;
@@ -2510,7 +2505,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
2510 cancel_work_sync(&efx->reset_work); 2505 cancel_work_sync(&efx->reset_work);
2511 2506
2512 if (rc == 0) { 2507 if (rc == 0) {
2513 if (efx->reset_pending != RESET_TYPE_NONE) { 2508 if (efx->reset_pending) {
2514 /* If there was a scheduled reset during 2509 /* If there was a scheduled reset during
2515 * probe, the NIC is probably hosed anyway */ 2510 * probe, the NIC is probably hosed anyway */
2516 efx_pci_remove_main(efx); 2511 efx_pci_remove_main(efx);
@@ -2521,11 +2516,12 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
2521 } 2516 }
2522 2517
2523 /* Retry if a recoverably reset event has been scheduled */ 2518 /* Retry if a recoverably reset event has been scheduled */
2524 if ((efx->reset_pending != RESET_TYPE_INVISIBLE) && 2519 if (efx->reset_pending &
2525 (efx->reset_pending != RESET_TYPE_ALL)) 2520 ~(1 << RESET_TYPE_INVISIBLE | 1 << RESET_TYPE_ALL) ||
2521 !efx->reset_pending)
2526 goto fail3; 2522 goto fail3;
2527 2523
2528 efx->reset_pending = RESET_TYPE_NONE; 2524 efx->reset_pending = 0;
2529 } 2525 }
2530 2526
2531 if (rc) { 2527 if (rc) {
@@ -2609,7 +2605,7 @@ static int efx_pm_poweroff(struct device *dev)
2609 2605
2610 efx->type->fini(efx); 2606 efx->type->fini(efx);
2611 2607
2612 efx->reset_pending = RESET_TYPE_NONE; 2608 efx->reset_pending = 0;
2613 2609
2614 pci_save_state(pci_dev); 2610 pci_save_state(pci_dev);
2615 return pci_set_power_state(pci_dev, PCI_D3hot); 2611 return pci_set_power_state(pci_dev, PCI_D3hot);
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
index 384cfe3b1be1..d725a8fbe1a6 100644
--- a/drivers/net/sfc/enum.h
+++ b/drivers/net/sfc/enum.h
@@ -134,6 +134,8 @@ enum efx_loopback_mode {
134 * other valuesspecify reasons, which efx_schedule_reset() will choose 134 * other valuesspecify reasons, which efx_schedule_reset() will choose
135 * a method for. 135 * a method for.
136 * 136 *
137 * Reset methods are numbered in order of increasing scope.
138 *
137 * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts 139 * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
138 * @RESET_TYPE_ALL: reset everything but PCI core blocks 140 * @RESET_TYPE_ALL: reset everything but PCI core blocks
139 * @RESET_TYPE_WORLD: reset everything, save & restore PCI config 141 * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
@@ -147,7 +149,6 @@ enum efx_loopback_mode {
147 * @RESET_TYPE_MC_FAILURE: MC reboot/assertion 149 * @RESET_TYPE_MC_FAILURE: MC reboot/assertion
148 */ 150 */
149enum reset_type { 151enum reset_type {
150 RESET_TYPE_NONE = -1,
151 RESET_TYPE_INVISIBLE = 0, 152 RESET_TYPE_INVISIBLE = 0,
152 RESET_TYPE_ALL = 1, 153 RESET_TYPE_ALL = 1,
153 RESET_TYPE_WORLD = 2, 154 RESET_TYPE_WORLD = 2,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 60176e873d62..a4c7830ec9b0 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -536,7 +536,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
536 efx_oword_t reg; 536 efx_oword_t reg;
537 int link_speed, isolate; 537 int link_speed, isolate;
538 538
539 isolate = (efx->reset_pending != RESET_TYPE_NONE); 539 isolate = !!ACCESS_ONCE(efx->reset_pending);
540 540
541 switch (link_state->speed) { 541 switch (link_state->speed) {
542 case 10000: link_speed = 3; break; 542 case 10000: link_speed = 3; break;
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index e8d5f03a89fe..c422eb2ce60a 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -645,7 +645,7 @@ struct efx_filter_state;
645 * @irq_rx_moderation: IRQ moderation time for RX event queues 645 * @irq_rx_moderation: IRQ moderation time for RX event queues
646 * @msg_enable: Log message enable flags 646 * @msg_enable: Log message enable flags
647 * @state: Device state flag. Serialised by the rtnl_lock. 647 * @state: Device state flag. Serialised by the rtnl_lock.
648 * @reset_pending: Pending reset method (normally RESET_TYPE_NONE) 648 * @reset_pending: Bitmask for pending resets
649 * @tx_queue: TX DMA queues 649 * @tx_queue: TX DMA queues
650 * @rx_queue: RX DMA queues 650 * @rx_queue: RX DMA queues
651 * @channel: Channels 651 * @channel: Channels
@@ -728,7 +728,7 @@ struct efx_nic {
728 u32 msg_enable; 728 u32 msg_enable;
729 729
730 enum nic_state state; 730 enum nic_state state;
731 enum reset_type reset_pending; 731 unsigned long reset_pending;
732 732
733 struct efx_channel *channel[EFX_MAX_CHANNELS]; 733 struct efx_channel *channel[EFX_MAX_CHANNELS];
734 char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6]; 734 char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6];