From: "Ahmed S. Darwish" <a.darwish@xxxxxxxxxxxxx> qla4_82xx_crb_win_lock() spins on a certain hardware state until it's updated. At the end of each spin, if in_interrupt() is true, it does 20 loops of cpu_relax(). Otherwise, it yields the CPU. The in_interrupt() macro is ill-defined as it does not provide what the name suggests, and it does not catch the intended use-case here. qla4_82xx_crb_win_lock() is always invoked with scsi_qla_host::hw_lock acquired, with disabled interrupts. If the caller is in process context, as in qla4_82xx_need_reset_handler(), then in_interrupt() will return false even though it is not allowed to call schedule(). Remove the in_interrupt() check. Change qla4_82xx_crb_win_lock() specification to a purely atomic function. Mark it as static, remove its forward declaration, and move it above its callers. To avoid hammering the PCI bus while spinning, use a 10 micro-second delay instead of cpu_relax(). Fixes: f4f5df23bf72 ("[SCSI] qla4xxx: Added support for ISP82XX") Signed-off-by: Ahmed S. Darwish <a.darwish@xxxxxxxxxxxxx> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> Cc: Nilesh Javali <njavali@xxxxxxxxxxx> Cc: Manish Rangankar <mrangankar@xxxxxxxxxxx> Cc: <GR-QLogic-Storage-Upstream@xxxxxxxxxxx> --- drivers/scsi/qla4xxx/ql4_glbl.h | 1 - drivers/scsi/qla4xxx/ql4_nx.c | 63 +++++++++++++++------------------ 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index b8f02210aeb03..ea60057b2e20a 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -114,7 +114,6 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id); void qla4_82xx_queue_iocb(struct scsi_qla_host *ha); void qla4_82xx_complete_iocb(struct scsi_qla_host *ha); -int qla4_82xx_crb_win_lock(struct scsi_qla_host *); void qla4_82xx_crb_win_unlock(struct scsi_qla_host *); int qla4_82xx_pci_get_crb_addr_2M(struct scsi_qla_host *, ulong *); void qla4_82xx_wr_32(struct scsi_qla_host *, ulong, u32); diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index f1767b21076f7..da903a545b2c0 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -375,6 +375,35 @@ qla4_82xx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off) *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; } +#define CRB_WIN_LOCK_TIMEOUT 100000000 + +/* + * Context: atomic + */ +static int qla4_82xx_crb_win_lock(struct scsi_qla_host *ha) +{ + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore3 from PCI HW block */ + done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); + if (done == 1) + break; + if (timeout >= CRB_WIN_LOCK_TIMEOUT) + return -1; + + timeout++; + udelay(10); + } + qla4_82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num); + return 0; +} + +void qla4_82xx_crb_win_unlock(struct scsi_qla_host *ha) +{ + qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +} + void qla4_82xx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data) { @@ -475,40 +504,6 @@ int qla4_82xx_md_wr_32(struct scsi_qla_host *ha, uint32_t off, uint32_t data) return rval; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 - -int qla4_82xx_crb_win_lock(struct scsi_qla_host *ha) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } - } - qla4_82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num); - return 0; -} - -void qla4_82xx_crb_win_unlock(struct scsi_qla_host *ha) -{ - qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); -} - #define IDC_LOCK_TIMEOUT 100000000 /** -- 2.29.2