1 /*
2  * Linux network driver for QLogic BR-series Converged Network Adapter.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License (GPL) Version 2 as
6  * published by the Free Software Foundation
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  */
13 /*
14  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
15  * Copyright (c) 2014-2015 QLogic Corporation
16  * All rights reserved
17  * www.qlogic.com
18  */
19 
20 /* MSGQ module source file. */
21 
22 #include "bfi.h"
23 #include "bfa_msgq.h"
24 #include "bfa_ioc.h"
25 
26 #define call_cmdq_ent_cbfn(_cmdq_ent, _status)				\
27 {									\
28 	bfa_msgq_cmdcbfn_t cbfn;					\
29 	void *cbarg;							\
30 	cbfn = (_cmdq_ent)->cbfn;					\
31 	cbarg = (_cmdq_ent)->cbarg;					\
32 	(_cmdq_ent)->cbfn = NULL;					\
33 	(_cmdq_ent)->cbarg = NULL;					\
34 	if (cbfn) {							\
35 		cbfn(cbarg, (_status));					\
36 	}								\
37 }
38 
39 static void bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq);
40 static void bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq);
41 
42 enum cmdq_event {
43 	CMDQ_E_START			= 1,
44 	CMDQ_E_STOP			= 2,
45 	CMDQ_E_FAIL			= 3,
46 	CMDQ_E_POST			= 4,
47 	CMDQ_E_INIT_RESP		= 5,
48 	CMDQ_E_DB_READY			= 6,
49 };
50 
51 bfa_fsm_state_decl(cmdq, stopped, struct bfa_msgq_cmdq, enum cmdq_event);
52 bfa_fsm_state_decl(cmdq, init_wait, struct bfa_msgq_cmdq, enum cmdq_event);
53 bfa_fsm_state_decl(cmdq, ready, struct bfa_msgq_cmdq, enum cmdq_event);
54 bfa_fsm_state_decl(cmdq, dbell_wait, struct bfa_msgq_cmdq,
55 			enum cmdq_event);
56 
57 static void
58 cmdq_sm_stopped_entry(struct bfa_msgq_cmdq *cmdq)
59 {
60 	struct bfa_msgq_cmd_entry *cmdq_ent;
61 
62 	cmdq->producer_index = 0;
63 	cmdq->consumer_index = 0;
64 	cmdq->flags = 0;
65 	cmdq->token = 0;
66 	cmdq->offset = 0;
67 	cmdq->bytes_to_copy = 0;
68 	while (!list_empty(&cmdq->pending_q)) {
69 		bfa_q_deq(&cmdq->pending_q, &cmdq_ent);
70 		bfa_q_qe_init(&cmdq_ent->qe);
71 		call_cmdq_ent_cbfn(cmdq_ent, BFA_STATUS_FAILED);
72 	}
73 }
74 
75 static void
76 cmdq_sm_stopped(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
77 {
78 	switch (event) {
79 	case CMDQ_E_START:
80 		bfa_fsm_set_state(cmdq, cmdq_sm_init_wait);
81 		break;
82 
83 	case CMDQ_E_STOP:
84 	case CMDQ_E_FAIL:
85 		/* No-op */
86 		break;
87 
88 	case CMDQ_E_POST:
89 		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
90 		break;
91 
92 	default:
93 		bfa_sm_fault(event);
94 	}
95 }
96 
97 static void
98 cmdq_sm_init_wait_entry(struct bfa_msgq_cmdq *cmdq)
99 {
100 	bfa_wc_down(&cmdq->msgq->init_wc);
101 }
102 
103 static void
104 cmdq_sm_init_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
105 {
106 	switch (event) {
107 	case CMDQ_E_STOP:
108 	case CMDQ_E_FAIL:
109 		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
110 		break;
111 
112 	case CMDQ_E_POST:
113 		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
114 		break;
115 
116 	case CMDQ_E_INIT_RESP:
117 		if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
118 			cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
119 			bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
120 		} else
121 			bfa_fsm_set_state(cmdq, cmdq_sm_ready);
122 		break;
123 
124 	default:
125 		bfa_sm_fault(event);
126 	}
127 }
128 
129 static void
130 cmdq_sm_ready_entry(struct bfa_msgq_cmdq *cmdq)
131 {
132 }
133 
134 static void
135 cmdq_sm_ready(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
136 {
137 	switch (event) {
138 	case CMDQ_E_STOP:
139 	case CMDQ_E_FAIL:
140 		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
141 		break;
142 
143 	case CMDQ_E_POST:
144 		bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
145 		break;
146 
147 	default:
148 		bfa_sm_fault(event);
149 	}
150 }
151 
152 static void
153 cmdq_sm_dbell_wait_entry(struct bfa_msgq_cmdq *cmdq)
154 {
155 	bfa_msgq_cmdq_dbell(cmdq);
156 }
157 
158 static void
159 cmdq_sm_dbell_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
160 {
161 	switch (event) {
162 	case CMDQ_E_STOP:
163 	case CMDQ_E_FAIL:
164 		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
165 		break;
166 
167 	case CMDQ_E_POST:
168 		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
169 		break;
170 
171 	case CMDQ_E_DB_READY:
172 		if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
173 			cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
174 			bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
175 		} else
176 			bfa_fsm_set_state(cmdq, cmdq_sm_ready);
177 		break;
178 
179 	default:
180 		bfa_sm_fault(event);
181 	}
182 }
183 
184 static void
185 bfa_msgq_cmdq_dbell_ready(void *arg)
186 {
187 	struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
188 	bfa_fsm_send_event(cmdq, CMDQ_E_DB_READY);
189 }
190 
191 static void
192 bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq)
193 {
194 	struct bfi_msgq_h2i_db *dbell =
195 		(struct bfi_msgq_h2i_db *)(&cmdq->dbell_mb.msg[0]);
196 
197 	memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
198 	bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_PI, 0);
199 	dbell->mh.mtag.i2htok = 0;
200 	dbell->idx.cmdq_pi = htons(cmdq->producer_index);
201 
202 	if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->dbell_mb,
203 				bfa_msgq_cmdq_dbell_ready, cmdq)) {
204 		bfa_msgq_cmdq_dbell_ready(cmdq);
205 	}
206 }
207 
208 static void
209 __cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd)
210 {
211 	size_t len = cmd->msg_size;
212 	int num_entries = 0;
213 	size_t to_copy;
214 	u8 *src, *dst;
215 
216 	src = (u8 *)cmd->msg_hdr;
217 	dst = (u8 *)cmdq->addr.kva;
218 	dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
219 
220 	while (len) {
221 		to_copy = (len < BFI_MSGQ_CMD_ENTRY_SIZE) ?
222 				len : BFI_MSGQ_CMD_ENTRY_SIZE;
223 		memcpy(dst, src, to_copy);
224 		len -= to_copy;
225 		src += BFI_MSGQ_CMD_ENTRY_SIZE;
226 		BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth);
227 		dst = (u8 *)cmdq->addr.kva;
228 		dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
229 		num_entries++;
230 	}
231 
232 }
233 
234 static void
235 bfa_msgq_cmdq_ci_update(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
236 {
237 	struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
238 	struct bfa_msgq_cmd_entry *cmd;
239 	int posted = 0;
240 
241 	cmdq->consumer_index = ntohs(dbell->idx.cmdq_ci);
242 
243 	/* Walk through pending list to see if the command can be posted */
244 	while (!list_empty(&cmdq->pending_q)) {
245 		cmd =
246 		(struct bfa_msgq_cmd_entry *)bfa_q_first(&cmdq->pending_q);
247 		if (ntohs(cmd->msg_hdr->num_entries) <=
248 			BFA_MSGQ_FREE_CNT(cmdq)) {
249 			list_del(&cmd->qe);
250 			__cmd_copy(cmdq, cmd);
251 			posted = 1;
252 			call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
253 		} else {
254 			break;
255 		}
256 	}
257 
258 	if (posted)
259 		bfa_fsm_send_event(cmdq, CMDQ_E_POST);
260 }
261 
262 static void
263 bfa_msgq_cmdq_copy_next(void *arg)
264 {
265 	struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
266 
267 	if (cmdq->bytes_to_copy)
268 		bfa_msgq_cmdq_copy_rsp(cmdq);
269 }
270 
271 static void
272 bfa_msgq_cmdq_copy_req(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
273 {
274 	struct bfi_msgq_i2h_cmdq_copy_req *req =
275 		(struct bfi_msgq_i2h_cmdq_copy_req *)mb;
276 
277 	cmdq->token = 0;
278 	cmdq->offset = ntohs(req->offset);
279 	cmdq->bytes_to_copy = ntohs(req->len);
280 	bfa_msgq_cmdq_copy_rsp(cmdq);
281 }
282 
283 static void
284 bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq)
285 {
286 	struct bfi_msgq_h2i_cmdq_copy_rsp *rsp =
287 		(struct bfi_msgq_h2i_cmdq_copy_rsp *)&cmdq->copy_mb.msg[0];
288 	int copied;
289 	u8 *addr = (u8 *)cmdq->addr.kva;
290 
291 	memset(rsp, 0, sizeof(struct bfi_msgq_h2i_cmdq_copy_rsp));
292 	bfi_h2i_set(rsp->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_CMDQ_COPY_RSP, 0);
293 	rsp->mh.mtag.i2htok = htons(cmdq->token);
294 	copied = (cmdq->bytes_to_copy >= BFI_CMD_COPY_SZ) ? BFI_CMD_COPY_SZ :
295 		cmdq->bytes_to_copy;
296 	addr += cmdq->offset;
297 	memcpy(rsp->data, addr, copied);
298 
299 	cmdq->token++;
300 	cmdq->offset += copied;
301 	cmdq->bytes_to_copy -= copied;
302 
303 	if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->copy_mb,
304 				bfa_msgq_cmdq_copy_next, cmdq)) {
305 		bfa_msgq_cmdq_copy_next(cmdq);
306 	}
307 }
308 
309 static void
310 bfa_msgq_cmdq_attach(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq *msgq)
311 {
312 	cmdq->depth = BFA_MSGQ_CMDQ_NUM_ENTRY;
313 	INIT_LIST_HEAD(&cmdq->pending_q);
314 	cmdq->msgq = msgq;
315 	bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
316 }
317 
318 static void bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq);
319 
320 enum rspq_event {
321 	RSPQ_E_START			= 1,
322 	RSPQ_E_STOP			= 2,
323 	RSPQ_E_FAIL			= 3,
324 	RSPQ_E_RESP			= 4,
325 	RSPQ_E_INIT_RESP		= 5,
326 	RSPQ_E_DB_READY			= 6,
327 };
328 
329 bfa_fsm_state_decl(rspq, stopped, struct bfa_msgq_rspq, enum rspq_event);
330 bfa_fsm_state_decl(rspq, init_wait, struct bfa_msgq_rspq,
331 			enum rspq_event);
332 bfa_fsm_state_decl(rspq, ready, struct bfa_msgq_rspq, enum rspq_event);
333 bfa_fsm_state_decl(rspq, dbell_wait, struct bfa_msgq_rspq,
334 			enum rspq_event);
335 
336 static void
337 rspq_sm_stopped_entry(struct bfa_msgq_rspq *rspq)
338 {
339 	rspq->producer_index = 0;
340 	rspq->consumer_index = 0;
341 	rspq->flags = 0;
342 }
343 
344 static void
345 rspq_sm_stopped(struct bfa_msgq_rspq *rspq, enum rspq_event event)
346 {
347 	switch (event) {
348 	case RSPQ_E_START:
349 		bfa_fsm_set_state(rspq, rspq_sm_init_wait);
350 		break;
351 
352 	case RSPQ_E_STOP:
353 	case RSPQ_E_FAIL:
354 		/* No-op */
355 		break;
356 
357 	default:
358 		bfa_sm_fault(event);
359 	}
360 }
361 
362 static void
363 rspq_sm_init_wait_entry(struct bfa_msgq_rspq *rspq)
364 {
365 	bfa_wc_down(&rspq->msgq->init_wc);
366 }
367 
368 static void
369 rspq_sm_init_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
370 {
371 	switch (event) {
372 	case RSPQ_E_FAIL:
373 	case RSPQ_E_STOP:
374 		bfa_fsm_set_state(rspq, rspq_sm_stopped);
375 		break;
376 
377 	case RSPQ_E_INIT_RESP:
378 		bfa_fsm_set_state(rspq, rspq_sm_ready);
379 		break;
380 
381 	default:
382 		bfa_sm_fault(event);
383 	}
384 }
385 
386 static void
387 rspq_sm_ready_entry(struct bfa_msgq_rspq *rspq)
388 {
389 }
390 
391 static void
392 rspq_sm_ready(struct bfa_msgq_rspq *rspq, enum rspq_event event)
393 {
394 	switch (event) {
395 	case RSPQ_E_STOP:
396 	case RSPQ_E_FAIL:
397 		bfa_fsm_set_state(rspq, rspq_sm_stopped);
398 		break;
399 
400 	case RSPQ_E_RESP:
401 		bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
402 		break;
403 
404 	default:
405 		bfa_sm_fault(event);
406 	}
407 }
408 
409 static void
410 rspq_sm_dbell_wait_entry(struct bfa_msgq_rspq *rspq)
411 {
412 	if (!bfa_nw_ioc_is_disabled(rspq->msgq->ioc))
413 		bfa_msgq_rspq_dbell(rspq);
414 }
415 
416 static void
417 rspq_sm_dbell_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
418 {
419 	switch (event) {
420 	case RSPQ_E_STOP:
421 	case RSPQ_E_FAIL:
422 		bfa_fsm_set_state(rspq, rspq_sm_stopped);
423 		break;
424 
425 	case RSPQ_E_RESP:
426 		rspq->flags |= BFA_MSGQ_RSPQ_F_DB_UPDATE;
427 		break;
428 
429 	case RSPQ_E_DB_READY:
430 		if (rspq->flags & BFA_MSGQ_RSPQ_F_DB_UPDATE) {
431 			rspq->flags &= ~BFA_MSGQ_RSPQ_F_DB_UPDATE;
432 			bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
433 		} else
434 			bfa_fsm_set_state(rspq, rspq_sm_ready);
435 		break;
436 
437 	default:
438 		bfa_sm_fault(event);
439 	}
440 }
441 
442 static void
443 bfa_msgq_rspq_dbell_ready(void *arg)
444 {
445 	struct bfa_msgq_rspq *rspq = (struct bfa_msgq_rspq *)arg;
446 	bfa_fsm_send_event(rspq, RSPQ_E_DB_READY);
447 }
448 
449 static void
450 bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq)
451 {
452 	struct bfi_msgq_h2i_db *dbell =
453 		(struct bfi_msgq_h2i_db *)(&rspq->dbell_mb.msg[0]);
454 
455 	memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
456 	bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_CI, 0);
457 	dbell->mh.mtag.i2htok = 0;
458 	dbell->idx.rspq_ci = htons(rspq->consumer_index);
459 
460 	if (!bfa_nw_ioc_mbox_queue(rspq->msgq->ioc, &rspq->dbell_mb,
461 				bfa_msgq_rspq_dbell_ready, rspq)) {
462 		bfa_msgq_rspq_dbell_ready(rspq);
463 	}
464 }
465 
466 static void
467 bfa_msgq_rspq_pi_update(struct bfa_msgq_rspq *rspq, struct bfi_mbmsg *mb)
468 {
469 	struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
470 	struct bfi_msgq_mhdr *msghdr;
471 	int num_entries;
472 	int mc;
473 	u8 *rspq_qe;
474 
475 	rspq->producer_index = ntohs(dbell->idx.rspq_pi);
476 
477 	while (rspq->consumer_index != rspq->producer_index) {
478 		rspq_qe = (u8 *)rspq->addr.kva;
479 		rspq_qe += (rspq->consumer_index * BFI_MSGQ_RSP_ENTRY_SIZE);
480 		msghdr = (struct bfi_msgq_mhdr *)rspq_qe;
481 
482 		mc = msghdr->msg_class;
483 		num_entries = ntohs(msghdr->num_entries);
484 
485 		if ((mc >= BFI_MC_MAX) || (rspq->rsphdlr[mc].cbfn == NULL))
486 			break;
487 
488 		(rspq->rsphdlr[mc].cbfn)(rspq->rsphdlr[mc].cbarg, msghdr);
489 
490 		BFA_MSGQ_INDX_ADD(rspq->consumer_index, num_entries,
491 				rspq->depth);
492 	}
493 
494 	bfa_fsm_send_event(rspq, RSPQ_E_RESP);
495 }
496 
497 static void
498 bfa_msgq_rspq_attach(struct bfa_msgq_rspq *rspq, struct bfa_msgq *msgq)
499 {
500 	rspq->depth = BFA_MSGQ_RSPQ_NUM_ENTRY;
501 	rspq->msgq = msgq;
502 	bfa_fsm_set_state(rspq, rspq_sm_stopped);
503 }
504 
505 static void
506 bfa_msgq_init_rsp(struct bfa_msgq *msgq,
507 		 struct bfi_mbmsg *mb)
508 {
509 	bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_INIT_RESP);
510 	bfa_fsm_send_event(&msgq->rspq, RSPQ_E_INIT_RESP);
511 }
512 
513 static void
514 bfa_msgq_init(void *arg)
515 {
516 	struct bfa_msgq *msgq = (struct bfa_msgq *)arg;
517 	struct bfi_msgq_cfg_req *msgq_cfg =
518 		(struct bfi_msgq_cfg_req *)&msgq->init_mb.msg[0];
519 
520 	memset(msgq_cfg, 0, sizeof(struct bfi_msgq_cfg_req));
521 	bfi_h2i_set(msgq_cfg->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_INIT_REQ, 0);
522 	msgq_cfg->mh.mtag.i2htok = 0;
523 
524 	bfa_dma_be_addr_set(msgq_cfg->cmdq.addr, msgq->cmdq.addr.pa);
525 	msgq_cfg->cmdq.q_depth = htons(msgq->cmdq.depth);
526 	bfa_dma_be_addr_set(msgq_cfg->rspq.addr, msgq->rspq.addr.pa);
527 	msgq_cfg->rspq.q_depth = htons(msgq->rspq.depth);
528 
529 	bfa_nw_ioc_mbox_queue(msgq->ioc, &msgq->init_mb, NULL, NULL);
530 }
531 
532 static void
533 bfa_msgq_isr(void *cbarg, struct bfi_mbmsg *msg)
534 {
535 	struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
536 
537 	switch (msg->mh.msg_id) {
538 	case BFI_MSGQ_I2H_INIT_RSP:
539 		bfa_msgq_init_rsp(msgq, msg);
540 		break;
541 
542 	case BFI_MSGQ_I2H_DOORBELL_PI:
543 		bfa_msgq_rspq_pi_update(&msgq->rspq, msg);
544 		break;
545 
546 	case BFI_MSGQ_I2H_DOORBELL_CI:
547 		bfa_msgq_cmdq_ci_update(&msgq->cmdq, msg);
548 		break;
549 
550 	case BFI_MSGQ_I2H_CMDQ_COPY_REQ:
551 		bfa_msgq_cmdq_copy_req(&msgq->cmdq, msg);
552 		break;
553 
554 	default:
555 		BUG_ON(1);
556 	}
557 }
558 
559 static void
560 bfa_msgq_notify(void *cbarg, enum bfa_ioc_event event)
561 {
562 	struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
563 
564 	switch (event) {
565 	case BFA_IOC_E_ENABLED:
566 		bfa_wc_init(&msgq->init_wc, bfa_msgq_init, msgq);
567 		bfa_wc_up(&msgq->init_wc);
568 		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_START);
569 		bfa_wc_up(&msgq->init_wc);
570 		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_START);
571 		bfa_wc_wait(&msgq->init_wc);
572 		break;
573 
574 	case BFA_IOC_E_DISABLED:
575 		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_STOP);
576 		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_STOP);
577 		break;
578 
579 	case BFA_IOC_E_FAILED:
580 		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_FAIL);
581 		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_FAIL);
582 		break;
583 
584 	default:
585 		break;
586 	}
587 }
588 
589 u32
590 bfa_msgq_meminfo(void)
591 {
592 	return roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ) +
593 		roundup(BFA_MSGQ_RSPQ_SIZE, BFA_DMA_ALIGN_SZ);
594 }
595 
596 void
597 bfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa)
598 {
599 	msgq->cmdq.addr.kva = kva;
600 	msgq->cmdq.addr.pa  = pa;
601 
602 	kva += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
603 	pa += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
604 
605 	msgq->rspq.addr.kva = kva;
606 	msgq->rspq.addr.pa = pa;
607 }
608 
609 void
610 bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc)
611 {
612 	msgq->ioc    = ioc;
613 
614 	bfa_msgq_cmdq_attach(&msgq->cmdq, msgq);
615 	bfa_msgq_rspq_attach(&msgq->rspq, msgq);
616 
617 	bfa_nw_ioc_mbox_regisr(msgq->ioc, BFI_MC_MSGQ, bfa_msgq_isr, msgq);
618 	bfa_q_qe_init(&msgq->ioc_notify);
619 	bfa_ioc_notify_init(&msgq->ioc_notify, bfa_msgq_notify, msgq);
620 	bfa_nw_ioc_notify_register(msgq->ioc, &msgq->ioc_notify);
621 }
622 
623 void
624 bfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
625 		bfa_msgq_mcfunc_t cbfn, void *cbarg)
626 {
627 	msgq->rspq.rsphdlr[mc].cbfn	= cbfn;
628 	msgq->rspq.rsphdlr[mc].cbarg	= cbarg;
629 }
630 
631 void
632 bfa_msgq_cmd_post(struct bfa_msgq *msgq,  struct bfa_msgq_cmd_entry *cmd)
633 {
634 	if (ntohs(cmd->msg_hdr->num_entries) <=
635 		BFA_MSGQ_FREE_CNT(&msgq->cmdq)) {
636 		__cmd_copy(&msgq->cmdq, cmd);
637 		call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
638 		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_POST);
639 	} else {
640 		list_add_tail(&cmd->qe, &msgq->cmdq.pending_q);
641 	}
642 }
643 
644 void
645 bfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len)
646 {
647 	struct bfa_msgq_rspq *rspq = &msgq->rspq;
648 	size_t len = buf_len;
649 	size_t to_copy;
650 	int ci;
651 	u8 *src, *dst;
652 
653 	ci = rspq->consumer_index;
654 	src = (u8 *)rspq->addr.kva;
655 	src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
656 	dst = buf;
657 
658 	while (len) {
659 		to_copy = (len < BFI_MSGQ_RSP_ENTRY_SIZE) ?
660 				len : BFI_MSGQ_RSP_ENTRY_SIZE;
661 		memcpy(dst, src, to_copy);
662 		len -= to_copy;
663 		dst += BFI_MSGQ_RSP_ENTRY_SIZE;
664 		BFA_MSGQ_INDX_ADD(ci, 1, rspq->depth);
665 		src = (u8 *)rspq->addr.kva;
666 		src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
667 	}
668 }
669