Commit 5b75da2f authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.0 : Add active interrupt test for enabling MSI/MSI-X/INTx

Per the recent discussions at the Linux Plumbers Conference, when
enabling MSI or MSI-X, generate a test interrupt to verify the
interrupt routing is working properly.  If the test interrupt fails,
fall back to MSI first, and if that fails as well, to INTx.  If the
interrupt test fails with INTx, log an error and fail the PCI probe.

Also changed the use of spin_(lock|unlock) to the _irq(save|restore)
variants in the interrupt handlers because with multi-message MSI-X,
both interrupt handlers can now run in parallel.
Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent eaf15d5b
...@@ -592,6 +592,8 @@ struct lpfc_hba { ...@@ -592,6 +592,8 @@ struct lpfc_hba {
struct fc_host_statistics link_stats; struct fc_host_statistics link_stats;
enum intr_type_t intr_type; enum intr_type_t intr_type;
uint32_t intr_mode;
#define LPFC_INTR_ERROR 0xFFFFFFFF
struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; struct msix_entry msix_entries[LPFC_MSIX_VECTORS];
struct list_head port_list; struct list_head port_list;
......
This diff is collapsed.
...@@ -1315,10 +1315,12 @@ lpfc_mbox_get(struct lpfc_hba * phba) ...@@ -1315,10 +1315,12 @@ lpfc_mbox_get(struct lpfc_hba * phba)
void void
lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
{ {
unsigned long iflag;
/* This function expects to be called from interrupt context */ /* This function expects to be called from interrupt context */
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl); list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
return; return;
} }
......
...@@ -5238,6 +5238,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5238,6 +5238,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
uint32_t ha_copy; uint32_t ha_copy;
uint32_t work_ha_copy; uint32_t work_ha_copy;
unsigned long status; unsigned long status;
unsigned long iflag;
uint32_t control; uint32_t control;
MAILBOX_t *mbox, *pmbox; MAILBOX_t *mbox, *pmbox;
...@@ -5270,7 +5271,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5270,7 +5271,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
if (unlikely(phba->link_state < LPFC_LINK_DOWN)) if (unlikely(phba->link_state < LPFC_LINK_DOWN))
return IRQ_NONE; return IRQ_NONE;
/* Need to read HA REG for slow-path events */ /* Need to read HA REG for slow-path events */
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
ha_copy = readl(phba->HAregaddr); ha_copy = readl(phba->HAregaddr);
/* If somebody is waiting to handle an eratt don't process it /* If somebody is waiting to handle an eratt don't process it
* here. The brdkill function will do this. * here. The brdkill function will do this.
...@@ -5290,7 +5291,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5290,7 +5291,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)), writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)),
phba->HAregaddr); phba->HAregaddr);
readl(phba->HAregaddr); /* flush */ readl(phba->HAregaddr); /* flush */
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
} else } else
ha_copy = phba->ha_copy; ha_copy = phba->ha_copy;
...@@ -5303,13 +5304,13 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5303,13 +5304,13 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
* Turn off Link Attention interrupts * Turn off Link Attention interrupts
* until CLEAR_LA done * until CLEAR_LA done
*/ */
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
phba->sli.sli_flag &= ~LPFC_PROCESS_LA; phba->sli.sli_flag &= ~LPFC_PROCESS_LA;
control = readl(phba->HCregaddr); control = readl(phba->HCregaddr);
control &= ~HC_LAINT_ENA; control &= ~HC_LAINT_ENA;
writel(control, phba->HCregaddr); writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */ readl(phba->HCregaddr); /* flush */
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
} }
else else
work_ha_copy &= ~HA_LATT; work_ha_copy &= ~HA_LATT;
...@@ -5324,7 +5325,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5324,7 +5325,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
(HA_RXMASK << (4*LPFC_ELS_RING))); (HA_RXMASK << (4*LPFC_ELS_RING)));
status >>= (4*LPFC_ELS_RING); status >>= (4*LPFC_ELS_RING);
if (status & HA_RXMASK) { if (status & HA_RXMASK) {
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
control = readl(phba->HCregaddr); control = readl(phba->HCregaddr);
lpfc_debugfs_slow_ring_trc(phba, lpfc_debugfs_slow_ring_trc(phba,
...@@ -5353,10 +5354,10 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5353,10 +5354,10 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
(uint32_t)((unsigned long) (uint32_t)((unsigned long)
&phba->work_waitq)); &phba->work_waitq));
} }
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
} }
} }
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
if (work_ha_copy & HA_ERATT) if (work_ha_copy & HA_ERATT)
lpfc_sli_read_hs(phba); lpfc_sli_read_hs(phba);
if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) {
...@@ -5368,7 +5369,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5368,7 +5369,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
/* First check out the status word */ /* First check out the status word */
lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t)); lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
if (pmbox->mbxOwner != OWN_HOST) { if (pmbox->mbxOwner != OWN_HOST) {
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
/* /*
* Stray Mailbox Interrupt, mbxCommand <cmd> * Stray Mailbox Interrupt, mbxCommand <cmd>
* mbxStatus <status> * mbxStatus <status>
...@@ -5385,7 +5386,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5385,7 +5386,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
work_ha_copy &= ~HA_MBATT; work_ha_copy &= ~HA_MBATT;
} else { } else {
phba->sli.mbox_active = NULL; phba->sli.mbox_active = NULL;
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
phba->last_completion_time = jiffies; phba->last_completion_time = jiffies;
del_timer(&phba->sli.mbox_tmo); del_timer(&phba->sli.mbox_tmo);
if (pmb->mbox_cmpl) { if (pmb->mbox_cmpl) {
...@@ -5434,14 +5435,18 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5434,14 +5435,18 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
goto send_current_mbox; goto send_current_mbox;
} }
} }
spin_lock(&phba->pport->work_port_lock); spin_lock_irqsave(
&phba->pport->work_port_lock,
iflag);
phba->pport->work_port_events &= phba->pport->work_port_events &=
~WORKER_MBOX_TMO; ~WORKER_MBOX_TMO;
spin_unlock(&phba->pport->work_port_lock); spin_unlock_irqrestore(
&phba->pport->work_port_lock,
iflag);
lpfc_mbox_cmpl_put(phba, pmb); lpfc_mbox_cmpl_put(phba, pmb);
} }
} else } else
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
if ((work_ha_copy & HA_MBATT) && if ((work_ha_copy & HA_MBATT) &&
(phba->sli.mbox_active == NULL)) { (phba->sli.mbox_active == NULL)) {
...@@ -5457,9 +5462,9 @@ lpfc_sp_intr_handler(int irq, void *dev_id) ...@@ -5457,9 +5462,9 @@ lpfc_sp_intr_handler(int irq, void *dev_id)
"MBX_SUCCESS"); "MBX_SUCCESS");
} }
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
phba->work_ha |= work_ha_copy; phba->work_ha |= work_ha_copy;
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
lpfc_worker_wake_up(phba); lpfc_worker_wake_up(phba);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -5491,6 +5496,7 @@ lpfc_fp_intr_handler(int irq, void *dev_id) ...@@ -5491,6 +5496,7 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
struct lpfc_hba *phba; struct lpfc_hba *phba;
uint32_t ha_copy; uint32_t ha_copy;
unsigned long status; unsigned long status;
unsigned long iflag;
/* Get the driver's phba structure from the dev_id and /* Get the driver's phba structure from the dev_id and
* assume the HBA is not interrupting. * assume the HBA is not interrupting.
...@@ -5516,11 +5522,11 @@ lpfc_fp_intr_handler(int irq, void *dev_id) ...@@ -5516,11 +5522,11 @@ lpfc_fp_intr_handler(int irq, void *dev_id)
/* Need to read HA REG for FCP ring and other ring events */ /* Need to read HA REG for FCP ring and other ring events */
ha_copy = readl(phba->HAregaddr); ha_copy = readl(phba->HAregaddr);
/* Clear up only attention source related to fast-path */ /* Clear up only attention source related to fast-path */
spin_lock(&phba->hbalock); spin_lock_irqsave(&phba->hbalock, iflag);
writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)), writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)),
phba->HAregaddr); phba->HAregaddr);
readl(phba->HAregaddr); /* flush */ readl(phba->HAregaddr); /* flush */
spin_unlock(&phba->hbalock); spin_unlock_irqrestore(&phba->hbalock, iflag);
} else } else
ha_copy = phba->ha_copy; ha_copy = phba->ha_copy;
......
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