linux/drivers/scsi/bfa/bfa_intr.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
   3 * All rights reserved
   4 * www.brocade.com
   5 *
   6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License (GPL) Version 2 as
  10 * published by the Free Software Foundation
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 */
  17#include <bfa.h>
  18#include <bfi/bfi_cbreg.h>
  19#include <bfa_port_priv.h>
  20#include <bfa_intr_priv.h>
  21#include <cs/bfa_debug.h>
  22
  23BFA_TRC_FILE(HAL, INTR);
  24
  25static void
  26bfa_msix_errint(struct bfa_s *bfa, u32 intr)
  27{
  28        bfa_ioc_error_isr(&bfa->ioc);
  29}
  30
  31static void
  32bfa_msix_lpu(struct bfa_s *bfa)
  33{
  34        bfa_ioc_mbox_isr(&bfa->ioc);
  35}
  36
  37void
  38bfa_msix_all(struct bfa_s *bfa, int vec)
  39{
  40        bfa_intx(bfa);
  41}
  42
  43/**
  44 *  hal_intr_api
  45 */
  46bfa_boolean_t
  47bfa_intx(struct bfa_s *bfa)
  48{
  49        u32        intr, qintr;
  50        int             queue;
  51
  52        intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
  53        if (!intr)
  54                return BFA_FALSE;
  55
  56        /**
  57         * RME completion queue interrupt
  58         */
  59        qintr = intr & __HFN_INT_RME_MASK;
  60        bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
  61
  62        for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue ++) {
  63                if (intr & (__HFN_INT_RME_Q0 << queue))
  64                        bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
  65        }
  66        intr &= ~qintr;
  67        if (!intr)
  68                return BFA_TRUE;
  69
  70        /**
  71         * CPE completion queue interrupt
  72         */
  73        qintr = intr & __HFN_INT_CPE_MASK;
  74        bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
  75
  76        for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
  77                if (intr & (__HFN_INT_CPE_Q0 << queue))
  78                        bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
  79        }
  80        intr &= ~qintr;
  81        if (!intr)
  82                return BFA_TRUE;
  83
  84        bfa_msix_lpu_err(bfa, intr);
  85
  86        return BFA_TRUE;
  87}
  88
  89void
  90bfa_isr_enable(struct bfa_s *bfa)
  91{
  92        u32        intr_unmask;
  93        int             pci_func = bfa_ioc_pcifn(&bfa->ioc);
  94
  95        bfa_trc(bfa, pci_func);
  96
  97        bfa_msix_install(bfa);
  98        intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
  99                       __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
 100
 101        if (pci_func == 0)
 102                intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
 103                                __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
 104                                __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
 105                                __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
 106                                __HFN_INT_MBOX_LPU0);
 107        else
 108                intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
 109                                __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
 110                                __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
 111                                __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
 112                                __HFN_INT_MBOX_LPU1);
 113
 114        bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
 115        bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
 116        bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
 117}
 118
 119void
 120bfa_isr_disable(struct bfa_s *bfa)
 121{
 122        bfa_isr_mode_set(bfa, BFA_FALSE);
 123        bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
 124        bfa_msix_uninstall(bfa);
 125}
 126
 127void
 128bfa_msix_reqq(struct bfa_s *bfa, int qid)
 129{
 130        struct list_head                *waitq, *qe, *qen;
 131        struct bfa_reqq_wait_s  *wqe;
 132
 133        qid &= (BFI_IOC_MAX_CQS - 1);
 134
 135        waitq = bfa_reqq(bfa, qid);
 136        list_for_each_safe(qe, qen, waitq) {
 137                /**
 138                 * Callback only as long as there is room in request queue
 139                 */
 140                if (bfa_reqq_full(bfa, qid))
 141                        break;
 142
 143                list_del(qe);
 144                wqe = (struct bfa_reqq_wait_s *) qe;
 145                wqe->qresume(wqe->cbarg);
 146        }
 147}
 148
 149void
 150bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m)
 151{
 152        bfa_trc(bfa, m->mhdr.msg_class);
 153        bfa_trc(bfa, m->mhdr.msg_id);
 154        bfa_trc(bfa, m->mhdr.mtag.i2htok);
 155        bfa_assert(0);
 156        bfa_trc_stop(bfa->trcmod);
 157}
 158
 159void
 160bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid)
 161{
 162        struct bfi_msg_s      *m;
 163        u32        pi, ci;
 164
 165        bfa_trc_fp(bfa, rsp_qid);
 166
 167        rsp_qid &= (BFI_IOC_MAX_CQS - 1);
 168
 169        bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid);
 170
 171        ci = bfa_rspq_ci(bfa, rsp_qid);
 172        pi = bfa_rspq_pi(bfa, rsp_qid);
 173
 174        bfa_trc_fp(bfa, ci);
 175        bfa_trc_fp(bfa, pi);
 176
 177        if (bfa->rme_process) {
 178                while (ci != pi) {
 179                        m = bfa_rspq_elem(bfa, rsp_qid, ci);
 180                        bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX);
 181
 182                        bfa_isrs[m->mhdr.msg_class] (bfa, m);
 183
 184                        CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems);
 185                }
 186        }
 187
 188        /**
 189         * update CI
 190         */
 191        bfa_rspq_ci(bfa, rsp_qid) = pi;
 192        bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid], pi);
 193        bfa_os_mmiowb();
 194}
 195
 196void
 197bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
 198{
 199        u32 intr;
 200
 201        intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
 202
 203        if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
 204                bfa_msix_lpu(bfa);
 205
 206        if (intr & (__HFN_INT_ERR_EMC |
 207                    __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 |
 208                    __HFN_INT_ERR_PSS))
 209                bfa_msix_errint(bfa, intr);
 210}
 211
 212void
 213bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
 214{
 215        bfa_isrs[mc] = isr_func;
 216}
 217
 218
 219