aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <jsmart2021@gmail.com>2019-08-14 16:56:35 -0700
committerMartin K. Petersen <martin.petersen@oracle.com>2019-08-19 22:41:08 -0400
commit8d34a59caecda9a7ce0cad108ee64c37aa0c9812 (patch)
treec673fbeef1e59154ef32c16b63b7b81286a9f5d8
parentscsi: lpfc: Fix crash on driver unload in wq free (diff)
downloadlinux-dev-8d34a59caecda9a7ce0cad108ee64c37aa0c9812.tar.xz
linux-dev-8d34a59caecda9a7ce0cad108ee64c37aa0c9812.zip
scsi: lpfc: Fix failure to clear non-zero eq_delay after io rate reduction
Unusually high IO latency can be observed with little IO in progress. The latency may remain high regardless of amount of IO and can only be cleared by forcing lpfc_fcp_imax values to non-zero and then back to zero. The driver's eq_delay mechanism that scales the interrupt coalescing based on io completion load failed to reduce or turn off coalescing when load decreased. Specifically, if no io completed on a cpu within an eq_delay polling window, the eq delay processing was skipped and no change was made to the coalescing values. This left the coalescing values set when they were no longer applicable. Fix by always clearing the percpu counters for each time period and always run the eq_delay calculations if an eq has a non-zero coalescing value. Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: James Smart <jsmart2021@gmail.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to '')
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index f9986efa0aa3..d04d00dea901 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1262,6 +1262,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
unsigned char *eqcnt = NULL;
uint32_t usdelay;
int i;
+ bool update = false;
if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING)
return;
@@ -1275,20 +1276,29 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
if (!eqcnt)
goto requeue;
- /* Loop thru all IRQ vectors */
- for (i = 0; i < phba->cfg_irq_chann; i++) {
- /* Get the EQ corresponding to the IRQ vector */
- eq = phba->sli4_hba.hba_eq_hdl[i].eq;
- if (eq && eqcnt[eq->last_cpu] < 2)
- eqcnt[eq->last_cpu]++;
- continue;
- }
+ if (phba->cfg_irq_chann > 1) {
+ /* Loop thru all IRQ vectors */
+ for (i = 0; i < phba->cfg_irq_chann; i++) {
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[i].eq;
+ if (!eq)
+ continue;
+ if (eq->q_mode) {
+ update = true;
+ break;
+ }
+ if (eqcnt[eq->last_cpu] < 2)
+ eqcnt[eq->last_cpu]++;
+ }
+ } else
+ update = true;
for_each_present_cpu(i) {
- if (phba->cfg_irq_chann > 1 && eqcnt[i] < 2)
- continue;
-
eqi = per_cpu_ptr(phba->sli4_hba.eq_info, i);
+ if (!update && eqcnt[i] < 2) {
+ eqi->icnt = 0;
+ continue;
+ }
usdelay = (eqi->icnt / LPFC_IMAX_THRESHOLD) *
LPFC_EQ_DELAY_STEP;