diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2010-12-07 14:24:45 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2010-12-07 14:30:19 -0500 |
commit | 94dec6a2d20a26a779b63bb584e48db5fb0ddb53 (patch) | |
tree | 3911c0883429411e27f22db1e34436d75fbb937b /drivers/net/sfc/efx.c | |
parent | 46bcf14f44d8f31ecfdc8b6708ec15a3b33316d9 (diff) |
sfc: Fix crash in legacy onterrupt handler during ring reallocation
If we are using a legacy interrupt, our IRQ may be shared and our
interrupt handler may be called even though interrupts are disabled on
the NIC. When we change ring sizes, we reallocate the event queue and
the interrupt handler may use an invalid pointer when called for
another device's interrupt.
Maintain a legacy_irq_enabled flag and test that at the top of the
interrupt handler. Note that this problem results from the need to
work around broken INT_ISR0 reads, and does not affect the legacy
interrupt handler for Falcon A1.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/sfc/efx.c')
-rw-r--r-- | drivers/net/sfc/efx.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 05df20e47976..d06cb742164b 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -335,8 +335,10 @@ void efx_process_channel_now(struct efx_channel *channel) | |||
335 | 335 | ||
336 | /* Disable interrupts and wait for ISRs to complete */ | 336 | /* Disable interrupts and wait for ISRs to complete */ |
337 | efx_nic_disable_interrupts(efx); | 337 | efx_nic_disable_interrupts(efx); |
338 | if (efx->legacy_irq) | 338 | if (efx->legacy_irq) { |
339 | synchronize_irq(efx->legacy_irq); | 339 | synchronize_irq(efx->legacy_irq); |
340 | efx->legacy_irq_enabled = false; | ||
341 | } | ||
340 | if (channel->irq) | 342 | if (channel->irq) |
341 | synchronize_irq(channel->irq); | 343 | synchronize_irq(channel->irq); |
342 | 344 | ||
@@ -351,6 +353,8 @@ void efx_process_channel_now(struct efx_channel *channel) | |||
351 | efx_channel_processed(channel); | 353 | efx_channel_processed(channel); |
352 | 354 | ||
353 | napi_enable(&channel->napi_str); | 355 | napi_enable(&channel->napi_str); |
356 | if (efx->legacy_irq) | ||
357 | efx->legacy_irq_enabled = true; | ||
354 | efx_nic_enable_interrupts(efx); | 358 | efx_nic_enable_interrupts(efx); |
355 | } | 359 | } |
356 | 360 | ||
@@ -1400,6 +1404,8 @@ static void efx_start_all(struct efx_nic *efx) | |||
1400 | efx_start_channel(channel); | 1404 | efx_start_channel(channel); |
1401 | } | 1405 | } |
1402 | 1406 | ||
1407 | if (efx->legacy_irq) | ||
1408 | efx->legacy_irq_enabled = true; | ||
1403 | efx_nic_enable_interrupts(efx); | 1409 | efx_nic_enable_interrupts(efx); |
1404 | 1410 | ||
1405 | /* Switch to event based MCDI completions after enabling interrupts. | 1411 | /* Switch to event based MCDI completions after enabling interrupts. |
@@ -1460,8 +1466,10 @@ static void efx_stop_all(struct efx_nic *efx) | |||
1460 | 1466 | ||
1461 | /* Disable interrupts and wait for ISR to complete */ | 1467 | /* Disable interrupts and wait for ISR to complete */ |
1462 | efx_nic_disable_interrupts(efx); | 1468 | efx_nic_disable_interrupts(efx); |
1463 | if (efx->legacy_irq) | 1469 | if (efx->legacy_irq) { |
1464 | synchronize_irq(efx->legacy_irq); | 1470 | synchronize_irq(efx->legacy_irq); |
1471 | efx->legacy_irq_enabled = false; | ||
1472 | } | ||
1465 | efx_for_each_channel(channel, efx) { | 1473 | efx_for_each_channel(channel, efx) { |
1466 | if (channel->irq) | 1474 | if (channel->irq) |
1467 | synchronize_irq(channel->irq); | 1475 | synchronize_irq(channel->irq); |