Commit | Line | Data |
---|---|---|
7725ccfd JH |
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 | ||
f8ceafde | 62 | for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { |
7725ccfd JH |
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 |