Commit b28405b0 authored by Alexandre Rames's avatar Alexandre Rames Committed by Ben Hutchings

sfc: Fix EEH with legacy interrupts.

PCI legacy interrupts are level-triggered, and we cannot mask them up
on an isolated device.  Instead, disable the IRQ at the controller
until we have recovered.
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
parent 37173488
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/cpu_rmap.h> #include <linux/cpu_rmap.h>
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/interrupt.h>
#include "net_driver.h" #include "net_driver.h"
#include "efx.h" #include "efx.h"
#include "nic.h" #include "nic.h"
...@@ -1427,6 +1428,10 @@ static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq) ...@@ -1427,6 +1428,10 @@ static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq)
BUG_ON(efx->state == STATE_DISABLED); BUG_ON(efx->state == STATE_DISABLED);
if (efx->eeh_disabled_legacy_irq) {
enable_irq(efx->legacy_irq);
efx->eeh_disabled_legacy_irq = false;
}
if (efx->legacy_irq) if (efx->legacy_irq)
efx->legacy_irq_enabled = true; efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx); efx_nic_enable_interrupts(efx);
...@@ -2365,7 +2370,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method) ...@@ -2365,7 +2370,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
* Returns 0 if the recovery mechanisms are unsuccessful. * Returns 0 if the recovery mechanisms are unsuccessful.
* Returns a non-zero value otherwise. * Returns a non-zero value otherwise.
*/ */
static int efx_try_recovery(struct efx_nic *efx) int efx_try_recovery(struct efx_nic *efx)
{ {
#ifdef CONFIG_EEH #ifdef CONFIG_EEH
/* A PCI error can occur and not be seen by EEH because nothing /* A PCI error can occur and not be seen by EEH because nothing
......
...@@ -124,6 +124,7 @@ extern const struct ethtool_ops efx_ethtool_ops; ...@@ -124,6 +124,7 @@ extern const struct ethtool_ops efx_ethtool_ops;
extern int efx_reset(struct efx_nic *efx, enum reset_type method); extern int efx_reset(struct efx_nic *efx, enum reset_type method);
extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
extern int efx_try_recovery(struct efx_nic *efx);
/* Global */ /* Global */
extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
......
...@@ -788,6 +788,7 @@ struct efx_nic { ...@@ -788,6 +788,7 @@ struct efx_nic {
const struct efx_nic_type *type; const struct efx_nic_type *type;
int legacy_irq; int legacy_irq;
bool legacy_irq_enabled; bool legacy_irq_enabled;
bool eeh_disabled_legacy_irq;
struct workqueue_struct *workqueue; struct workqueue_struct *workqueue;
char workqueue_name[16]; char workqueue_name[16];
struct work_struct reset_work; struct work_struct reset_work;
......
...@@ -1579,6 +1579,16 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) ...@@ -1579,6 +1579,16 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
efx_readd(efx, &reg, FR_BZ_INT_ISR0); efx_readd(efx, &reg, FR_BZ_INT_ISR0);
queues = EFX_EXTRACT_DWORD(reg, 0, 31); queues = EFX_EXTRACT_DWORD(reg, 0, 31);
/* Legacy interrupts are disabled too late by the EEH kernel
* code. Disable them earlier.
* If an EEH error occurred, the read will have returned all ones.
*/
if (EFX_DWORD_IS_ALL_ONES(reg) && efx_try_recovery(efx) &&
!efx->eeh_disabled_legacy_irq) {
disable_irq_nosync(efx->legacy_irq);
efx->eeh_disabled_legacy_irq = true;
}
/* Handle non-event-queue sources */ /* Handle non-event-queue sources */
if (queues & (1U << efx->irq_level)) { if (queues & (1U << efx->irq_level)) {
syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment