mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08: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;
|
int node;
|
||||||
u32 led_reg;
|
u32 led_reg;
|
||||||
u32 interrupt_event;
|
u32 interrupt_event;
|
||||||
char lsc_int_name[IFNAMSIZ + 9];
|
|
||||||
|
|
||||||
/* SR-IOV */
|
/* SR-IOV */
|
||||||
DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS);
|
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,
|
static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
|
||||||
u64 qmask)
|
u64 qmask)
|
||||||
{
|
{
|
||||||
@ -1946,6 +1880,112 @@ static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
|
|||||||
/* skip the flush */
|
/* 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)
|
static irqreturn_t ixgbe_msix_clean_rings(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct ixgbe_q_vector *q_vector = 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,
|
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) {
|
if (err) {
|
||||||
e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
|
e_err(probe, "request_irq for msix_lsc failed: %d\n", err);
|
||||||
goto free_queue_irqs;
|
goto free_queue_irqs;
|
||||||
@ -2102,42 +2141,6 @@ free_queue_irqs:
|
|||||||
return err;
|
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
|
* ixgbe_intr - legacy mode Interrupt Handler
|
||||||
* @irq: interrupt number
|
* @irq: interrupt number
|
||||||
|
Loading…
Reference in New Issue
Block a user