mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 21:02:19 +00:00
ixgbe: Correctly name and handle MSI-X other interrupt
It was possible to inadvertently add additional interrupt causes to the MSI-X other interrupt. This occurred when things such as RX buffer overrun events were being triggered at the same time as an event such as a Flow Director table reinit request. In order to avoid this we should be explicitly programming only the interrupts that we want enabled. In addition I am renaming the ixgbe_msix_lsc function and interrupt to drop any implied meaning of this being a link status only interrupt. Unfortunately the patch is a bit ugly due to the fact that ixgbe_irq_enable needed to be moved up before ixgbe_msix_other in order to have things defined in the correct order. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
8e34d1aacc
commit
2c4af694fe
@ -491,7 +491,6 @@ struct ixgbe_adapter {
|
||||
int node;
|
||||
u32 led_reg;
|
||||
u32 interrupt_event;
|
||||
char lsc_int_name[IFNAMSIZ + 9];
|
||||
|
||||
/* SR-IOV */
|
||||
DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
|
||||
|
@ -1828,72 +1828,6 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = data;
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 eicr;
|
||||
|
||||
/*
|
||||
* Workaround for Silicon errata. Use clear-by-write instead
|
||||
* of clear-by-read. Reading with EICS will return the
|
||||
* interrupt causes without clearing, which later be done
|
||||
* with the write to EICR.
|
||||
*/
|
||||
eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
|
||||
|
||||
if (eicr & IXGBE_EICR_LSC)
|
||||
ixgbe_check_lsc(adapter);
|
||||
|
||||
if (eicr & IXGBE_EICR_MAILBOX)
|
||||
ixgbe_msg_task(adapter);
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case ixgbe_mac_82599EB:
|
||||
case ixgbe_mac_X540:
|
||||
/* Handle Flow Director Full threshold interrupt */
|
||||
if (eicr & IXGBE_EICR_FLOW_DIR) {
|
||||
int reinit_count = 0;
|
||||
int i;
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct ixgbe_ring *ring = adapter->tx_ring[i];
|
||||
if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
|
||||
&ring->state))
|
||||
reinit_count++;
|
||||
}
|
||||
if (reinit_count) {
|
||||
/* no more flow director interrupts until after init */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
|
||||
eicr &= ~IXGBE_EICR_FLOW_DIR;
|
||||
adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
|
||||
ixgbe_service_event_schedule(adapter);
|
||||
}
|
||||
}
|
||||
ixgbe_check_sfp_event(adapter, eicr);
|
||||
if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
|
||||
((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
|
||||
if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
|
||||
adapter->interrupt_event = eicr;
|
||||
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
|
||||
ixgbe_service_event_schedule(adapter);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ixgbe_check_fan_failure(adapter, eicr);
|
||||
|
||||
/* re-enable the original interrupt state, no lsc, no queues */
|
||||
if (!test_bit(__IXGBE_DOWN, &adapter->state))
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr &
|
||||
~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
|
||||
u64 qmask)
|
||||
{
|
||||
@ -1946,6 +1880,112 @@ static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
|
||||
/* skip the flush */
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_irq_enable - Enable default interrupt generation settings
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
|
||||
bool flush)
|
||||
{
|
||||
u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
|
||||
|
||||
/* don't reenable LSC while waiting for link */
|
||||
if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
|
||||
mask &= ~IXGBE_EIMS_LSC;
|
||||
|
||||
if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
|
||||
mask |= IXGBE_EIMS_GPI_SDP0;
|
||||
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
|
||||
mask |= IXGBE_EIMS_GPI_SDP1;
|
||||
switch (adapter->hw.mac.type) {
|
||||
case ixgbe_mac_82599EB:
|
||||
case ixgbe_mac_X540:
|
||||
mask |= IXGBE_EIMS_ECC;
|
||||
mask |= IXGBE_EIMS_GPI_SDP1;
|
||||
mask |= IXGBE_EIMS_GPI_SDP2;
|
||||
mask |= IXGBE_EIMS_MAILBOX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) &&
|
||||
!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT))
|
||||
mask |= IXGBE_EIMS_FLOW_DIR;
|
||||
|
||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
|
||||
if (queues)
|
||||
ixgbe_irq_enable_queues(adapter, ~0);
|
||||
if (flush)
|
||||
IXGBE_WRITE_FLUSH(&adapter->hw);
|
||||
}
|
||||
|
||||
static irqreturn_t ixgbe_msix_other(int irq, void *data)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = data;
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
u32 eicr;
|
||||
|
||||
/*
|
||||
* Workaround for Silicon errata. Use clear-by-write instead
|
||||
* of clear-by-read. Reading with EICS will return the
|
||||
* interrupt causes without clearing, which later be done
|
||||
* with the write to EICR.
|
||||
*/
|
||||
eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
|
||||
|
||||
if (eicr & IXGBE_EICR_LSC)
|
||||
ixgbe_check_lsc(adapter);
|
||||
|
||||
if (eicr & IXGBE_EICR_MAILBOX)
|
||||
ixgbe_msg_task(adapter);
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case ixgbe_mac_82599EB:
|
||||
case ixgbe_mac_X540:
|
||||
if (eicr & IXGBE_EICR_ECC)
|
||||
e_info(link, "Received unrecoverable ECC Err, please "
|
||||
"reboot\n");
|
||||
/* Handle Flow Director Full threshold interrupt */
|
||||
if (eicr & IXGBE_EICR_FLOW_DIR) {
|
||||
int reinit_count = 0;
|
||||
int i;
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct ixgbe_ring *ring = adapter->tx_ring[i];
|
||||
if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
|
||||
&ring->state))
|
||||
reinit_count++;
|
||||
}
|
||||
if (reinit_count) {
|
||||
/* no more flow director interrupts until after init */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
|
||||
adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
|
||||
ixgbe_service_event_schedule(adapter);
|
||||
}
|
||||
}
|
||||
ixgbe_check_sfp_event(adapter, eicr);
|
||||
if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
|
||||
((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
|
||||
if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
|
||||
adapter->interrupt_event = eicr;
|
||||
adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
|
||||
ixgbe_service_event_schedule(adapter);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ixgbe_check_fan_failure(adapter, eicr);
|
||||
|
||||
/* re-enable the original interrupt state, no lsc, no queues */
|
||||
if (!test_bit(__IXGBE_DOWN, &adapter->state))
|
||||
ixgbe_irq_enable(adapter, false, false);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t ixgbe_msix_clean_rings(int irq, void *data)
|
||||
{
|
||||
struct ixgbe_q_vector *q_vector = data;
|
||||
@ -2077,9 +2117,8 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(adapter->lsc_int_name, "%s:lsc", netdev->name);
|
||||
err = request_irq(adapter->msix_entries[vector].vector,
|
||||
ixgbe_msix_lsc, 0, adapter->lsc_int_name, adapter);
|
||||
ixgbe_msix_other, 0, netdev->name, adapter);
|
||||
if (err) {
|
||||
e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
|
||||
goto free_queue_irqs;
|
||||
@ -2102,42 +2141,6 @@ free_queue_irqs:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_irq_enable - Enable default interrupt generation settings
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
|
||||
bool flush)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
|
||||
if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
|
||||
mask |= IXGBE_EIMS_GPI_SDP0;
|
||||
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
|
||||
mask |= IXGBE_EIMS_GPI_SDP1;
|
||||
switch (adapter->hw.mac.type) {
|
||||
case ixgbe_mac_82599EB:
|
||||
case ixgbe_mac_X540:
|
||||
mask |= IXGBE_EIMS_ECC;
|
||||
mask |= IXGBE_EIMS_GPI_SDP1;
|
||||
mask |= IXGBE_EIMS_GPI_SDP2;
|
||||
if (adapter->num_vfs)
|
||||
mask |= IXGBE_EIMS_MAILBOX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)
|
||||
mask |= IXGBE_EIMS_FLOW_DIR;
|
||||
|
||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
|
||||
if (queues)
|
||||
ixgbe_irq_enable_queues(adapter, ~0);
|
||||
if (flush)
|
||||
IXGBE_WRITE_FLUSH(&adapter->hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_intr - legacy mode Interrupt Handler
|
||||
* @irq: interrupt number
|
||||
|
Loading…
Reference in New Issue
Block a user