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 | ||
18 | /** | |
19 | * bfa_uf.c BFA unsolicited frame receive implementation | |
20 | */ | |
21 | ||
22 | #include <bfa.h> | |
23 | #include <bfa_svc.h> | |
24 | #include <bfi/bfi_uf.h> | |
25 | #include <cs/bfa_debug.h> | |
26 | ||
27 | BFA_TRC_FILE(HAL, UF); | |
28 | BFA_MODULE(uf); | |
29 | ||
30 | /* | |
31 | ***************************************************************************** | |
32 | * Internal functions | |
33 | ***************************************************************************** | |
34 | */ | |
35 | static void | |
36 | __bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) | |
37 | { | |
38 | struct bfa_uf_s *uf = cbarg; | |
39 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa); | |
40 | ||
41 | if (complete) | |
42 | ufm->ufrecv(ufm->cbarg, uf); | |
43 | } | |
44 | ||
45 | static void | |
46 | claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | |
47 | { | |
48 | u32 uf_pb_tot_sz; | |
49 | ||
50 | ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); | |
51 | ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); | |
52 | uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), | |
53 | BFA_DMA_ALIGN_SZ); | |
54 | ||
55 | bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; | |
56 | bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; | |
57 | ||
58 | bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); | |
59 | } | |
60 | ||
61 | static void | |
62 | claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | |
63 | { | |
64 | struct bfi_uf_buf_post_s *uf_bp_msg; | |
65 | struct bfi_sge_s *sge; | |
66 | union bfi_addr_u sga_zero = { {0} }; | |
67 | u16 i; | |
68 | u16 buf_len; | |
69 | ||
70 | ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); | |
71 | uf_bp_msg = ufm->uf_buf_posts; | |
72 | ||
73 | for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; | |
74 | i++, uf_bp_msg++) { | |
75 | bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s)); | |
76 | ||
77 | uf_bp_msg->buf_tag = i; | |
78 | buf_len = sizeof(struct bfa_uf_buf_s); | |
79 | uf_bp_msg->buf_len = bfa_os_htons(buf_len); | |
80 | bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, | |
81 | bfa_lpuid(ufm->bfa)); | |
82 | ||
83 | sge = uf_bp_msg->sge; | |
84 | sge[0].sg_len = buf_len; | |
85 | sge[0].flags = BFI_SGE_DATA_LAST; | |
86 | bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); | |
87 | bfa_sge_to_be(sge); | |
88 | ||
89 | sge[1].sg_len = buf_len; | |
90 | sge[1].flags = BFI_SGE_PGDLEN; | |
91 | sge[1].sga = sga_zero; | |
92 | bfa_sge_to_be(&sge[1]); | |
93 | } | |
94 | ||
95 | /** | |
96 | * advance pointer beyond consumed memory | |
97 | */ | |
98 | bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; | |
99 | } | |
100 | ||
101 | static void | |
102 | claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | |
103 | { | |
104 | u16 i; | |
105 | struct bfa_uf_s *uf; | |
106 | ||
107 | /* | |
108 | * Claim block of memory for UF list | |
109 | */ | |
110 | ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); | |
111 | ||
112 | /* | |
113 | * Initialize UFs and queue it in UF free queue | |
114 | */ | |
115 | for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) { | |
116 | bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s)); | |
117 | uf->bfa = ufm->bfa; | |
118 | uf->uf_tag = i; | |
119 | uf->pb_len = sizeof(struct bfa_uf_buf_s); | |
120 | uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; | |
121 | uf->buf_pa = ufm_pbs_pa(ufm, i); | |
122 | list_add_tail(&uf->qe, &ufm->uf_free_q); | |
123 | } | |
124 | ||
125 | /** | |
126 | * advance memory pointer | |
127 | */ | |
128 | bfa_meminfo_kva(mi) = (u8 *) uf; | |
129 | } | |
130 | ||
131 | static void | |
132 | uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) | |
133 | { | |
134 | claim_uf_pbs(ufm, mi); | |
135 | claim_ufs(ufm, mi); | |
136 | claim_uf_post_msgs(ufm, mi); | |
137 | } | |
138 | ||
139 | static void | |
140 | bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) | |
141 | { | |
142 | u32 num_ufs = cfg->fwcfg.num_uf_bufs; | |
143 | ||
144 | /* | |
145 | * dma-able memory for UF posted bufs | |
146 | */ | |
147 | *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), | |
148 | BFA_DMA_ALIGN_SZ); | |
149 | ||
150 | /* | |
151 | * kernel Virtual memory for UFs and UF buf post msg copies | |
152 | */ | |
153 | *ndm_len += sizeof(struct bfa_uf_s) * num_ufs; | |
154 | *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; | |
155 | } | |
156 | ||
157 | static void | |
158 | bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | |
159 | struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) | |
160 | { | |
161 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | |
162 | ||
163 | bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); | |
164 | ufm->bfa = bfa; | |
165 | ufm->num_ufs = cfg->fwcfg.num_uf_bufs; | |
166 | INIT_LIST_HEAD(&ufm->uf_free_q); | |
167 | INIT_LIST_HEAD(&ufm->uf_posted_q); | |
168 | ||
169 | uf_mem_claim(ufm, meminfo); | |
170 | } | |
171 | ||
172 | static void | |
173 | bfa_uf_initdone(struct bfa_s *bfa) | |
174 | { | |
175 | } | |
176 | ||
177 | static void | |
178 | bfa_uf_detach(struct bfa_s *bfa) | |
179 | { | |
180 | } | |
181 | ||
182 | static struct bfa_uf_s * | |
183 | bfa_uf_get(struct bfa_uf_mod_s *uf_mod) | |
184 | { | |
185 | struct bfa_uf_s *uf; | |
186 | ||
187 | bfa_q_deq(&uf_mod->uf_free_q, &uf); | |
f8ceafde | 188 | return uf; |
7725ccfd JH |
189 | } |
190 | ||
191 | static void | |
192 | bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf) | |
193 | { | |
194 | list_add_tail(&uf->qe, &uf_mod->uf_free_q); | |
195 | } | |
196 | ||
197 | static bfa_status_t | |
198 | bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) | |
199 | { | |
200 | struct bfi_uf_buf_post_s *uf_post_msg; | |
201 | ||
202 | uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP); | |
203 | if (!uf_post_msg) | |
204 | return BFA_STATUS_FAILED; | |
205 | ||
206 | bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], | |
207 | sizeof(struct bfi_uf_buf_post_s)); | |
208 | bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); | |
209 | ||
210 | bfa_trc(ufm->bfa, uf->uf_tag); | |
211 | ||
212 | list_add_tail(&uf->qe, &ufm->uf_posted_q); | |
213 | return BFA_STATUS_OK; | |
214 | } | |
215 | ||
216 | static void | |
217 | bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod) | |
218 | { | |
219 | struct bfa_uf_s *uf; | |
220 | ||
221 | while ((uf = bfa_uf_get(uf_mod)) != NULL) { | |
222 | if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK) | |
223 | break; | |
224 | } | |
225 | } | |
226 | ||
227 | static void | |
228 | uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) | |
229 | { | |
230 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | |
231 | u16 uf_tag = m->buf_tag; | |
232 | struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; | |
233 | struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; | |
234 | u8 *buf = &uf_buf->d[0]; | |
235 | struct fchs_s *fchs; | |
236 | ||
237 | m->frm_len = bfa_os_ntohs(m->frm_len); | |
238 | m->xfr_len = bfa_os_ntohs(m->xfr_len); | |
239 | ||
240 | fchs = (struct fchs_s *) uf_buf; | |
241 | ||
242 | list_del(&uf->qe); /* dequeue from posted queue */ | |
243 | ||
244 | uf->data_ptr = buf; | |
245 | uf->data_len = m->xfr_len; | |
246 | ||
247 | bfa_assert(uf->data_len >= sizeof(struct fchs_s)); | |
248 | ||
249 | if (uf->data_len == sizeof(struct fchs_s)) { | |
250 | bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX, | |
251 | uf->data_len, (struct fchs_s *) buf); | |
252 | } else { | |
253 | u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s))); | |
254 | bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF, | |
255 | BFA_PL_EID_RX, uf->data_len, | |
256 | (struct fchs_s *) buf, pld_w0); | |
257 | } | |
258 | ||
259 | bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); | |
260 | } | |
261 | ||
262 | static void | |
263 | bfa_uf_stop(struct bfa_s *bfa) | |
264 | { | |
265 | } | |
266 | ||
267 | static void | |
268 | bfa_uf_iocdisable(struct bfa_s *bfa) | |
269 | { | |
270 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | |
271 | struct bfa_uf_s *uf; | |
272 | struct list_head *qe, *qen; | |
273 | ||
274 | list_for_each_safe(qe, qen, &ufm->uf_posted_q) { | |
275 | uf = (struct bfa_uf_s *) qe; | |
276 | list_del(&uf->qe); | |
277 | bfa_uf_put(ufm, uf); | |
278 | } | |
279 | } | |
280 | ||
281 | static void | |
282 | bfa_uf_start(struct bfa_s *bfa) | |
283 | { | |
284 | bfa_uf_post_all(BFA_UF_MOD(bfa)); | |
285 | } | |
286 | ||
287 | ||
288 | ||
289 | /** | |
290 | * bfa_uf_api | |
291 | */ | |
292 | ||
293 | /** | |
294 | * Register handler for all unsolicted recieve frames. | |
295 | * | |
296 | * @param[in] bfa BFA instance | |
297 | * @param[in] ufrecv receive handler function | |
298 | * @param[in] cbarg receive handler arg | |
299 | */ | |
300 | void | |
301 | bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg) | |
302 | { | |
303 | struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); | |
304 | ||
305 | ufm->ufrecv = ufrecv; | |
306 | ufm->cbarg = cbarg; | |
307 | } | |
308 | ||
309 | /** | |
310 | * Free an unsolicited frame back to BFA. | |
311 | * | |
312 | * @param[in] uf unsolicited frame to be freed | |
313 | * | |
314 | * @return None | |
315 | */ | |
316 | void | |
317 | bfa_uf_free(struct bfa_uf_s *uf) | |
318 | { | |
319 | bfa_uf_put(BFA_UF_MOD(uf->bfa), uf); | |
320 | bfa_uf_post_all(BFA_UF_MOD(uf->bfa)); | |
321 | } | |
322 | ||
323 | ||
324 | ||
325 | /** | |
326 | * uf_pub BFA uf module public functions | |
327 | */ | |
328 | ||
329 | void | |
330 | bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) | |
331 | { | |
332 | bfa_trc(bfa, msg->mhdr.msg_id); | |
333 | ||
334 | switch (msg->mhdr.msg_id) { | |
335 | case BFI_UF_I2H_FRM_RCVD: | |
336 | uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg); | |
337 | break; | |
338 | ||
339 | default: | |
340 | bfa_trc(bfa, msg->mhdr.msg_id); | |
341 | bfa_assert(0); | |
342 | } | |
343 | } | |
344 | ||
345 |