Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 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); |
Jing Huang | f8ceafd | 2009-09-25 12:29:54 -0700 | [diff] [blame] | 188 | return uf; |
Jing Huang | 7725ccf | 2009-09-23 17:46:15 -0700 | [diff] [blame] | 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 | |