[SCSI] bfa: Brocade BFA FC SCSI driver
[linux-2.6-block.git] / drivers / scsi / bfa / bfa_intr.c
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
23 BFA_TRC_FILE(HAL, INTR);
24
25 static void
26 bfa_msix_errint(struct bfa_s *bfa, u32 intr)
27 {
28         bfa_ioc_error_isr(&bfa->ioc);
29 }
30
31 static void
32 bfa_msix_lpu(struct bfa_s *bfa)
33 {
34         bfa_ioc_mbox_isr(&bfa->ioc);
35 }
36
37 void
38 bfa_msix_all(struct bfa_s *bfa, int vec)
39 {
40         bfa_intx(bfa);
41 }
42
43 /**
44  *  hal_intr_api
45  */
46 bfa_boolean_t
47 bfa_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
89 void
90 bfa_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
119 void
120 bfa_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
127 void
128 bfa_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
149 void
150 bfa_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
159 void
160 bfa_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
196 void
197 bfa_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
212 void
213 bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
214 {
215         bfa_isrs[mc] = isr_func;
216 }
217
218