Commit 8d34a59c authored by James Smart's avatar James Smart Committed by Martin K. Petersen

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: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 3cee98db
...@@ -1262,6 +1262,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work) ...@@ -1262,6 +1262,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
unsigned char *eqcnt = NULL; unsigned char *eqcnt = NULL;
uint32_t usdelay; uint32_t usdelay;
int i; int i;
bool update = false;
if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING) if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING)
return; return;
...@@ -1275,20 +1276,29 @@ lpfc_hb_eq_delay_work(struct work_struct *work) ...@@ -1275,20 +1276,29 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
if (!eqcnt) if (!eqcnt)
goto requeue; goto requeue;
/* Loop thru all IRQ vectors */ if (phba->cfg_irq_chann > 1) {
for (i = 0; i < phba->cfg_irq_chann; i++) { /* Loop thru all IRQ vectors */
/* Get the EQ corresponding to the IRQ vector */ for (i = 0; i < phba->cfg_irq_chann; i++) {
eq = phba->sli4_hba.hba_eq_hdl[i].eq; /* Get the EQ corresponding to the IRQ vector */
if (eq && eqcnt[eq->last_cpu] < 2) eq = phba->sli4_hba.hba_eq_hdl[i].eq;
eqcnt[eq->last_cpu]++; if (!eq)
continue; 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) { 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); 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) * usdelay = (eqi->icnt / LPFC_IMAX_THRESHOLD) *
LPFC_EQ_DELAY_STEP; LPFC_EQ_DELAY_STEP;
......
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