diff options
Diffstat (limited to 'drivers/scsi/bfa/bfa_intr.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_intr.c | 111 |
1 files changed, 81 insertions, 30 deletions
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c index b36540e4ed76..0eba3f930d5b 100644 --- a/drivers/scsi/bfa/bfa_intr.c +++ b/drivers/scsi/bfa/bfa_intr.c @@ -15,7 +15,7 @@ * General Public License for more details. */ #include <bfa.h> -#include <bfi/bfi_cbreg.h> +#include <bfi/bfi_ctreg.h> #include <bfa_port_priv.h> #include <bfa_intr_priv.h> #include <cs/bfa_debug.h> @@ -34,6 +34,26 @@ bfa_msix_lpu(struct bfa_s *bfa) bfa_ioc_mbox_isr(&bfa->ioc); } +static void +bfa_reqq_resume(struct bfa_s *bfa, int qid) +{ + struct list_head *waitq, *qe, *qen; + struct bfa_reqq_wait_s *wqe; + + waitq = bfa_reqq(bfa, qid); + list_for_each_safe(qe, qen, waitq) { + /** + * Callback only as long as there is room in request queue + */ + if (bfa_reqq_full(bfa, qid)) + break; + + list_del(qe); + wqe = (struct bfa_reqq_wait_s *) qe; + wqe->qresume(wqe->cbarg); + } +} + void bfa_msix_all(struct bfa_s *bfa, int vec) { @@ -96,7 +116,8 @@ bfa_isr_enable(struct bfa_s *bfa) bfa_msix_install(bfa); intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | - __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS); + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | + __HFN_INT_LL_HALT); if (pci_func == 0) intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | @@ -127,23 +148,18 @@ bfa_isr_disable(struct bfa_s *bfa) void bfa_msix_reqq(struct bfa_s *bfa, int qid) { - struct list_head *waitq, *qe, *qen; - struct bfa_reqq_wait_s *wqe; + struct list_head *waitq; qid &= (BFI_IOC_MAX_CQS - 1); - waitq = bfa_reqq(bfa, qid); - list_for_each_safe(qe, qen, waitq) { - /** - * Callback only as long as there is room in request queue - */ - if (bfa_reqq_full(bfa, qid)) - break; + bfa->iocfc.hwif.hw_reqq_ack(bfa, qid); - list_del(qe); - wqe = (struct bfa_reqq_wait_s *) qe; - wqe->qresume(wqe->cbarg); - } + /** + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); } void @@ -157,26 +173,27 @@ bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) } void -bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid) +bfa_msix_rspq(struct bfa_s *bfa, int qid) { - struct bfi_msg_s *m; - u32 pi, ci; + struct bfi_msg_s *m; + u32 pi, ci; + struct list_head *waitq; - bfa_trc_fp(bfa, rsp_qid); + bfa_trc_fp(bfa, qid); - rsp_qid &= (BFI_IOC_MAX_CQS - 1); + qid &= (BFI_IOC_MAX_CQS - 1); - bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid); + bfa->iocfc.hwif.hw_rspq_ack(bfa, qid); - ci = bfa_rspq_ci(bfa, rsp_qid); - pi = bfa_rspq_pi(bfa, rsp_qid); + ci = bfa_rspq_ci(bfa, qid); + pi = bfa_rspq_pi(bfa, qid); bfa_trc_fp(bfa, ci); bfa_trc_fp(bfa, pi); if (bfa->rme_process) { while (ci != pi) { - m = bfa_rspq_elem(bfa, rsp_qid, ci); + m = bfa_rspq_elem(bfa, qid, ci); bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX); bfa_isrs[m->mhdr.msg_class] (bfa, m); @@ -188,25 +205,59 @@ bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid) /** * update CI */ - bfa_rspq_ci(bfa, rsp_qid) = pi; - bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid], pi); + bfa_rspq_ci(bfa, qid) = pi; + bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[qid], pi); bfa_os_mmiowb(); + + /** + * Resume any pending requests in the corresponding reqq. + */ + waitq = bfa_reqq(bfa, qid); + if (!list_empty(waitq)) + bfa_reqq_resume(bfa, qid); } void bfa_msix_lpu_err(struct bfa_s *bfa, int vec) { - u32 intr; + u32 intr, curr_value; intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1)) bfa_msix_lpu(bfa); - if (intr & (__HFN_INT_ERR_EMC | - __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 | - __HFN_INT_ERR_PSS)) + intr &= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | + __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT); + + if (intr) { + if (intr & __HFN_INT_LL_HALT) { + /** + * If LL_HALT bit is set then FW Init Halt LL Port + * Register needs to be cleared as well so Interrupt + * Status Register will be cleared. + */ + curr_value = bfa_reg_read(bfa->ioc.ioc_regs.ll_halt); + curr_value &= ~__FW_INIT_HALT_P; + bfa_reg_write(bfa->ioc.ioc_regs.ll_halt, curr_value); + } + + if (intr & __HFN_INT_ERR_PSS) { + /** + * ERR_PSS bit needs to be cleared as well in case + * interrups are shared so driver's interrupt handler is + * still called eventhough it is already masked out. + */ + curr_value = bfa_reg_read( + bfa->ioc.ioc_regs.pss_err_status_reg); + curr_value &= __PSS_ERR_STATUS_SET; + bfa_reg_write(bfa->ioc.ioc_regs.pss_err_status_reg, + curr_value); + } + + bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr); bfa_msix_errint(bfa, intr); + } } void |