diff options
author | Jing Huang <huangj@brocade.com> | 2009-09-23 20:46:15 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-10-02 10:47:40 -0400 |
commit | 7725ccfda59715ecf8f99e3b520a0b84cc2ea79e (patch) | |
tree | df76910891c6b92bf23c06c84955bf600c9d7573 /drivers/scsi/bfa/bfa_intr.c | |
parent | 5415907af1f5ef80c95147bacbd321b0d4236dd5 (diff) |
[SCSI] bfa: Brocade BFA FC SCSI driver
Add new driver for Brocade Hardware
Signed-off-by: Jing Huang <huangj@brocade.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/bfa/bfa_intr.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_intr.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c new file mode 100644 index 000000000000..0ca125712a04 --- /dev/null +++ b/drivers/scsi/bfa/bfa_intr.c | |||
@@ -0,0 +1,218 @@ | |||
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 | |||