1/*-
2 * Copyright (C) 2012 Emulex
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the Emulex Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Contact Information:
32 * freebsd-drivers@emulex.com
33 *
34 * Emulex
35 * 3333 Susan Street
36 * Costa Mesa, CA 92626
37 */
38
39
40
41/* $FreeBSD: head/sys/dev/oce/oce_mbox.c 231437 2012-02-10 21:03:04Z luigi $ */
42
43
44#include "oce_if.h"
45
46
47/**
48 * @brief Reset (firmware) common function
49 * @param sc software handle to the device
50 * @returns 0 on success, ETIMEDOUT on failure
51 */
52int
53oce_reset_fun(POCE_SOFTC sc)
54{
55 struct oce_mbx *mbx;
56 struct oce_bmbx *mb;
57 struct ioctl_common_function_reset *fwcmd;
58 int rc = 0;
59
60 if (sc->flags & OCE_FLAGS_FUNCRESET_RQD) {
61 mb = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
62 mbx = &mb->mbx;
63 bzero(mbx, sizeof(struct oce_mbx));
64
65 fwcmd = (struct ioctl_common_function_reset *)&mbx->payload;
66 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
67 MBX_SUBSYSTEM_COMMON,
68 OPCODE_COMMON_FUNCTION_RESET,
69 10, /* MBX_TIMEOUT_SEC */
70 sizeof(struct
71 ioctl_common_function_reset),
72 OCE_MBX_VER_V0);
73
74 mbx->u0.s.embedded = 1;
75 mbx->payload_length =
76 sizeof(struct ioctl_common_function_reset);
77
78 rc = oce_mbox_dispatch(sc, 2);
79 }
80
81 return rc;
82}
83
84
85/**
86 * @brief This funtions tells firmware we are
87 * done with commands.
88 * @param sc software handle to the device
89 * @returns 0 on success, ETIMEDOUT on failure
90 */
91int
92oce_fw_clean(POCE_SOFTC sc)
93{
94 struct oce_bmbx *mbx;
95 uint8_t *ptr;
96 int ret = 0;
97
98 mbx = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
99 ptr = (uint8_t *) &mbx->mbx;
100
101 /* Endian Signature */
102 *ptr++ = 0xff;
103 *ptr++ = 0xaa;
104 *ptr++ = 0xbb;
105 *ptr++ = 0xff;
106 *ptr++ = 0xff;
107 *ptr++ = 0xcc;
108 *ptr++ = 0xdd;
109 *ptr = 0xff;
110
111 ret = oce_mbox_dispatch(sc, 2);
112
113 return ret;
114}
115
116
117/**
118 * @brief Mailbox wait
119 * @param sc software handle to the device
120 * @param tmo_sec timeout in seconds
121 */
122static int
123oce_mbox_wait(POCE_SOFTC sc, uint32_t tmo_sec)
124{
125 tmo_sec *= 10000;
126 pd_mpu_mbox_db_t mbox_db;
127
128 for (;;) {
129 if (tmo_sec != 0) {
130 if (--tmo_sec == 0)
131 break;
132 }
133
134 mbox_db.dw0 = OCE_READ_REG32(sc, db, PD_MPU_MBOX_DB);
135
136 if (mbox_db.bits.ready)
137 return 0;
138
139 DELAY(100);
140 }
141
142 device_printf(sc->dev, "Mailbox timed out\n");
143
144 return ETIMEDOUT;
145}
146
147
148
149/**
150 * @brief Mailbox dispatch
151 * @param sc software handle to the device
152 * @param tmo_sec timeout in seconds
153 */
154int
155oce_mbox_dispatch(POCE_SOFTC sc, uint32_t tmo_sec)
156{
157 pd_mpu_mbox_db_t mbox_db;
158 uint32_t pa;
159 int rc;
160
161 oce_dma_sync(&sc->bsmbx, BUS_DMASYNC_PREWRITE);
162 pa = (uint32_t) ((uint64_t) sc->bsmbx.paddr >> 34);
163 bzero(&mbox_db, sizeof(pd_mpu_mbox_db_t));
164 mbox_db.bits.ready = 0;
165 mbox_db.bits.hi = 1;
166 mbox_db.bits.address = pa;
167
168 rc = oce_mbox_wait(sc, tmo_sec);
169 if (rc == 0) {
170 OCE_WRITE_REG32(sc, db, PD_MPU_MBOX_DB, mbox_db.dw0);
171
172 pa = (uint32_t) ((uint64_t) sc->bsmbx.paddr >> 4) & 0x3fffffff;
173 mbox_db.bits.ready = 0;
174 mbox_db.bits.hi = 0;
175 mbox_db.bits.address = pa;
176
177 rc = oce_mbox_wait(sc, tmo_sec);
178
179 if (rc == 0) {
180 OCE_WRITE_REG32(sc, db, PD_MPU_MBOX_DB, mbox_db.dw0);
181
182 rc = oce_mbox_wait(sc, tmo_sec);
183
184 oce_dma_sync(&sc->bsmbx, BUS_DMASYNC_POSTWRITE);
185 }
186 }
187
188 return rc;
189}
190
191
192
193/**
194 * @brief Mailbox common request header initialization
195 * @param hdr mailbox header
196 * @param dom domain
197 * @param port port
198 * @param subsys subsystem
199 * @param opcode opcode
200 * @param timeout timeout
201 * @param pyld_len payload length
202 */
203void
204mbx_common_req_hdr_init(struct mbx_hdr *hdr,
205 uint8_t dom, uint8_t port,
206 uint8_t subsys, uint8_t opcode,
207 uint32_t timeout, uint32_t pyld_len,
208 uint8_t version)
209{
210 hdr->u0.req.opcode = opcode;
211 hdr->u0.req.subsystem = subsys;
212 hdr->u0.req.port_number = port;
213 hdr->u0.req.domain = dom;
214
215 hdr->u0.req.timeout = timeout;
216 hdr->u0.req.request_length = pyld_len - sizeof(struct mbx_hdr);
217 hdr->u0.req.version = version;
218}
219
220
221
222/**
223 * @brief Function to initialize the hw with host endian information
224 * @param sc software handle to the device
225 * @returns 0 on success, ETIMEDOUT on failure
226 */
227int
228oce_mbox_init(POCE_SOFTC sc)
229{
230 struct oce_bmbx *mbx;
231 uint8_t *ptr;
232 int ret = 0;
233
234 if (sc->flags & OCE_FLAGS_MBOX_ENDIAN_RQD) {
235 mbx = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
236 ptr = (uint8_t *) &mbx->mbx;
237
238 /* Endian Signature */
239 *ptr++ = 0xff;
240 *ptr++ = 0x12;
241 *ptr++ = 0x34;
242 *ptr++ = 0xff;
243 *ptr++ = 0xff;
244 *ptr++ = 0x56;
245 *ptr++ = 0x78;
246 *ptr = 0xff;
247
248 ret = oce_mbox_dispatch(sc, 0);
249 }
250
251 return ret;
252}
253
254
255/**
256 * @brief Function to get the firmware version
257 * @param sc software handle to the device
258 * @returns 0 on success, EIO on failure
259 */
260int
261oce_get_fw_version(POCE_SOFTC sc)
262{
263 struct oce_mbx mbx;
264 struct mbx_get_common_fw_version *fwcmd;
265 int ret = 0;
266
267 bzero(&mbx, sizeof(struct oce_mbx));
268
269 fwcmd = (struct mbx_get_common_fw_version *)&mbx.payload;
270 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
271 MBX_SUBSYSTEM_COMMON,
272 OPCODE_COMMON_GET_FW_VERSION,
273 MBX_TIMEOUT_SEC,
274 sizeof(struct mbx_get_common_fw_version),
275 OCE_MBX_VER_V0);
276
277 mbx.u0.s.embedded = 1;
278 mbx.payload_length = sizeof(struct mbx_get_common_fw_version);
279 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
280
281 ret = oce_mbox_post(sc, &mbx, NULL);
282 if (ret)
283 return ret;
284
285 bcopy(fwcmd->params.rsp.fw_ver_str, sc->fw_version, 32);
286
287 return 0;
288}
289
290
291/**
292 * @brief Function to post a MBX to the mbox
293 * @param sc software handle to the device
294 * @param mbx pointer to the MBX to send
295 * @param mbxctx pointer to the mbx context structure
296 * @returns 0 on success, error on failure
297 */
298int
299oce_mbox_post(POCE_SOFTC sc, struct oce_mbx *mbx, struct oce_mbx_ctx *mbxctx)
300{
301 struct oce_mbx *mb_mbx = NULL;
302 struct oce_mq_cqe *mb_cqe = NULL;
303 struct oce_bmbx *mb = NULL;
304 int rc = 0;
305 uint32_t tmo = 0;
306 uint32_t cstatus = 0;
307 uint32_t xstatus = 0;
308
309 LOCK(&sc->bmbx_lock);
310
311 mb = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
312 mb_mbx = &mb->mbx;
313
314 /* get the tmo */
315 tmo = mbx->tag[0];
316 mbx->tag[0] = 0;
317
318 /* copy mbx into mbox */
319 bcopy(mbx, mb_mbx, sizeof(struct oce_mbx));
320
321 /* now dispatch */
322 rc = oce_mbox_dispatch(sc, tmo);
323 if (rc == 0) {
324 /*
325 * the command completed successfully. Now get the
326 * completion queue entry
327 */
328 mb_cqe = &mb->cqe;
329 DW_SWAP(u32ptr(&mb_cqe->u0.dw[0]), sizeof(struct oce_mq_cqe));
330
331 /* copy mbox mbx back */
332 bcopy(mb_mbx, mbx, sizeof(struct oce_mbx));
333
334 /* pick up the mailbox status */
335 cstatus = mb_cqe->u0.s.completion_status;
336 xstatus = mb_cqe->u0.s.extended_status;
337
338 /*
339 * store the mbx context in the cqe tag section so that
340 * the upper layer handling the cqe can associate the mbx
341 * with the response
342 */
343 if (cstatus == 0 && mbxctx) {
344 /* save context */
345 mbxctx->mbx = mb_mbx;
346 bcopy(&mbxctx, mb_cqe->u0.s.mq_tag,
347 sizeof(struct oce_mbx_ctx *));
348 }
349 }
350
351 UNLOCK(&sc->bmbx_lock);
352
353 return rc;
354}
355
356/**
357 * @brief Function to read the mac address associated with an interface
358 * @param sc software handle to the device
359 * @param if_id interface id to read the address from
360 * @param perm set to 1 if reading the factory mac address.
361 * In this case if_id is ignored
362 * @param type type of the mac address, whether network or storage
363 * @param[out] mac [OUTPUT] pointer to a buffer containing the
364 * mac address when the command succeeds.
365 * @returns 0 on success, EIO on failure
366 */
367int
368oce_read_mac_addr(POCE_SOFTC sc, uint32_t if_id,
369 uint8_t perm, uint8_t type, struct mac_address_format *mac)
370{
371 struct oce_mbx mbx;
372 struct mbx_query_common_iface_mac *fwcmd;
373 int ret = 0;
374
375 bzero(&mbx, sizeof(struct oce_mbx));
376
377 fwcmd = (struct mbx_query_common_iface_mac *)&mbx.payload;
378 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
379 MBX_SUBSYSTEM_COMMON,
380 OPCODE_COMMON_QUERY_IFACE_MAC,
381 MBX_TIMEOUT_SEC,
382 sizeof(struct mbx_query_common_iface_mac),
383 OCE_MBX_VER_V0);
384
385 fwcmd->params.req.permanent = perm;
386 if (!perm)
387 fwcmd->params.req.if_id = (uint16_t) if_id;
388 else
389 fwcmd->params.req.if_id = 0;
390
391 fwcmd->params.req.type = type;
392
393 mbx.u0.s.embedded = 1;
394 mbx.payload_length = sizeof(struct mbx_query_common_iface_mac);
395 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
396
397 ret = oce_mbox_post(sc, &mbx, NULL);
398 if (ret)
399 return ret;
400
401 /* copy the mac addres in the output parameter */
402 mac->size_of_struct = fwcmd->params.rsp.mac.size_of_struct;
403 bcopy(&fwcmd->params.rsp.mac.mac_addr[0], &mac->mac_addr[0],
404 mac->size_of_struct);
405
406 return 0;
407}
408
409/**
410 * @brief Function to query the fw attributes from the hw
411 * @param sc software handle to the device
412 * @returns 0 on success, EIO on failure
413 */
414int
415oce_get_fw_config(POCE_SOFTC sc)
416{
417 struct oce_mbx mbx;
418 struct mbx_common_query_fw_config *fwcmd;
419 int ret = 0;
420
421 bzero(&mbx, sizeof(struct oce_mbx));
422
423 fwcmd = (struct mbx_common_query_fw_config *)&mbx.payload;
424 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
425 MBX_SUBSYSTEM_COMMON,
426 OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
427 MBX_TIMEOUT_SEC,
428 sizeof(struct mbx_common_query_fw_config),
429 OCE_MBX_VER_V0);
430
431 mbx.u0.s.embedded = 1;
432 mbx.payload_length = sizeof(struct mbx_common_query_fw_config);
433 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
434
435 ret = oce_mbox_post(sc, &mbx, NULL);
436 if (ret)
437 return ret;
438
439 DW_SWAP(u32ptr(fwcmd), sizeof(struct mbx_common_query_fw_config));
440
441 sc->config_number = fwcmd->params.rsp.config_number;
442 sc->asic_revision = fwcmd->params.rsp.asic_revision;
443 sc->port_id = fwcmd->params.rsp.port_id;
444 sc->function_mode = fwcmd->params.rsp.function_mode;
445 sc->function_caps = fwcmd->params.rsp.function_caps;
446
447 if (fwcmd->params.rsp.ulp[0].ulp_mode & ULP_NIC_MODE) {
448 sc->max_tx_rings = fwcmd->params.rsp.ulp[0].nic_wq_tot;
449 sc->max_rx_rings = fwcmd->params.rsp.ulp[0].lro_rqid_tot;
450 } else {
451 sc->max_tx_rings = fwcmd->params.rsp.ulp[1].nic_wq_tot;
452 sc->max_rx_rings = fwcmd->params.rsp.ulp[1].lro_rqid_tot;
453 }
454
455 return 0;
456
457}
458
459/**
460 *
461 * @brief function to create a device interface
462 * @param sc software handle to the device
463 * @param cap_flags capability flags
464 * @param en_flags enable capability flags
465 * @param vlan_tag optional vlan tag to associate with the if
466 * @param mac_addr pointer to a buffer containing the mac address
467 * @param[out] if_id [OUTPUT] pointer to an integer to hold the ID of the
468 interface created
469 * @returns 0 on success, EIO on failure
470 */
471int
472oce_if_create(POCE_SOFTC sc,
473 uint32_t cap_flags,
474 uint32_t en_flags,
475 uint16_t vlan_tag,
476 uint8_t *mac_addr,
477 uint32_t *if_id)
478{
479 struct oce_mbx mbx;
480 struct mbx_create_common_iface *fwcmd;
481 int rc = 0;
482
483 bzero(&mbx, sizeof(struct oce_mbx));
484
485 fwcmd = (struct mbx_create_common_iface *)&mbx.payload;
486 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
487 MBX_SUBSYSTEM_COMMON,
488 OPCODE_COMMON_CREATE_IFACE,
489 MBX_TIMEOUT_SEC,
490 sizeof(struct mbx_create_common_iface),
491 OCE_MBX_VER_V0);
492 DW_SWAP(u32ptr(&fwcmd->hdr), sizeof(struct mbx_hdr));
493
494 fwcmd->params.req.version = 0;
495 fwcmd->params.req.cap_flags = LE_32(cap_flags);
496 fwcmd->params.req.enable_flags = LE_32(en_flags);
497 if (mac_addr != NULL) {
498 bcopy(mac_addr, &fwcmd->params.req.mac_addr[0], 6);
499 fwcmd->params.req.vlan_tag.u0.normal.vtag = LE_16(vlan_tag);
500 fwcmd->params.req.mac_invalid = 0;
501 } else {
502 fwcmd->params.req.mac_invalid = 1;
503 }
504
505 mbx.u0.s.embedded = 1;
506 mbx.payload_length = sizeof(struct mbx_create_common_iface);
507 DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ);
508
509 rc = oce_mbox_post(sc, &mbx, NULL);
510 if (rc)
511 return rc;
512
513 *if_id = LE_32(fwcmd->params.rsp.if_id);
514
515 if (mac_addr != NULL)
516 sc->pmac_id = LE_32(fwcmd->params.rsp.pmac_id);
517
518 return 0;
519}
520
521/**
522 * @brief Function to delete an interface
523 * @param sc software handle to the device
524 * @param if_id ID of the interface to delete
525 * @returns 0 on success, EIO on failure
526 */
527int
528oce_if_del(POCE_SOFTC sc, uint32_t if_id)
529{
530 struct oce_mbx mbx;
531 struct mbx_destroy_common_iface *fwcmd;
532 int rc = 0;
533
534 bzero(&mbx, sizeof(struct oce_mbx));
535
536 fwcmd = (struct mbx_destroy_common_iface *)&mbx.payload;
537 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
538 MBX_SUBSYSTEM_COMMON,
539 OPCODE_COMMON_DESTROY_IFACE,
540 MBX_TIMEOUT_SEC,
541 sizeof(struct mbx_destroy_common_iface),
542 OCE_MBX_VER_V0);
543
544 fwcmd->params.req.if_id = if_id;
545
546 mbx.u0.s.embedded = 1;
547 mbx.payload_length = sizeof(struct mbx_destroy_common_iface);
548 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
549
550 rc = oce_mbox_post(sc, &mbx, NULL);
551 return rc;
552}
553
554/**
555 * @brief Function to send the mbx command to configure vlan
556 * @param sc software handle to the device
557 * @param if_id interface identifier index
558 * @param vtag_arr array of vlan tags
559 * @param vtag_cnt number of elements in array
560 * @param untagged boolean TRUE/FLASE
561 * @param enable_promisc flag to enable/disable VLAN promiscuous mode
562 * @returns 0 on success, EIO on failure
563 */
564int
565oce_config_vlan(POCE_SOFTC sc,
566 uint32_t if_id,
567 struct normal_vlan *vtag_arr,
568 uint8_t vtag_cnt, uint32_t untagged, uint32_t enable_promisc)
569{
570 struct oce_mbx mbx;
571 struct mbx_common_config_vlan *fwcmd;
572 int rc;
573
574 bzero(&mbx, sizeof(struct oce_mbx));
575 fwcmd = (struct mbx_common_config_vlan *)&mbx.payload;
576
577 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
578 MBX_SUBSYSTEM_COMMON,
579 OPCODE_COMMON_CONFIG_IFACE_VLAN,
580 MBX_TIMEOUT_SEC,
581 sizeof(struct mbx_common_config_vlan),
582 OCE_MBX_VER_V0);
583
584 fwcmd->params.req.if_id = (uint8_t) if_id;
585 fwcmd->params.req.promisc = (uint8_t) enable_promisc;
586 fwcmd->params.req.untagged = (uint8_t) untagged;
587 fwcmd->params.req.num_vlans = vtag_cnt;
588
589 if (!enable_promisc) {
590 bcopy(vtag_arr, fwcmd->params.req.tags.normal_vlans,
591 vtag_cnt * sizeof(struct normal_vlan));
592 }
593 mbx.u0.s.embedded = 1;
594 mbx.payload_length = sizeof(struct mbx_common_config_vlan);
595 DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + mbx.payload_length));
596
597 rc = oce_mbox_post(sc, &mbx, NULL);
598
599 return rc;
600
601}
602
603/**
604 * @brief Function to set flow control capability in the hardware
605 * @param sc software handle to the device
606 * @param flow_control flow control flags to set
607 * @returns 0 on success, EIO on failure
608 */
609int
610oce_set_flow_control(POCE_SOFTC sc, uint32_t flow_control)
611{
612 struct oce_mbx mbx;
613 struct mbx_common_get_set_flow_control *fwcmd =
614 (struct mbx_common_get_set_flow_control *)&mbx.payload;
615 int rc;
616
617 bzero(&mbx, sizeof(struct oce_mbx));
618
619 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
620 MBX_SUBSYSTEM_COMMON,
621 OPCODE_COMMON_SET_FLOW_CONTROL,
622 MBX_TIMEOUT_SEC,
623 sizeof(struct mbx_common_get_set_flow_control),
624 OCE_MBX_VER_V0);
625
626 if (flow_control & OCE_FC_TX)
627 fwcmd->tx_flow_control = 1;
628
629 if (flow_control & OCE_FC_RX)
630 fwcmd->rx_flow_control = 1;
631
632 mbx.u0.s.embedded = 1;
633 mbx.payload_length = sizeof(struct mbx_common_get_set_flow_control);
634 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
635
636 rc = oce_mbox_post(sc, &mbx, NULL);
637
638 return rc;
639}
640
641/**
642 * @brief Initialize the RSS CPU indirection table
643 *
644 * The table is used to choose the queue to place the incomming packets.
645 * Incomming packets are hashed. The lowest bits in the hash result
646 * are used as the index into the CPU indirection table.
647 * Each entry in the table contains the RSS CPU-ID returned by the NIC
648 * create. Based on the CPU ID, the receive completion is routed to
649 * the corresponding RSS CQs. (Non-RSS packets are always completed
650 * on the default (0) CQ).
651 *
652 * @param sc software handle to the device
653 * @param *fwcmd pointer to the rss mbox command
654 * @returns none
655 */
656static int
657oce_rss_itbl_init(POCE_SOFTC sc, struct mbx_config_nic_rss *fwcmd)
658{
659 int i = 0, j = 0, rc = 0;
660 uint8_t *tbl = fwcmd->params.req.cputable;
661
662
663 for (j = 0; j < sc->nrqs; j++) {
664 if (sc->rq[j]->cfg.is_rss_queue) {
665 tbl[i] = sc->rq[j]->rss_cpuid;
666 i = i + 1;
667 }
668 }
669 if (i == 0) {
670 device_printf(sc->dev, "error: Invalid number of RSS RQ's\n");
671 rc = ENXIO;
672
673 }
674
675 /* fill log2 value indicating the size of the CPU table */
676 if (rc == 0)
677 fwcmd->params.req.cpu_tbl_sz_log2 = LE_16(OCE_LOG2(i));
678
679 return rc;
680}
681
682/**
683 * @brief Function to set flow control capability in the hardware
684 * @param sc software handle to the device
685 * @param if_id interface id to read the address from
686 * @param enable_rss 0=disable, RSS_ENABLE_xxx flags otherwise
687 * @returns 0 on success, EIO on failure
688 */
689int
690oce_config_nic_rss(POCE_SOFTC sc, uint32_t if_id, uint16_t enable_rss)
691{
692 int rc;
693 struct oce_mbx mbx;
694 struct mbx_config_nic_rss *fwcmd =
695 (struct mbx_config_nic_rss *)&mbx.payload;
696
697 bzero(&mbx, sizeof(struct oce_mbx));
698
699 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
700 MBX_SUBSYSTEM_NIC,
701 NIC_CONFIG_RSS,
702 MBX_TIMEOUT_SEC,
703 sizeof(struct mbx_config_nic_rss),
704 OCE_MBX_VER_V0);
705 if (enable_rss)
706 fwcmd->params.req.enable_rss = (RSS_ENABLE_IPV4 |
707 RSS_ENABLE_TCP_IPV4 |
708 RSS_ENABLE_IPV6 |
709 RSS_ENABLE_TCP_IPV6);
710 fwcmd->params.req.flush = OCE_FLUSH;
711 fwcmd->params.req.if_id = LE_32(if_id);
712
713 srandom(arc4random()); /* random entropy seed */
714 read_random(fwcmd->params.req.hash, sizeof(fwcmd->params.req.hash));
715
716 rc = oce_rss_itbl_init(sc, fwcmd);
717 if (rc == 0) {
718 mbx.u0.s.embedded = 1;
719 mbx.payload_length = sizeof(struct mbx_config_nic_rss);
720 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
721
722 rc = oce_mbox_post(sc, &mbx, NULL);
723
724 }
725
726 return rc;
727}
728
729/**
730 * @brief RXF function to enable/disable device promiscuous mode
731 * @param sc software handle to the device
732 * @param enable enable/disable flag
733 * @returns 0 on success, EIO on failure
734 * @note
735 * The NIC_CONFIG_PROMISCUOUS command deprecated for Lancer.
736 * This function uses the COMMON_SET_IFACE_RX_FILTER command instead.
737 */
738int
739oce_rxf_set_promiscuous(POCE_SOFTC sc, uint32_t enable)
740{
741 struct mbx_set_common_iface_rx_filter *fwcmd;
742 int sz = sizeof(struct mbx_set_common_iface_rx_filter);
743 iface_rx_filter_ctx_t *req;
744 OCE_DMA_MEM sgl;
745 int rc;
746
747 /* allocate mbx payload's dma scatter/gather memory */
748 rc = oce_dma_alloc(sc, sz, &sgl, 0);
749 if (rc)
750 return rc;
751
752 fwcmd = OCE_DMAPTR(&sgl, struct mbx_set_common_iface_rx_filter);
753
754 req = &fwcmd->params.req;
755 req->iface_flags_mask = MBX_RX_IFACE_FLAGS_PROMISCUOUS |
756 MBX_RX_IFACE_FLAGS_VLAN_PROMISCUOUS;
757 if (enable) {
758 req->iface_flags = MBX_RX_IFACE_FLAGS_PROMISCUOUS |
759 MBX_RX_IFACE_FLAGS_VLAN_PROMISCUOUS;
760 }
761 req->if_id = sc->if_id;
762
763 rc = oce_set_common_iface_rx_filter(sc, &sgl);
764 oce_dma_free(sc, &sgl);
765
766 return rc;
767}
768
769
770/**
771 * @brief Function modify and select rx filter options
772 * @param sc software handle to the device
773 * @param sgl scatter/gather request/response
774 * @returns 0 on success, error code on failure
775 */
776int
777oce_set_common_iface_rx_filter(POCE_SOFTC sc, POCE_DMA_MEM sgl)
778{
779 struct oce_mbx mbx;
780 int mbx_sz = sizeof(struct mbx_set_common_iface_rx_filter);
781 struct mbx_set_common_iface_rx_filter *fwcmd;
782 int rc;
783
784 bzero(&mbx, sizeof(struct oce_mbx));
785 fwcmd = OCE_DMAPTR(sgl, struct mbx_set_common_iface_rx_filter);
786
787 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
788 MBX_SUBSYSTEM_COMMON,
789 OPCODE_COMMON_SET_IFACE_RX_FILTER,
790 MBX_TIMEOUT_SEC,
791 mbx_sz,
792 OCE_MBX_VER_V0);
793
794 oce_dma_sync(sgl, BUS_DMASYNC_PREWRITE);
795 mbx.u0.s.embedded = 0;
796 mbx.u0.s.sge_count = 1;
797 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(sgl->paddr);
798 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(sgl->paddr);
799 mbx.payload.u0.u1.sgl[0].length = mbx_sz;
800 mbx.payload_length = mbx_sz;
801 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
802
803 rc = oce_mbox_post(sc, &mbx, NULL);
804 return rc;
805}
806
807/**
808 * @brief Function to query the link status from the hardware
809 * @param sc software handle to the device
810 * @param[out] link pointer to the structure returning link attributes
811 * @returns 0 on success, EIO on failure
812 */
813int
814oce_get_link_status(POCE_SOFTC sc, struct link_status *link)
815{
816 struct oce_mbx mbx;
817 struct mbx_query_common_link_config *fwcmd;
818 int rc = 0;
819
820 bzero(&mbx, sizeof(struct oce_mbx));
821
822 fwcmd = (struct mbx_query_common_link_config *)&mbx.payload;
823 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
824 MBX_SUBSYSTEM_COMMON,
825 OPCODE_COMMON_QUERY_LINK_CONFIG,
826 MBX_TIMEOUT_SEC,
827 sizeof(struct mbx_query_common_link_config),
828 OCE_MBX_VER_V0);
829
830 mbx.u0.s.embedded = 1;
831 mbx.payload_length = sizeof(struct mbx_query_common_link_config);
832 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
833
834 rc = oce_mbox_post(sc, &mbx, NULL);
835
836 if (rc) {
837 device_printf(sc->dev, "Could not get link speed: %d\n", rc);
838 } else {
839 /* interpret response */
840 bcopy(&fwcmd->params.rsp, link, sizeof(struct link_status));
841 link->logical_link_status = LE_32(link->logical_link_status);
842 link->qos_link_speed = LE_16(link->qos_link_speed);
843 }
844
845 return rc;
846}
847
848
849
850int
851oce_mbox_get_nic_stats_v0(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem)
852{
853 struct oce_mbx mbx;
854 struct mbx_get_nic_stats_v0 *fwcmd;
855 int rc = 0;
856
857 bzero(&mbx, sizeof(struct oce_mbx));
858
859 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_nic_stats_v0);
860 bzero(fwcmd, sizeof(struct mbx_get_nic_stats_v0));
861
862 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
863 MBX_SUBSYSTEM_NIC,
864 NIC_GET_STATS,
865 MBX_TIMEOUT_SEC,
866 sizeof(struct mbx_get_nic_stats_v0),
867 OCE_MBX_VER_V0);
868
869 mbx.u0.s.embedded = 0;
870 mbx.u0.s.sge_count = 1;
871
872 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
873
874 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
875 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
876 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_nic_stats_v0);
877
878 mbx.payload_length = sizeof(struct mbx_get_nic_stats_v0);
879
880 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
881
882 rc = oce_mbox_post(sc, &mbx, NULL);
883
884 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
885
886 if (rc) {
887 device_printf(sc->dev,
888 "Could not get nic statistics: %d\n", rc);
889 }
890
891 return rc;
892}
893
894
895
896/**
897 * @brief Function to get NIC statistics
898 * @param sc software handle to the device
899 * @param *stats pointer to where to store statistics
900 * @param reset_stats resets statistics of set
901 * @returns 0 on success, EIO on failure
902 * @note command depricated in Lancer
903 */
904int
905oce_mbox_get_nic_stats(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem)
906{
907 struct oce_mbx mbx;
908 struct mbx_get_nic_stats *fwcmd;
909 int rc = 0;
910
911 bzero(&mbx, sizeof(struct oce_mbx));
912 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_nic_stats);
913 bzero(fwcmd, sizeof(struct mbx_get_nic_stats));
914
915 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
916 MBX_SUBSYSTEM_NIC,
917 NIC_GET_STATS,
918 MBX_TIMEOUT_SEC,
919 sizeof(struct mbx_get_nic_stats),
920 OCE_MBX_VER_V1);
921
922
923 mbx.u0.s.embedded = 0; /* stats too large for embedded mbx rsp */
924 mbx.u0.s.sge_count = 1; /* using scatter gather instead */
925
926 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
927 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
928 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
929 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_nic_stats);
930
931 mbx.payload_length = sizeof(struct mbx_get_nic_stats);
932 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
933
934 rc = oce_mbox_post(sc, &mbx, NULL);
935 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
936 if (rc) {
937 device_printf(sc->dev,
938 "Could not get nic statistics: %d\n", rc);
939 }
940 return rc;
941}
942
943
944/**
945 * @brief Function to get pport (physical port) statistics
946 * @param sc software handle to the device
947 * @param *stats pointer to where to store statistics
948 * @param reset_stats resets statistics of set
949 * @returns 0 on success, EIO on failure
950 */
951int
952oce_mbox_get_pport_stats(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem,
953 uint32_t reset_stats)
954{
955 struct oce_mbx mbx;
956 struct mbx_get_pport_stats *fwcmd;
957 int rc = 0;
958
959 bzero(&mbx, sizeof(struct oce_mbx));
960 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_pport_stats);
961 bzero(fwcmd, sizeof(struct mbx_get_pport_stats));
962
963 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
964 MBX_SUBSYSTEM_NIC,
965 NIC_GET_PPORT_STATS,
966 MBX_TIMEOUT_SEC,
967 sizeof(struct mbx_get_pport_stats),
968 OCE_MBX_VER_V0);
969
970 fwcmd->params.req.reset_stats = reset_stats;
971 fwcmd->params.req.port_number = sc->if_id;
972
973 mbx.u0.s.embedded = 0; /* stats too large for embedded mbx rsp */
974 mbx.u0.s.sge_count = 1; /* using scatter gather instead */
975
976 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
977 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
978 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
979 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_pport_stats);
980
981 mbx.payload_length = sizeof(struct mbx_get_pport_stats);
982 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
983
984 rc = oce_mbox_post(sc, &mbx, NULL);
985 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
986
987 if (rc != 0) {
988 device_printf(sc->dev,
989 "Could not get physical port statistics: %d\n", rc);
990 }
991
992 return rc;
993}
994
995
996/**
997 * @brief Function to get vport (virtual port) statistics
998 * @param sc software handle to the device
999 * @param *stats pointer to where to store statistics
1000 * @param reset_stats resets statistics of set
1001 * @returns 0 on success, EIO on failure
1002 */
1003int
1004oce_mbox_get_vport_stats(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem,
1005 uint32_t req_size, uint32_t reset_stats)
1006{
1007 struct oce_mbx mbx;
1008 struct mbx_get_vport_stats *fwcmd;
1009 int rc = 0;
1010
1011 bzero(&mbx, sizeof(struct oce_mbx));
1012
1013 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_vport_stats);
1014 bzero(fwcmd, sizeof(struct mbx_get_vport_stats));
1015
1016 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1017 MBX_SUBSYSTEM_NIC,
1018 NIC_GET_VPORT_STATS,
1019 MBX_TIMEOUT_SEC,
1020 sizeof(struct mbx_get_vport_stats),
1021 OCE_MBX_VER_V0);
1022
1023 fwcmd->params.req.reset_stats = reset_stats;
1024 fwcmd->params.req.vport_number = sc->if_id;
1025
1026 mbx.u0.s.embedded = 0; /* stats too large for embedded mbx rsp */
1027 mbx.u0.s.sge_count = 1; /* using scatter gather instead */
1028
1029 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
1030 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
1031 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
1032 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_vport_stats);
1033
1034 mbx.payload_length = sizeof(struct mbx_get_vport_stats);
1035 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1036
1037 rc = oce_mbox_post(sc, &mbx, NULL);
1038 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
1039
1040 if (rc != 0) {
1041 device_printf(sc->dev,
1042 "Could not get physical port statistics: %d\n", rc);
1043 }
1044
1045 return rc;
1046}
1047
1048
1049/**
1050 * @brief Function to update the muticast filter with
1051 * values in dma_mem
1052 * @param sc software handle to the device
1053 * @param dma_mem pointer to dma memory region
1054 * @returns 0 on success, EIO on failure
1055 */
1056int
1057oce_update_multicast(POCE_SOFTC sc, POCE_DMA_MEM pdma_mem)
1058{
1059 struct oce_mbx mbx;
1060 struct oce_mq_sge *sgl;
1061 struct mbx_set_common_iface_multicast *req = NULL;
1062 int rc = 0;
1063
1064 req = OCE_DMAPTR(pdma_mem, struct mbx_set_common_iface_multicast);
1065 mbx_common_req_hdr_init(&req->hdr, 0, 0,
1066 MBX_SUBSYSTEM_COMMON,
1067 OPCODE_COMMON_SET_IFACE_MULTICAST,
1068 MBX_TIMEOUT_SEC,
1069 sizeof(struct mbx_set_common_iface_multicast),
1070 OCE_MBX_VER_V0);
1071
1072 bzero(&mbx, sizeof(struct oce_mbx));
1073
1074 mbx.u0.s.embedded = 0; /*Non embeded*/
1075 mbx.payload_length = sizeof(struct mbx_set_common_iface_multicast);
1076 mbx.u0.s.sge_count = 1;
1077 sgl = &mbx.payload.u0.u1.sgl[0];
1078 sgl->pa_hi = htole32(upper_32_bits(pdma_mem->paddr));
1079 sgl->pa_lo = htole32((pdma_mem->paddr) & 0xFFFFFFFF);
1080 sgl->length = htole32(mbx.payload_length);
1081
1082 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1083
1084 rc = oce_mbox_post(sc, &mbx, NULL);
1085
1086 return rc;
1087}
1088
1089
1090/**
1091 * @brief Function to send passthrough Ioctls
1092 * @param sc software handle to the device
1093 * @param dma_mem pointer to dma memory region
1094 * @param req_size size of dma_mem
1095 * @returns 0 on success, EIO on failure
1096 */
1097int
1098oce_pass_through_mbox(POCE_SOFTC sc, POCE_DMA_MEM dma_mem, uint32_t req_size)
1099{
1100 struct oce_mbx mbx;
1101 struct oce_mq_sge *sgl;
1102 int rc = 0;
1103
1104 bzero(&mbx, sizeof(struct oce_mbx));
1105
1106 mbx.u0.s.embedded = 0; /*Non embeded*/
1107 mbx.payload_length = req_size;
1108 mbx.u0.s.sge_count = 1;
1109 sgl = &mbx.payload.u0.u1.sgl[0];
1110 sgl->pa_hi = htole32(upper_32_bits(dma_mem->paddr));
1111 sgl->pa_lo = htole32((dma_mem->paddr) & 0xFFFFFFFF);
1112 sgl->length = htole32(req_size);
1113
1114 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1115
1116 rc = oce_mbox_post(sc, &mbx, NULL);
1117 return rc;
1118}
1119
1120
1121int
1122oce_mbox_macaddr_add(POCE_SOFTC sc, uint8_t *mac_addr,
1123 uint32_t if_id, uint32_t *pmac_id)
1124{
1125 struct oce_mbx mbx;
1126 struct mbx_add_common_iface_mac *fwcmd;
1127 int rc = 0;
1128
1129 bzero(&mbx, sizeof(struct oce_mbx));
1130
1131 fwcmd = (struct mbx_add_common_iface_mac *)&mbx.payload;
1132 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1133 MBX_SUBSYSTEM_COMMON,
1134 OPCODE_COMMON_ADD_IFACE_MAC,
1135 MBX_TIMEOUT_SEC,
1136 sizeof(struct mbx_add_common_iface_mac),
1137 OCE_MBX_VER_V0);
1138
1139 fwcmd->params.req.if_id = (uint16_t) if_id;
1140 bcopy(mac_addr, fwcmd->params.req.mac_address, 6);
1141
1142 mbx.u0.s.embedded = 1;
1143 mbx.payload_length = sizeof(struct mbx_add_common_iface_mac);
1144 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1145 rc = oce_mbox_post(sc, &mbx, NULL);
1146 if (rc)
1147 return rc;
1148
1149 *pmac_id = fwcmd->params.rsp.pmac_id;
1150
1151 return rc;
1152}
1153
1154
1155int
1156oce_mbox_macaddr_del(POCE_SOFTC sc, uint32_t if_id, uint32_t pmac_id)
1157{
1158 struct oce_mbx mbx;
1159 struct mbx_del_common_iface_mac *fwcmd;
1160 int rc = 0;
1161
1162 bzero(&mbx, sizeof(struct oce_mbx));
1163
1164 fwcmd = (struct mbx_del_common_iface_mac *)&mbx.payload;
1165 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1166 MBX_SUBSYSTEM_COMMON,
1167 OPCODE_COMMON_DEL_IFACE_MAC,
1168 MBX_TIMEOUT_SEC,
1169 sizeof(struct mbx_del_common_iface_mac),
1170 OCE_MBX_VER_V0);
1171
1172 fwcmd->params.req.if_id = (uint16_t)if_id;
1173 fwcmd->params.req.pmac_id = pmac_id;
1174
1175 mbx.u0.s.embedded = 1;
1176 mbx.payload_length = sizeof(struct mbx_del_common_iface_mac);
1177 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1178
1179 rc = oce_mbox_post(sc, &mbx, NULL);
1180 return rc;
1181}
1182
1183
1184
1185int
1186oce_mbox_check_native_mode(POCE_SOFTC sc)
1187{
1188 struct oce_mbx mbx;
1189 struct mbx_common_set_function_cap *fwcmd;
1190 int rc = 0;
1191
1192 bzero(&mbx, sizeof(struct oce_mbx));
1193
1194 fwcmd = (struct mbx_common_set_function_cap *)&mbx.payload;
1195 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1196 MBX_SUBSYSTEM_COMMON,
1197 OPCODE_COMMON_SET_FUNCTIONAL_CAPS,
1198 MBX_TIMEOUT_SEC,
1199 sizeof(struct mbx_common_set_function_cap),
1200 OCE_MBX_VER_V0);
1201
1202 fwcmd->params.req.valid_capability_flags = CAP_SW_TIMESTAMPS |
1203 CAP_BE3_NATIVE_ERX_API;
1204
1205 fwcmd->params.req.capability_flags = CAP_BE3_NATIVE_ERX_API;
1206
1207 mbx.u0.s.embedded = 1;
1208 mbx.payload_length = sizeof(struct mbx_common_set_function_cap);
1209 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1210
1211 rc = oce_mbox_post(sc, &mbx, NULL);
1212 //if (rc != 0) This can fail in legacy mode. So skip
1213 // FN_LEAVE(rc);
1214
1215 sc->be3_native = fwcmd->params.rsp.capability_flags
1216 & CAP_BE3_NATIVE_ERX_API;
1217
1218 return 0;
1219}
1220
1221
1222
1223int
1224oce_mbox_cmd_set_loopback(POCE_SOFTC sc, uint8_t port_num,
1225 uint8_t loopback_type, uint8_t enable)
1226{
1227 struct oce_mbx mbx;
1228 struct mbx_lowlevel_set_loopback_mode *fwcmd;
1229 int rc = 0;
1230
1231
1232 bzero(&mbx, sizeof(struct oce_mbx));
1233
1234 fwcmd = (struct mbx_lowlevel_set_loopback_mode *)&mbx.payload;
1235 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1236 MBX_SUBSYSTEM_LOWLEVEL,
1237 OPCODE_LOWLEVEL_SET_LOOPBACK_MODE,
1238 MBX_TIMEOUT_SEC,
1239 sizeof(struct mbx_lowlevel_set_loopback_mode),
1240 OCE_MBX_VER_V0);
1241
1242 fwcmd->params.req.src_port = port_num;
1243 fwcmd->params.req.dest_port = port_num;
1244 fwcmd->params.req.loopback_type = loopback_type;
1245 fwcmd->params.req.loopback_state = enable;
1246
1247 mbx.u0.s.embedded = 1;
1248 mbx.payload_length = sizeof(struct mbx_lowlevel_set_loopback_mode);
1249 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1250
1251 rc = oce_mbox_post(sc, &mbx, NULL);
1252
1253 return rc;
1254
1255}
1256
1257int
1258oce_mbox_cmd_test_loopback(POCE_SOFTC sc, uint32_t port_num,
1259 uint32_t loopback_type, uint32_t pkt_size, uint32_t num_pkts,
1260 uint64_t pattern)
1261{
1262
1263 struct oce_mbx mbx;
1264 struct mbx_lowlevel_test_loopback_mode *fwcmd;
1265 int rc = 0;
1266
1267
1268 bzero(&mbx, sizeof(struct oce_mbx));
1269
1270 fwcmd = (struct mbx_lowlevel_test_loopback_mode *)&mbx.payload;
1271 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1272 MBX_SUBSYSTEM_LOWLEVEL,
1273 OPCODE_LOWLEVEL_TEST_LOOPBACK,
1274 MBX_TIMEOUT_SEC,
1275 sizeof(struct mbx_lowlevel_test_loopback_mode),
1276 OCE_MBX_VER_V0);
1277
1278 fwcmd->params.req.pattern = pattern;
1279 fwcmd->params.req.src_port = port_num;
1280 fwcmd->params.req.dest_port = port_num;
1281 fwcmd->params.req.pkt_size = pkt_size;
1282 fwcmd->params.req.num_pkts = num_pkts;
1283 fwcmd->params.req.loopback_type = loopback_type;
1284
1285 mbx.u0.s.embedded = 1;
1286 mbx.payload_length = sizeof(struct mbx_lowlevel_test_loopback_mode);
1287 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1288
1289 rc = oce_mbox_post(sc, &mbx, NULL);
1290 if (rc)
1291 return rc;
1292
1293 return(fwcmd->params.rsp.status);
1294}
1295
1296int
1297oce_mbox_write_flashrom(POCE_SOFTC sc, uint32_t optype,uint32_t opcode,
1298 POCE_DMA_MEM pdma_mem, uint32_t num_bytes)
1299{
1300
1301 struct oce_mbx mbx;
1302 struct oce_mq_sge *sgl = NULL;
1303 struct mbx_common_read_write_flashrom *fwcmd = NULL;
1304 int rc = 0, payload_len = 0;
1305
1306 bzero(&mbx, sizeof(struct oce_mbx));
1307 fwcmd = OCE_DMAPTR(pdma_mem, struct mbx_common_read_write_flashrom);
1308 payload_len = sizeof(struct mbx_common_read_write_flashrom) + 32*1024;
1309
1310 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1311 MBX_SUBSYSTEM_COMMON,
1312 OPCODE_COMMON_WRITE_FLASHROM,
1313 LONG_TIMEOUT,
1314 payload_len,
1315 OCE_MBX_VER_V0);
1316
1317 fwcmd->flash_op_type = optype;
1318 fwcmd->flash_op_code = opcode;
1319 fwcmd->data_buffer_size = num_bytes;
1320
1321 mbx.u0.s.embedded = 0; /*Non embeded*/
1322 mbx.payload_length = payload_len;
1323 mbx.u0.s.sge_count = 1;
1324
1325 sgl = &mbx.payload.u0.u1.sgl[0];
1326 sgl->pa_hi = upper_32_bits(pdma_mem->paddr);
1327 sgl->pa_lo = pdma_mem->paddr & 0xFFFFFFFF;
1328 sgl->length = payload_len;
1329
1330 /* post the command */
1331 if (rc) {
1332 device_printf(sc->dev, "Write FlashROM mbox post failed\n");
1333 } else {
1334 rc = fwcmd->hdr.u0.rsp.status;
1335 }
1336
1337 return rc;
1338
1339}
1340
1341int
1342oce_mbox_get_flashrom_crc(POCE_SOFTC sc, uint8_t *flash_crc,
1343 uint32_t offset, uint32_t optype)
1344{
1345
1346 int rc = 0, payload_len = 0;
1347 struct oce_mbx mbx;
1348 struct mbx_common_read_write_flashrom *fwcmd;
1349
1350 bzero(&mbx, sizeof(struct oce_mbx));
1351
1352 fwcmd = (struct mbx_common_read_write_flashrom *)&mbx.payload;
1353
1354 /* Firmware requires extra 4 bytes with this ioctl. Since there
1355 is enough room in the mbx payload it should be good enough
1356 Reference: Bug 14853
1357 */
1358 payload_len = sizeof(struct mbx_common_read_write_flashrom) + 4;
1359
1360 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1361 MBX_SUBSYSTEM_COMMON,
1362 OPCODE_COMMON_READ_FLASHROM,
1363 MBX_TIMEOUT_SEC,
1364 payload_len,
1365 OCE_MBX_VER_V0);
1366
1367 fwcmd->flash_op_type = optype;
1368 fwcmd->flash_op_code = FLASHROM_OPER_REPORT;
1369 fwcmd->data_offset = offset;
1370 fwcmd->data_buffer_size = 0x4;
1371
1372 mbx.u0.s.embedded = 1;
1373 mbx.payload_length = payload_len;
1374
1375 /* post the command */
1376 rc = oce_mbox_post(sc, &mbx, NULL);
1377 if (rc) {
1378 device_printf(sc->dev, "Read FlashROM CRC mbox post failed\n");
1379 } else {
1380 bcopy(fwcmd->data_buffer, flash_crc, 4);
1381 rc = fwcmd->hdr.u0.rsp.status;
1382 }
1383 return rc;
1384}
1385
1386int
1387oce_mbox_get_phy_info(POCE_SOFTC sc, struct oce_phy_info *phy_info)
1388{
1389
1390 struct oce_mbx mbx;
1391 struct mbx_common_phy_info *fwcmd;
1392 int rc = 0;
1393
1394 bzero(&mbx, sizeof(struct oce_mbx));
1395
1396 fwcmd = (struct mbx_common_phy_info *)&mbx.payload;
1397 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1398 MBX_SUBSYSTEM_COMMON,
1399 OPCODE_COMMON_GET_PHY_CONFIG,
1400 MBX_TIMEOUT_SEC,
1401 sizeof(struct mbx_common_phy_info),
1402 OCE_MBX_VER_V0);
1403
1404 mbx.u0.s.embedded = 1;
1405 mbx.payload_length = sizeof(struct mbx_common_phy_info);
1406
1407 /* now post the command */
1408 rc = oce_mbox_post(sc, &mbx, NULL);
1409 if (rc) {
1410 device_printf(sc->dev, "Read PHY info mbox post failed\n");
1411 } else {
1412 rc = fwcmd->hdr.u0.rsp.status;
1413 phy_info->phy_type = fwcmd->params.rsp.phy_info.phy_type;
1414 phy_info->interface_type =
1415 fwcmd->params.rsp.phy_info.interface_type;
1416 phy_info->auto_speeds_supported =
1417 fwcmd->params.rsp.phy_info.auto_speeds_supported;
1418 phy_info->fixed_speeds_supported =
1419 fwcmd->params.rsp.phy_info.fixed_speeds_supported;
1420 phy_info->misc_params =fwcmd->params.rsp.phy_info.misc_params;
1421
1422 }
1423 return rc;
1424
1425}
1426
1427
1428int
1429oce_mbox_lancer_write_flashrom(POCE_SOFTC sc, uint32_t data_size,
1430 uint32_t data_offset, POCE_DMA_MEM pdma_mem,
1431 uint32_t *written_data, uint32_t *additional_status)
1432{
1433
1434 struct oce_mbx mbx;
1435 struct mbx_lancer_common_write_object *fwcmd = NULL;
1436 int rc = 0, payload_len = 0;
1437
1438 bzero(&mbx, sizeof(struct oce_mbx));
1439 payload_len = sizeof(struct mbx_lancer_common_write_object);
1440
1441 mbx.u0.s.embedded = 1;/* Embedded */
1442 mbx.payload_length = payload_len;
1443 fwcmd = (struct mbx_lancer_common_write_object *)&mbx.payload;
1444
1445 /* initialize the ioctl header */
1446 mbx_common_req_hdr_init(&fwcmd->params.req.hdr, 0, 0,
1447 MBX_SUBSYSTEM_COMMON,
1448 OPCODE_COMMON_WRITE_OBJECT,
1449 LONG_TIMEOUT,
1450 payload_len,
1451 OCE_MBX_VER_V0);
1452
1453 fwcmd->params.req.write_length = data_size;
1454 if (data_size == 0)
1455 fwcmd->params.req.eof = 1;
1456 else
1457 fwcmd->params.req.eof = 0;
1458
1459 strcpy(fwcmd->params.req.object_name, "/prg");
1460 fwcmd->params.req.descriptor_count = 1;
1461 fwcmd->params.req.write_offset = data_offset;
1462 fwcmd->params.req.buffer_length = data_size;
1463 fwcmd->params.req.address_lower = pdma_mem->paddr & 0xFFFFFFFF;
1464 fwcmd->params.req.address_upper = upper_32_bits(pdma_mem->paddr);
1465
1466 /* post the command */
1467 rc = oce_mbox_post(sc, &mbx, NULL);
1468 if (rc) {
1469 device_printf(sc->dev,
1470 "Write Lancer FlashROM mbox post failed\n");
1471 } else {
1472 *written_data = fwcmd->params.rsp.actual_write_length;
1473 *additional_status = fwcmd->params.rsp.additional_status;
1474 rc = fwcmd->params.rsp.status;
1475 }
1476 return rc;
1477
1478}
1479
1480
1481
1482int
1483oce_mbox_create_rq(struct oce_rq *rq)
1484{
1485
1486 struct oce_mbx mbx;
1487 struct mbx_create_nic_rq *fwcmd;
1488 POCE_SOFTC sc = rq->parent;
1489 int rc, num_pages = 0;
1490
1491 if (rq->qstate == QCREATED)
1492 return 0;
1493
1494 bzero(&mbx, sizeof(struct oce_mbx));
1495
1496 fwcmd = (struct mbx_create_nic_rq *)&mbx.payload;
1497 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1498 MBX_SUBSYSTEM_NIC,
1499 NIC_CREATE_RQ, MBX_TIMEOUT_SEC,
1500 sizeof(struct mbx_create_nic_rq),
1501 OCE_MBX_VER_V0);
1502
1503 /* oce_page_list will also prepare pages */
1504 num_pages = oce_page_list(rq->ring, &fwcmd->params.req.pages[0]);
1505
1506 if (IS_XE201(sc)) {
1507 fwcmd->params.req.frag_size = rq->cfg.frag_size/2048;
1508 fwcmd->params.req.page_size = 1;
1509 fwcmd->hdr.u0.req.version = OCE_MBX_VER_V1;
1510 } else
1511 fwcmd->params.req.frag_size = OCE_LOG2(rq->cfg.frag_size);
1512 fwcmd->params.req.num_pages = num_pages;
1513 fwcmd->params.req.cq_id = rq->cq->cq_id;
1514 fwcmd->params.req.if_id = sc->if_id;
1515 fwcmd->params.req.max_frame_size = rq->cfg.mtu;
1516 fwcmd->params.req.is_rss_queue = rq->cfg.is_rss_queue;
1517
1518 mbx.u0.s.embedded = 1;
1519 mbx.payload_length = sizeof(struct mbx_create_nic_rq);
1520
1521 rc = oce_mbox_post(sc, &mbx, NULL);
1522 if (rc)
1523 goto error;
1524
1525 rq->rq_id = fwcmd->params.rsp.rq_id;
1526 rq->rss_cpuid = fwcmd->params.rsp.rss_cpuid;
1527
1528 return 0;
1529error:
1530 device_printf(sc->dev, "Mbox Create RQ failed\n");
1531 return rc;
1532
1533}
1534
1535
1536
1537int
1538oce_mbox_create_wq(struct oce_wq *wq)
1539{
1540 struct oce_mbx mbx;
1541 struct mbx_create_nic_wq *fwcmd;
1542 POCE_SOFTC sc = wq->parent;
1543 int rc = 0, version, num_pages;
1544
1545 bzero(&mbx, sizeof(struct oce_mbx));
1546
1547 fwcmd = (struct mbx_create_nic_wq *)&mbx.payload;
1548 if (IS_XE201(sc)) {
1549 version = OCE_MBX_VER_V1;
1550 fwcmd->params.req.if_id = sc->if_id;
1551 } else
1552 version = OCE_MBX_VER_V0;
1553
1554 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1555 MBX_SUBSYSTEM_NIC,
1556 NIC_CREATE_WQ, MBX_TIMEOUT_SEC,
1557 sizeof(struct mbx_create_nic_wq),
1558 version);
1559
1560 num_pages = oce_page_list(wq->ring, &fwcmd->params.req.pages[0]);
1561
1562 fwcmd->params.req.nic_wq_type = wq->cfg.wq_type;
1563 fwcmd->params.req.num_pages = num_pages;
1564 fwcmd->params.req.wq_size = OCE_LOG2(wq->cfg.q_len) + 1;
1565 fwcmd->params.req.cq_id = wq->cq->cq_id;
1566 fwcmd->params.req.ulp_num = 1;
1567
1568 mbx.u0.s.embedded = 1;
1569 mbx.payload_length = sizeof(struct mbx_create_nic_wq);
1570
1571 rc = oce_mbox_post(sc, &mbx, NULL);
1572 if (rc)
1573 goto error;
1574
1575 wq->wq_id = LE_16(fwcmd->params.rsp.wq_id);
1576
1577 return 0;
1578error:
1579 device_printf(sc->dev, "Mbox Create WQ failed\n");
1580 return rc;
1581
1582}
1583
1584
1585
1586int
1587oce_mbox_create_eq(struct oce_eq *eq)
1588{
1589 struct oce_mbx mbx;
1590 struct mbx_create_common_eq *fwcmd;
1591 POCE_SOFTC sc = eq->parent;
1592 int rc = 0;
1593 uint32_t num_pages;
1594
1595 bzero(&mbx, sizeof(struct oce_mbx));
1596
1597 fwcmd = (struct mbx_create_common_eq *)&mbx.payload;
1598
1599 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1600 MBX_SUBSYSTEM_COMMON,
1601 OPCODE_COMMON_CREATE_EQ, MBX_TIMEOUT_SEC,
1602 sizeof(struct mbx_create_common_eq),
1603 OCE_MBX_VER_V0);
1604
1605 num_pages = oce_page_list(eq->ring, &fwcmd->params.req.pages[0]);
1606 fwcmd->params.req.ctx.num_pages = num_pages;
1607 fwcmd->params.req.ctx.valid = 1;
1608 fwcmd->params.req.ctx.size = (eq->eq_cfg.item_size == 4) ? 0 : 1;
1609 fwcmd->params.req.ctx.count = OCE_LOG2(eq->eq_cfg.q_len / 256);
1610 fwcmd->params.req.ctx.armed = 0;
1611 fwcmd->params.req.ctx.delay_mult = eq->eq_cfg.cur_eqd;
1612
1613
1614 mbx.u0.s.embedded = 1;
1615 mbx.payload_length = sizeof(struct mbx_create_common_eq);
1616
1617 rc = oce_mbox_post(sc, &mbx, NULL);
1618 if (rc)
1619 goto error;
1620
1621 eq->eq_id = LE_16(fwcmd->params.rsp.eq_id);
1622
1623 return 0;
1624error:
1625 device_printf(sc->dev, "Mbox Create EQ failed\n");
1626 return rc;
1627}
1628
1629
1630
1631int
1632oce_mbox_cq_create(struct oce_cq *cq, uint32_t ncoalesce, uint32_t is_eventable)
1633{
1634 struct oce_mbx mbx;
1635 struct mbx_create_common_cq *fwcmd;
1636 POCE_SOFTC sc = cq->parent;
1637 uint8_t version;
1638 oce_cq_ctx_t *ctx;
1639 uint32_t num_pages, page_size;
1640 int rc = 0;
1641
1642
1643 bzero(&mbx, sizeof(struct oce_mbx));
1644
1645 fwcmd = (struct mbx_create_common_cq *)&mbx.payload;
1646
1647 if (IS_XE201(sc))
1648 version = OCE_MBX_VER_V2;
1649 else
1650 version = OCE_MBX_VER_V0;
1651
1652 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1653 MBX_SUBSYSTEM_COMMON,
1654 OPCODE_COMMON_CREATE_CQ,
1655 MBX_TIMEOUT_SEC,
1656 sizeof(struct mbx_create_common_cq),
1657 version);
1658
1659 ctx = &fwcmd->params.req.cq_ctx;
1660
1661 num_pages = oce_page_list(cq->ring, &fwcmd->params.req.pages[0]);
1662 page_size = 1; /* 1 for 4K */
1663
1664 if (version == OCE_MBX_VER_V2) {
1665 ctx->v2.num_pages = LE_16(num_pages);
1666 ctx->v2.page_size = page_size;
1667 ctx->v2.eventable = is_eventable;
1668 ctx->v2.valid = 1;
1669 ctx->v2.count = OCE_LOG2(cq->cq_cfg.q_len / 256);
1670 ctx->v2.nodelay = cq->cq_cfg.nodelay;
1671 ctx->v2.coalesce_wm = ncoalesce;
1672 ctx->v2.armed = 0;
1673 ctx->v2.eq_id = cq->eq->eq_id;
1674 if (ctx->v2.count == 3) {
1675 if (cq->cq_cfg.q_len > (4*1024)-1)
1676 ctx->v2.cqe_count = (4*1024)-1;
1677 else
1678 ctx->v2.cqe_count = cq->cq_cfg.q_len;
1679 }
1680 } else {
1681 ctx->v0.num_pages = LE_16(num_pages);
1682 ctx->v0.eventable = is_eventable;
1683 ctx->v0.valid = 1;
1684 ctx->v0.count = OCE_LOG2(cq->cq_cfg.q_len / 256);
1685 ctx->v0.nodelay = cq->cq_cfg.nodelay;
1686 ctx->v0.coalesce_wm = ncoalesce;
1687 ctx->v0.armed = 0;
1688 ctx->v0.eq_id = cq->eq->eq_id;
1689 }
1690
1691 mbx.u0.s.embedded = 1;
1692 mbx.payload_length = sizeof(struct mbx_create_common_cq);
1693
1694 rc = oce_mbox_post(sc, &mbx, NULL);
1695 if (rc)
1696 goto error;
1697
1698 cq->cq_id = LE_16(fwcmd->params.rsp.cq_id);
1699
1700 return 0;
1701error:
1702 device_printf(sc->dev, "Mbox Create CQ failed\n");
1703 return rc;
1704
1705}
2 * Copyright (C) 2012 Emulex
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the Emulex Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Contact Information:
32 * freebsd-drivers@emulex.com
33 *
34 * Emulex
35 * 3333 Susan Street
36 * Costa Mesa, CA 92626
37 */
38
39
40
41/* $FreeBSD: head/sys/dev/oce/oce_mbox.c 231437 2012-02-10 21:03:04Z luigi $ */
42
43
44#include "oce_if.h"
45
46
47/**
48 * @brief Reset (firmware) common function
49 * @param sc software handle to the device
50 * @returns 0 on success, ETIMEDOUT on failure
51 */
52int
53oce_reset_fun(POCE_SOFTC sc)
54{
55 struct oce_mbx *mbx;
56 struct oce_bmbx *mb;
57 struct ioctl_common_function_reset *fwcmd;
58 int rc = 0;
59
60 if (sc->flags & OCE_FLAGS_FUNCRESET_RQD) {
61 mb = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
62 mbx = &mb->mbx;
63 bzero(mbx, sizeof(struct oce_mbx));
64
65 fwcmd = (struct ioctl_common_function_reset *)&mbx->payload;
66 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
67 MBX_SUBSYSTEM_COMMON,
68 OPCODE_COMMON_FUNCTION_RESET,
69 10, /* MBX_TIMEOUT_SEC */
70 sizeof(struct
71 ioctl_common_function_reset),
72 OCE_MBX_VER_V0);
73
74 mbx->u0.s.embedded = 1;
75 mbx->payload_length =
76 sizeof(struct ioctl_common_function_reset);
77
78 rc = oce_mbox_dispatch(sc, 2);
79 }
80
81 return rc;
82}
83
84
85/**
86 * @brief This funtions tells firmware we are
87 * done with commands.
88 * @param sc software handle to the device
89 * @returns 0 on success, ETIMEDOUT on failure
90 */
91int
92oce_fw_clean(POCE_SOFTC sc)
93{
94 struct oce_bmbx *mbx;
95 uint8_t *ptr;
96 int ret = 0;
97
98 mbx = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
99 ptr = (uint8_t *) &mbx->mbx;
100
101 /* Endian Signature */
102 *ptr++ = 0xff;
103 *ptr++ = 0xaa;
104 *ptr++ = 0xbb;
105 *ptr++ = 0xff;
106 *ptr++ = 0xff;
107 *ptr++ = 0xcc;
108 *ptr++ = 0xdd;
109 *ptr = 0xff;
110
111 ret = oce_mbox_dispatch(sc, 2);
112
113 return ret;
114}
115
116
117/**
118 * @brief Mailbox wait
119 * @param sc software handle to the device
120 * @param tmo_sec timeout in seconds
121 */
122static int
123oce_mbox_wait(POCE_SOFTC sc, uint32_t tmo_sec)
124{
125 tmo_sec *= 10000;
126 pd_mpu_mbox_db_t mbox_db;
127
128 for (;;) {
129 if (tmo_sec != 0) {
130 if (--tmo_sec == 0)
131 break;
132 }
133
134 mbox_db.dw0 = OCE_READ_REG32(sc, db, PD_MPU_MBOX_DB);
135
136 if (mbox_db.bits.ready)
137 return 0;
138
139 DELAY(100);
140 }
141
142 device_printf(sc->dev, "Mailbox timed out\n");
143
144 return ETIMEDOUT;
145}
146
147
148
149/**
150 * @brief Mailbox dispatch
151 * @param sc software handle to the device
152 * @param tmo_sec timeout in seconds
153 */
154int
155oce_mbox_dispatch(POCE_SOFTC sc, uint32_t tmo_sec)
156{
157 pd_mpu_mbox_db_t mbox_db;
158 uint32_t pa;
159 int rc;
160
161 oce_dma_sync(&sc->bsmbx, BUS_DMASYNC_PREWRITE);
162 pa = (uint32_t) ((uint64_t) sc->bsmbx.paddr >> 34);
163 bzero(&mbox_db, sizeof(pd_mpu_mbox_db_t));
164 mbox_db.bits.ready = 0;
165 mbox_db.bits.hi = 1;
166 mbox_db.bits.address = pa;
167
168 rc = oce_mbox_wait(sc, tmo_sec);
169 if (rc == 0) {
170 OCE_WRITE_REG32(sc, db, PD_MPU_MBOX_DB, mbox_db.dw0);
171
172 pa = (uint32_t) ((uint64_t) sc->bsmbx.paddr >> 4) & 0x3fffffff;
173 mbox_db.bits.ready = 0;
174 mbox_db.bits.hi = 0;
175 mbox_db.bits.address = pa;
176
177 rc = oce_mbox_wait(sc, tmo_sec);
178
179 if (rc == 0) {
180 OCE_WRITE_REG32(sc, db, PD_MPU_MBOX_DB, mbox_db.dw0);
181
182 rc = oce_mbox_wait(sc, tmo_sec);
183
184 oce_dma_sync(&sc->bsmbx, BUS_DMASYNC_POSTWRITE);
185 }
186 }
187
188 return rc;
189}
190
191
192
193/**
194 * @brief Mailbox common request header initialization
195 * @param hdr mailbox header
196 * @param dom domain
197 * @param port port
198 * @param subsys subsystem
199 * @param opcode opcode
200 * @param timeout timeout
201 * @param pyld_len payload length
202 */
203void
204mbx_common_req_hdr_init(struct mbx_hdr *hdr,
205 uint8_t dom, uint8_t port,
206 uint8_t subsys, uint8_t opcode,
207 uint32_t timeout, uint32_t pyld_len,
208 uint8_t version)
209{
210 hdr->u0.req.opcode = opcode;
211 hdr->u0.req.subsystem = subsys;
212 hdr->u0.req.port_number = port;
213 hdr->u0.req.domain = dom;
214
215 hdr->u0.req.timeout = timeout;
216 hdr->u0.req.request_length = pyld_len - sizeof(struct mbx_hdr);
217 hdr->u0.req.version = version;
218}
219
220
221
222/**
223 * @brief Function to initialize the hw with host endian information
224 * @param sc software handle to the device
225 * @returns 0 on success, ETIMEDOUT on failure
226 */
227int
228oce_mbox_init(POCE_SOFTC sc)
229{
230 struct oce_bmbx *mbx;
231 uint8_t *ptr;
232 int ret = 0;
233
234 if (sc->flags & OCE_FLAGS_MBOX_ENDIAN_RQD) {
235 mbx = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
236 ptr = (uint8_t *) &mbx->mbx;
237
238 /* Endian Signature */
239 *ptr++ = 0xff;
240 *ptr++ = 0x12;
241 *ptr++ = 0x34;
242 *ptr++ = 0xff;
243 *ptr++ = 0xff;
244 *ptr++ = 0x56;
245 *ptr++ = 0x78;
246 *ptr = 0xff;
247
248 ret = oce_mbox_dispatch(sc, 0);
249 }
250
251 return ret;
252}
253
254
255/**
256 * @brief Function to get the firmware version
257 * @param sc software handle to the device
258 * @returns 0 on success, EIO on failure
259 */
260int
261oce_get_fw_version(POCE_SOFTC sc)
262{
263 struct oce_mbx mbx;
264 struct mbx_get_common_fw_version *fwcmd;
265 int ret = 0;
266
267 bzero(&mbx, sizeof(struct oce_mbx));
268
269 fwcmd = (struct mbx_get_common_fw_version *)&mbx.payload;
270 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
271 MBX_SUBSYSTEM_COMMON,
272 OPCODE_COMMON_GET_FW_VERSION,
273 MBX_TIMEOUT_SEC,
274 sizeof(struct mbx_get_common_fw_version),
275 OCE_MBX_VER_V0);
276
277 mbx.u0.s.embedded = 1;
278 mbx.payload_length = sizeof(struct mbx_get_common_fw_version);
279 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
280
281 ret = oce_mbox_post(sc, &mbx, NULL);
282 if (ret)
283 return ret;
284
285 bcopy(fwcmd->params.rsp.fw_ver_str, sc->fw_version, 32);
286
287 return 0;
288}
289
290
291/**
292 * @brief Function to post a MBX to the mbox
293 * @param sc software handle to the device
294 * @param mbx pointer to the MBX to send
295 * @param mbxctx pointer to the mbx context structure
296 * @returns 0 on success, error on failure
297 */
298int
299oce_mbox_post(POCE_SOFTC sc, struct oce_mbx *mbx, struct oce_mbx_ctx *mbxctx)
300{
301 struct oce_mbx *mb_mbx = NULL;
302 struct oce_mq_cqe *mb_cqe = NULL;
303 struct oce_bmbx *mb = NULL;
304 int rc = 0;
305 uint32_t tmo = 0;
306 uint32_t cstatus = 0;
307 uint32_t xstatus = 0;
308
309 LOCK(&sc->bmbx_lock);
310
311 mb = OCE_DMAPTR(&sc->bsmbx, struct oce_bmbx);
312 mb_mbx = &mb->mbx;
313
314 /* get the tmo */
315 tmo = mbx->tag[0];
316 mbx->tag[0] = 0;
317
318 /* copy mbx into mbox */
319 bcopy(mbx, mb_mbx, sizeof(struct oce_mbx));
320
321 /* now dispatch */
322 rc = oce_mbox_dispatch(sc, tmo);
323 if (rc == 0) {
324 /*
325 * the command completed successfully. Now get the
326 * completion queue entry
327 */
328 mb_cqe = &mb->cqe;
329 DW_SWAP(u32ptr(&mb_cqe->u0.dw[0]), sizeof(struct oce_mq_cqe));
330
331 /* copy mbox mbx back */
332 bcopy(mb_mbx, mbx, sizeof(struct oce_mbx));
333
334 /* pick up the mailbox status */
335 cstatus = mb_cqe->u0.s.completion_status;
336 xstatus = mb_cqe->u0.s.extended_status;
337
338 /*
339 * store the mbx context in the cqe tag section so that
340 * the upper layer handling the cqe can associate the mbx
341 * with the response
342 */
343 if (cstatus == 0 && mbxctx) {
344 /* save context */
345 mbxctx->mbx = mb_mbx;
346 bcopy(&mbxctx, mb_cqe->u0.s.mq_tag,
347 sizeof(struct oce_mbx_ctx *));
348 }
349 }
350
351 UNLOCK(&sc->bmbx_lock);
352
353 return rc;
354}
355
356/**
357 * @brief Function to read the mac address associated with an interface
358 * @param sc software handle to the device
359 * @param if_id interface id to read the address from
360 * @param perm set to 1 if reading the factory mac address.
361 * In this case if_id is ignored
362 * @param type type of the mac address, whether network or storage
363 * @param[out] mac [OUTPUT] pointer to a buffer containing the
364 * mac address when the command succeeds.
365 * @returns 0 on success, EIO on failure
366 */
367int
368oce_read_mac_addr(POCE_SOFTC sc, uint32_t if_id,
369 uint8_t perm, uint8_t type, struct mac_address_format *mac)
370{
371 struct oce_mbx mbx;
372 struct mbx_query_common_iface_mac *fwcmd;
373 int ret = 0;
374
375 bzero(&mbx, sizeof(struct oce_mbx));
376
377 fwcmd = (struct mbx_query_common_iface_mac *)&mbx.payload;
378 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
379 MBX_SUBSYSTEM_COMMON,
380 OPCODE_COMMON_QUERY_IFACE_MAC,
381 MBX_TIMEOUT_SEC,
382 sizeof(struct mbx_query_common_iface_mac),
383 OCE_MBX_VER_V0);
384
385 fwcmd->params.req.permanent = perm;
386 if (!perm)
387 fwcmd->params.req.if_id = (uint16_t) if_id;
388 else
389 fwcmd->params.req.if_id = 0;
390
391 fwcmd->params.req.type = type;
392
393 mbx.u0.s.embedded = 1;
394 mbx.payload_length = sizeof(struct mbx_query_common_iface_mac);
395 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
396
397 ret = oce_mbox_post(sc, &mbx, NULL);
398 if (ret)
399 return ret;
400
401 /* copy the mac addres in the output parameter */
402 mac->size_of_struct = fwcmd->params.rsp.mac.size_of_struct;
403 bcopy(&fwcmd->params.rsp.mac.mac_addr[0], &mac->mac_addr[0],
404 mac->size_of_struct);
405
406 return 0;
407}
408
409/**
410 * @brief Function to query the fw attributes from the hw
411 * @param sc software handle to the device
412 * @returns 0 on success, EIO on failure
413 */
414int
415oce_get_fw_config(POCE_SOFTC sc)
416{
417 struct oce_mbx mbx;
418 struct mbx_common_query_fw_config *fwcmd;
419 int ret = 0;
420
421 bzero(&mbx, sizeof(struct oce_mbx));
422
423 fwcmd = (struct mbx_common_query_fw_config *)&mbx.payload;
424 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
425 MBX_SUBSYSTEM_COMMON,
426 OPCODE_COMMON_QUERY_FIRMWARE_CONFIG,
427 MBX_TIMEOUT_SEC,
428 sizeof(struct mbx_common_query_fw_config),
429 OCE_MBX_VER_V0);
430
431 mbx.u0.s.embedded = 1;
432 mbx.payload_length = sizeof(struct mbx_common_query_fw_config);
433 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
434
435 ret = oce_mbox_post(sc, &mbx, NULL);
436 if (ret)
437 return ret;
438
439 DW_SWAP(u32ptr(fwcmd), sizeof(struct mbx_common_query_fw_config));
440
441 sc->config_number = fwcmd->params.rsp.config_number;
442 sc->asic_revision = fwcmd->params.rsp.asic_revision;
443 sc->port_id = fwcmd->params.rsp.port_id;
444 sc->function_mode = fwcmd->params.rsp.function_mode;
445 sc->function_caps = fwcmd->params.rsp.function_caps;
446
447 if (fwcmd->params.rsp.ulp[0].ulp_mode & ULP_NIC_MODE) {
448 sc->max_tx_rings = fwcmd->params.rsp.ulp[0].nic_wq_tot;
449 sc->max_rx_rings = fwcmd->params.rsp.ulp[0].lro_rqid_tot;
450 } else {
451 sc->max_tx_rings = fwcmd->params.rsp.ulp[1].nic_wq_tot;
452 sc->max_rx_rings = fwcmd->params.rsp.ulp[1].lro_rqid_tot;
453 }
454
455 return 0;
456
457}
458
459/**
460 *
461 * @brief function to create a device interface
462 * @param sc software handle to the device
463 * @param cap_flags capability flags
464 * @param en_flags enable capability flags
465 * @param vlan_tag optional vlan tag to associate with the if
466 * @param mac_addr pointer to a buffer containing the mac address
467 * @param[out] if_id [OUTPUT] pointer to an integer to hold the ID of the
468 interface created
469 * @returns 0 on success, EIO on failure
470 */
471int
472oce_if_create(POCE_SOFTC sc,
473 uint32_t cap_flags,
474 uint32_t en_flags,
475 uint16_t vlan_tag,
476 uint8_t *mac_addr,
477 uint32_t *if_id)
478{
479 struct oce_mbx mbx;
480 struct mbx_create_common_iface *fwcmd;
481 int rc = 0;
482
483 bzero(&mbx, sizeof(struct oce_mbx));
484
485 fwcmd = (struct mbx_create_common_iface *)&mbx.payload;
486 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
487 MBX_SUBSYSTEM_COMMON,
488 OPCODE_COMMON_CREATE_IFACE,
489 MBX_TIMEOUT_SEC,
490 sizeof(struct mbx_create_common_iface),
491 OCE_MBX_VER_V0);
492 DW_SWAP(u32ptr(&fwcmd->hdr), sizeof(struct mbx_hdr));
493
494 fwcmd->params.req.version = 0;
495 fwcmd->params.req.cap_flags = LE_32(cap_flags);
496 fwcmd->params.req.enable_flags = LE_32(en_flags);
497 if (mac_addr != NULL) {
498 bcopy(mac_addr, &fwcmd->params.req.mac_addr[0], 6);
499 fwcmd->params.req.vlan_tag.u0.normal.vtag = LE_16(vlan_tag);
500 fwcmd->params.req.mac_invalid = 0;
501 } else {
502 fwcmd->params.req.mac_invalid = 1;
503 }
504
505 mbx.u0.s.embedded = 1;
506 mbx.payload_length = sizeof(struct mbx_create_common_iface);
507 DW_SWAP(u32ptr(&mbx), OCE_BMBX_RHDR_SZ);
508
509 rc = oce_mbox_post(sc, &mbx, NULL);
510 if (rc)
511 return rc;
512
513 *if_id = LE_32(fwcmd->params.rsp.if_id);
514
515 if (mac_addr != NULL)
516 sc->pmac_id = LE_32(fwcmd->params.rsp.pmac_id);
517
518 return 0;
519}
520
521/**
522 * @brief Function to delete an interface
523 * @param sc software handle to the device
524 * @param if_id ID of the interface to delete
525 * @returns 0 on success, EIO on failure
526 */
527int
528oce_if_del(POCE_SOFTC sc, uint32_t if_id)
529{
530 struct oce_mbx mbx;
531 struct mbx_destroy_common_iface *fwcmd;
532 int rc = 0;
533
534 bzero(&mbx, sizeof(struct oce_mbx));
535
536 fwcmd = (struct mbx_destroy_common_iface *)&mbx.payload;
537 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
538 MBX_SUBSYSTEM_COMMON,
539 OPCODE_COMMON_DESTROY_IFACE,
540 MBX_TIMEOUT_SEC,
541 sizeof(struct mbx_destroy_common_iface),
542 OCE_MBX_VER_V0);
543
544 fwcmd->params.req.if_id = if_id;
545
546 mbx.u0.s.embedded = 1;
547 mbx.payload_length = sizeof(struct mbx_destroy_common_iface);
548 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
549
550 rc = oce_mbox_post(sc, &mbx, NULL);
551 return rc;
552}
553
554/**
555 * @brief Function to send the mbx command to configure vlan
556 * @param sc software handle to the device
557 * @param if_id interface identifier index
558 * @param vtag_arr array of vlan tags
559 * @param vtag_cnt number of elements in array
560 * @param untagged boolean TRUE/FLASE
561 * @param enable_promisc flag to enable/disable VLAN promiscuous mode
562 * @returns 0 on success, EIO on failure
563 */
564int
565oce_config_vlan(POCE_SOFTC sc,
566 uint32_t if_id,
567 struct normal_vlan *vtag_arr,
568 uint8_t vtag_cnt, uint32_t untagged, uint32_t enable_promisc)
569{
570 struct oce_mbx mbx;
571 struct mbx_common_config_vlan *fwcmd;
572 int rc;
573
574 bzero(&mbx, sizeof(struct oce_mbx));
575 fwcmd = (struct mbx_common_config_vlan *)&mbx.payload;
576
577 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
578 MBX_SUBSYSTEM_COMMON,
579 OPCODE_COMMON_CONFIG_IFACE_VLAN,
580 MBX_TIMEOUT_SEC,
581 sizeof(struct mbx_common_config_vlan),
582 OCE_MBX_VER_V0);
583
584 fwcmd->params.req.if_id = (uint8_t) if_id;
585 fwcmd->params.req.promisc = (uint8_t) enable_promisc;
586 fwcmd->params.req.untagged = (uint8_t) untagged;
587 fwcmd->params.req.num_vlans = vtag_cnt;
588
589 if (!enable_promisc) {
590 bcopy(vtag_arr, fwcmd->params.req.tags.normal_vlans,
591 vtag_cnt * sizeof(struct normal_vlan));
592 }
593 mbx.u0.s.embedded = 1;
594 mbx.payload_length = sizeof(struct mbx_common_config_vlan);
595 DW_SWAP(u32ptr(&mbx), (OCE_BMBX_RHDR_SZ + mbx.payload_length));
596
597 rc = oce_mbox_post(sc, &mbx, NULL);
598
599 return rc;
600
601}
602
603/**
604 * @brief Function to set flow control capability in the hardware
605 * @param sc software handle to the device
606 * @param flow_control flow control flags to set
607 * @returns 0 on success, EIO on failure
608 */
609int
610oce_set_flow_control(POCE_SOFTC sc, uint32_t flow_control)
611{
612 struct oce_mbx mbx;
613 struct mbx_common_get_set_flow_control *fwcmd =
614 (struct mbx_common_get_set_flow_control *)&mbx.payload;
615 int rc;
616
617 bzero(&mbx, sizeof(struct oce_mbx));
618
619 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
620 MBX_SUBSYSTEM_COMMON,
621 OPCODE_COMMON_SET_FLOW_CONTROL,
622 MBX_TIMEOUT_SEC,
623 sizeof(struct mbx_common_get_set_flow_control),
624 OCE_MBX_VER_V0);
625
626 if (flow_control & OCE_FC_TX)
627 fwcmd->tx_flow_control = 1;
628
629 if (flow_control & OCE_FC_RX)
630 fwcmd->rx_flow_control = 1;
631
632 mbx.u0.s.embedded = 1;
633 mbx.payload_length = sizeof(struct mbx_common_get_set_flow_control);
634 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
635
636 rc = oce_mbox_post(sc, &mbx, NULL);
637
638 return rc;
639}
640
641/**
642 * @brief Initialize the RSS CPU indirection table
643 *
644 * The table is used to choose the queue to place the incomming packets.
645 * Incomming packets are hashed. The lowest bits in the hash result
646 * are used as the index into the CPU indirection table.
647 * Each entry in the table contains the RSS CPU-ID returned by the NIC
648 * create. Based on the CPU ID, the receive completion is routed to
649 * the corresponding RSS CQs. (Non-RSS packets are always completed
650 * on the default (0) CQ).
651 *
652 * @param sc software handle to the device
653 * @param *fwcmd pointer to the rss mbox command
654 * @returns none
655 */
656static int
657oce_rss_itbl_init(POCE_SOFTC sc, struct mbx_config_nic_rss *fwcmd)
658{
659 int i = 0, j = 0, rc = 0;
660 uint8_t *tbl = fwcmd->params.req.cputable;
661
662
663 for (j = 0; j < sc->nrqs; j++) {
664 if (sc->rq[j]->cfg.is_rss_queue) {
665 tbl[i] = sc->rq[j]->rss_cpuid;
666 i = i + 1;
667 }
668 }
669 if (i == 0) {
670 device_printf(sc->dev, "error: Invalid number of RSS RQ's\n");
671 rc = ENXIO;
672
673 }
674
675 /* fill log2 value indicating the size of the CPU table */
676 if (rc == 0)
677 fwcmd->params.req.cpu_tbl_sz_log2 = LE_16(OCE_LOG2(i));
678
679 return rc;
680}
681
682/**
683 * @brief Function to set flow control capability in the hardware
684 * @param sc software handle to the device
685 * @param if_id interface id to read the address from
686 * @param enable_rss 0=disable, RSS_ENABLE_xxx flags otherwise
687 * @returns 0 on success, EIO on failure
688 */
689int
690oce_config_nic_rss(POCE_SOFTC sc, uint32_t if_id, uint16_t enable_rss)
691{
692 int rc;
693 struct oce_mbx mbx;
694 struct mbx_config_nic_rss *fwcmd =
695 (struct mbx_config_nic_rss *)&mbx.payload;
696
697 bzero(&mbx, sizeof(struct oce_mbx));
698
699 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
700 MBX_SUBSYSTEM_NIC,
701 NIC_CONFIG_RSS,
702 MBX_TIMEOUT_SEC,
703 sizeof(struct mbx_config_nic_rss),
704 OCE_MBX_VER_V0);
705 if (enable_rss)
706 fwcmd->params.req.enable_rss = (RSS_ENABLE_IPV4 |
707 RSS_ENABLE_TCP_IPV4 |
708 RSS_ENABLE_IPV6 |
709 RSS_ENABLE_TCP_IPV6);
710 fwcmd->params.req.flush = OCE_FLUSH;
711 fwcmd->params.req.if_id = LE_32(if_id);
712
713 srandom(arc4random()); /* random entropy seed */
714 read_random(fwcmd->params.req.hash, sizeof(fwcmd->params.req.hash));
715
716 rc = oce_rss_itbl_init(sc, fwcmd);
717 if (rc == 0) {
718 mbx.u0.s.embedded = 1;
719 mbx.payload_length = sizeof(struct mbx_config_nic_rss);
720 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
721
722 rc = oce_mbox_post(sc, &mbx, NULL);
723
724 }
725
726 return rc;
727}
728
729/**
730 * @brief RXF function to enable/disable device promiscuous mode
731 * @param sc software handle to the device
732 * @param enable enable/disable flag
733 * @returns 0 on success, EIO on failure
734 * @note
735 * The NIC_CONFIG_PROMISCUOUS command deprecated for Lancer.
736 * This function uses the COMMON_SET_IFACE_RX_FILTER command instead.
737 */
738int
739oce_rxf_set_promiscuous(POCE_SOFTC sc, uint32_t enable)
740{
741 struct mbx_set_common_iface_rx_filter *fwcmd;
742 int sz = sizeof(struct mbx_set_common_iface_rx_filter);
743 iface_rx_filter_ctx_t *req;
744 OCE_DMA_MEM sgl;
745 int rc;
746
747 /* allocate mbx payload's dma scatter/gather memory */
748 rc = oce_dma_alloc(sc, sz, &sgl, 0);
749 if (rc)
750 return rc;
751
752 fwcmd = OCE_DMAPTR(&sgl, struct mbx_set_common_iface_rx_filter);
753
754 req = &fwcmd->params.req;
755 req->iface_flags_mask = MBX_RX_IFACE_FLAGS_PROMISCUOUS |
756 MBX_RX_IFACE_FLAGS_VLAN_PROMISCUOUS;
757 if (enable) {
758 req->iface_flags = MBX_RX_IFACE_FLAGS_PROMISCUOUS |
759 MBX_RX_IFACE_FLAGS_VLAN_PROMISCUOUS;
760 }
761 req->if_id = sc->if_id;
762
763 rc = oce_set_common_iface_rx_filter(sc, &sgl);
764 oce_dma_free(sc, &sgl);
765
766 return rc;
767}
768
769
770/**
771 * @brief Function modify and select rx filter options
772 * @param sc software handle to the device
773 * @param sgl scatter/gather request/response
774 * @returns 0 on success, error code on failure
775 */
776int
777oce_set_common_iface_rx_filter(POCE_SOFTC sc, POCE_DMA_MEM sgl)
778{
779 struct oce_mbx mbx;
780 int mbx_sz = sizeof(struct mbx_set_common_iface_rx_filter);
781 struct mbx_set_common_iface_rx_filter *fwcmd;
782 int rc;
783
784 bzero(&mbx, sizeof(struct oce_mbx));
785 fwcmd = OCE_DMAPTR(sgl, struct mbx_set_common_iface_rx_filter);
786
787 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
788 MBX_SUBSYSTEM_COMMON,
789 OPCODE_COMMON_SET_IFACE_RX_FILTER,
790 MBX_TIMEOUT_SEC,
791 mbx_sz,
792 OCE_MBX_VER_V0);
793
794 oce_dma_sync(sgl, BUS_DMASYNC_PREWRITE);
795 mbx.u0.s.embedded = 0;
796 mbx.u0.s.sge_count = 1;
797 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(sgl->paddr);
798 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(sgl->paddr);
799 mbx.payload.u0.u1.sgl[0].length = mbx_sz;
800 mbx.payload_length = mbx_sz;
801 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
802
803 rc = oce_mbox_post(sc, &mbx, NULL);
804 return rc;
805}
806
807/**
808 * @brief Function to query the link status from the hardware
809 * @param sc software handle to the device
810 * @param[out] link pointer to the structure returning link attributes
811 * @returns 0 on success, EIO on failure
812 */
813int
814oce_get_link_status(POCE_SOFTC sc, struct link_status *link)
815{
816 struct oce_mbx mbx;
817 struct mbx_query_common_link_config *fwcmd;
818 int rc = 0;
819
820 bzero(&mbx, sizeof(struct oce_mbx));
821
822 fwcmd = (struct mbx_query_common_link_config *)&mbx.payload;
823 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
824 MBX_SUBSYSTEM_COMMON,
825 OPCODE_COMMON_QUERY_LINK_CONFIG,
826 MBX_TIMEOUT_SEC,
827 sizeof(struct mbx_query_common_link_config),
828 OCE_MBX_VER_V0);
829
830 mbx.u0.s.embedded = 1;
831 mbx.payload_length = sizeof(struct mbx_query_common_link_config);
832 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
833
834 rc = oce_mbox_post(sc, &mbx, NULL);
835
836 if (rc) {
837 device_printf(sc->dev, "Could not get link speed: %d\n", rc);
838 } else {
839 /* interpret response */
840 bcopy(&fwcmd->params.rsp, link, sizeof(struct link_status));
841 link->logical_link_status = LE_32(link->logical_link_status);
842 link->qos_link_speed = LE_16(link->qos_link_speed);
843 }
844
845 return rc;
846}
847
848
849
850int
851oce_mbox_get_nic_stats_v0(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem)
852{
853 struct oce_mbx mbx;
854 struct mbx_get_nic_stats_v0 *fwcmd;
855 int rc = 0;
856
857 bzero(&mbx, sizeof(struct oce_mbx));
858
859 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_nic_stats_v0);
860 bzero(fwcmd, sizeof(struct mbx_get_nic_stats_v0));
861
862 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
863 MBX_SUBSYSTEM_NIC,
864 NIC_GET_STATS,
865 MBX_TIMEOUT_SEC,
866 sizeof(struct mbx_get_nic_stats_v0),
867 OCE_MBX_VER_V0);
868
869 mbx.u0.s.embedded = 0;
870 mbx.u0.s.sge_count = 1;
871
872 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
873
874 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
875 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
876 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_nic_stats_v0);
877
878 mbx.payload_length = sizeof(struct mbx_get_nic_stats_v0);
879
880 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
881
882 rc = oce_mbox_post(sc, &mbx, NULL);
883
884 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
885
886 if (rc) {
887 device_printf(sc->dev,
888 "Could not get nic statistics: %d\n", rc);
889 }
890
891 return rc;
892}
893
894
895
896/**
897 * @brief Function to get NIC statistics
898 * @param sc software handle to the device
899 * @param *stats pointer to where to store statistics
900 * @param reset_stats resets statistics of set
901 * @returns 0 on success, EIO on failure
902 * @note command depricated in Lancer
903 */
904int
905oce_mbox_get_nic_stats(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem)
906{
907 struct oce_mbx mbx;
908 struct mbx_get_nic_stats *fwcmd;
909 int rc = 0;
910
911 bzero(&mbx, sizeof(struct oce_mbx));
912 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_nic_stats);
913 bzero(fwcmd, sizeof(struct mbx_get_nic_stats));
914
915 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
916 MBX_SUBSYSTEM_NIC,
917 NIC_GET_STATS,
918 MBX_TIMEOUT_SEC,
919 sizeof(struct mbx_get_nic_stats),
920 OCE_MBX_VER_V1);
921
922
923 mbx.u0.s.embedded = 0; /* stats too large for embedded mbx rsp */
924 mbx.u0.s.sge_count = 1; /* using scatter gather instead */
925
926 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
927 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
928 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
929 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_nic_stats);
930
931 mbx.payload_length = sizeof(struct mbx_get_nic_stats);
932 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
933
934 rc = oce_mbox_post(sc, &mbx, NULL);
935 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
936 if (rc) {
937 device_printf(sc->dev,
938 "Could not get nic statistics: %d\n", rc);
939 }
940 return rc;
941}
942
943
944/**
945 * @brief Function to get pport (physical port) statistics
946 * @param sc software handle to the device
947 * @param *stats pointer to where to store statistics
948 * @param reset_stats resets statistics of set
949 * @returns 0 on success, EIO on failure
950 */
951int
952oce_mbox_get_pport_stats(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem,
953 uint32_t reset_stats)
954{
955 struct oce_mbx mbx;
956 struct mbx_get_pport_stats *fwcmd;
957 int rc = 0;
958
959 bzero(&mbx, sizeof(struct oce_mbx));
960 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_pport_stats);
961 bzero(fwcmd, sizeof(struct mbx_get_pport_stats));
962
963 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
964 MBX_SUBSYSTEM_NIC,
965 NIC_GET_PPORT_STATS,
966 MBX_TIMEOUT_SEC,
967 sizeof(struct mbx_get_pport_stats),
968 OCE_MBX_VER_V0);
969
970 fwcmd->params.req.reset_stats = reset_stats;
971 fwcmd->params.req.port_number = sc->if_id;
972
973 mbx.u0.s.embedded = 0; /* stats too large for embedded mbx rsp */
974 mbx.u0.s.sge_count = 1; /* using scatter gather instead */
975
976 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
977 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
978 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
979 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_pport_stats);
980
981 mbx.payload_length = sizeof(struct mbx_get_pport_stats);
982 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
983
984 rc = oce_mbox_post(sc, &mbx, NULL);
985 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
986
987 if (rc != 0) {
988 device_printf(sc->dev,
989 "Could not get physical port statistics: %d\n", rc);
990 }
991
992 return rc;
993}
994
995
996/**
997 * @brief Function to get vport (virtual port) statistics
998 * @param sc software handle to the device
999 * @param *stats pointer to where to store statistics
1000 * @param reset_stats resets statistics of set
1001 * @returns 0 on success, EIO on failure
1002 */
1003int
1004oce_mbox_get_vport_stats(POCE_SOFTC sc, POCE_DMA_MEM pstats_dma_mem,
1005 uint32_t req_size, uint32_t reset_stats)
1006{
1007 struct oce_mbx mbx;
1008 struct mbx_get_vport_stats *fwcmd;
1009 int rc = 0;
1010
1011 bzero(&mbx, sizeof(struct oce_mbx));
1012
1013 fwcmd = OCE_DMAPTR(pstats_dma_mem, struct mbx_get_vport_stats);
1014 bzero(fwcmd, sizeof(struct mbx_get_vport_stats));
1015
1016 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1017 MBX_SUBSYSTEM_NIC,
1018 NIC_GET_VPORT_STATS,
1019 MBX_TIMEOUT_SEC,
1020 sizeof(struct mbx_get_vport_stats),
1021 OCE_MBX_VER_V0);
1022
1023 fwcmd->params.req.reset_stats = reset_stats;
1024 fwcmd->params.req.vport_number = sc->if_id;
1025
1026 mbx.u0.s.embedded = 0; /* stats too large for embedded mbx rsp */
1027 mbx.u0.s.sge_count = 1; /* using scatter gather instead */
1028
1029 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_PREWRITE);
1030 mbx.payload.u0.u1.sgl[0].pa_lo = ADDR_LO(pstats_dma_mem->paddr);
1031 mbx.payload.u0.u1.sgl[0].pa_hi = ADDR_HI(pstats_dma_mem->paddr);
1032 mbx.payload.u0.u1.sgl[0].length = sizeof(struct mbx_get_vport_stats);
1033
1034 mbx.payload_length = sizeof(struct mbx_get_vport_stats);
1035 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1036
1037 rc = oce_mbox_post(sc, &mbx, NULL);
1038 oce_dma_sync(pstats_dma_mem, BUS_DMASYNC_POSTWRITE);
1039
1040 if (rc != 0) {
1041 device_printf(sc->dev,
1042 "Could not get physical port statistics: %d\n", rc);
1043 }
1044
1045 return rc;
1046}
1047
1048
1049/**
1050 * @brief Function to update the muticast filter with
1051 * values in dma_mem
1052 * @param sc software handle to the device
1053 * @param dma_mem pointer to dma memory region
1054 * @returns 0 on success, EIO on failure
1055 */
1056int
1057oce_update_multicast(POCE_SOFTC sc, POCE_DMA_MEM pdma_mem)
1058{
1059 struct oce_mbx mbx;
1060 struct oce_mq_sge *sgl;
1061 struct mbx_set_common_iface_multicast *req = NULL;
1062 int rc = 0;
1063
1064 req = OCE_DMAPTR(pdma_mem, struct mbx_set_common_iface_multicast);
1065 mbx_common_req_hdr_init(&req->hdr, 0, 0,
1066 MBX_SUBSYSTEM_COMMON,
1067 OPCODE_COMMON_SET_IFACE_MULTICAST,
1068 MBX_TIMEOUT_SEC,
1069 sizeof(struct mbx_set_common_iface_multicast),
1070 OCE_MBX_VER_V0);
1071
1072 bzero(&mbx, sizeof(struct oce_mbx));
1073
1074 mbx.u0.s.embedded = 0; /*Non embeded*/
1075 mbx.payload_length = sizeof(struct mbx_set_common_iface_multicast);
1076 mbx.u0.s.sge_count = 1;
1077 sgl = &mbx.payload.u0.u1.sgl[0];
1078 sgl->pa_hi = htole32(upper_32_bits(pdma_mem->paddr));
1079 sgl->pa_lo = htole32((pdma_mem->paddr) & 0xFFFFFFFF);
1080 sgl->length = htole32(mbx.payload_length);
1081
1082 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1083
1084 rc = oce_mbox_post(sc, &mbx, NULL);
1085
1086 return rc;
1087}
1088
1089
1090/**
1091 * @brief Function to send passthrough Ioctls
1092 * @param sc software handle to the device
1093 * @param dma_mem pointer to dma memory region
1094 * @param req_size size of dma_mem
1095 * @returns 0 on success, EIO on failure
1096 */
1097int
1098oce_pass_through_mbox(POCE_SOFTC sc, POCE_DMA_MEM dma_mem, uint32_t req_size)
1099{
1100 struct oce_mbx mbx;
1101 struct oce_mq_sge *sgl;
1102 int rc = 0;
1103
1104 bzero(&mbx, sizeof(struct oce_mbx));
1105
1106 mbx.u0.s.embedded = 0; /*Non embeded*/
1107 mbx.payload_length = req_size;
1108 mbx.u0.s.sge_count = 1;
1109 sgl = &mbx.payload.u0.u1.sgl[0];
1110 sgl->pa_hi = htole32(upper_32_bits(dma_mem->paddr));
1111 sgl->pa_lo = htole32((dma_mem->paddr) & 0xFFFFFFFF);
1112 sgl->length = htole32(req_size);
1113
1114 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1115
1116 rc = oce_mbox_post(sc, &mbx, NULL);
1117 return rc;
1118}
1119
1120
1121int
1122oce_mbox_macaddr_add(POCE_SOFTC sc, uint8_t *mac_addr,
1123 uint32_t if_id, uint32_t *pmac_id)
1124{
1125 struct oce_mbx mbx;
1126 struct mbx_add_common_iface_mac *fwcmd;
1127 int rc = 0;
1128
1129 bzero(&mbx, sizeof(struct oce_mbx));
1130
1131 fwcmd = (struct mbx_add_common_iface_mac *)&mbx.payload;
1132 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1133 MBX_SUBSYSTEM_COMMON,
1134 OPCODE_COMMON_ADD_IFACE_MAC,
1135 MBX_TIMEOUT_SEC,
1136 sizeof(struct mbx_add_common_iface_mac),
1137 OCE_MBX_VER_V0);
1138
1139 fwcmd->params.req.if_id = (uint16_t) if_id;
1140 bcopy(mac_addr, fwcmd->params.req.mac_address, 6);
1141
1142 mbx.u0.s.embedded = 1;
1143 mbx.payload_length = sizeof(struct mbx_add_common_iface_mac);
1144 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1145 rc = oce_mbox_post(sc, &mbx, NULL);
1146 if (rc)
1147 return rc;
1148
1149 *pmac_id = fwcmd->params.rsp.pmac_id;
1150
1151 return rc;
1152}
1153
1154
1155int
1156oce_mbox_macaddr_del(POCE_SOFTC sc, uint32_t if_id, uint32_t pmac_id)
1157{
1158 struct oce_mbx mbx;
1159 struct mbx_del_common_iface_mac *fwcmd;
1160 int rc = 0;
1161
1162 bzero(&mbx, sizeof(struct oce_mbx));
1163
1164 fwcmd = (struct mbx_del_common_iface_mac *)&mbx.payload;
1165 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1166 MBX_SUBSYSTEM_COMMON,
1167 OPCODE_COMMON_DEL_IFACE_MAC,
1168 MBX_TIMEOUT_SEC,
1169 sizeof(struct mbx_del_common_iface_mac),
1170 OCE_MBX_VER_V0);
1171
1172 fwcmd->params.req.if_id = (uint16_t)if_id;
1173 fwcmd->params.req.pmac_id = pmac_id;
1174
1175 mbx.u0.s.embedded = 1;
1176 mbx.payload_length = sizeof(struct mbx_del_common_iface_mac);
1177 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1178
1179 rc = oce_mbox_post(sc, &mbx, NULL);
1180 return rc;
1181}
1182
1183
1184
1185int
1186oce_mbox_check_native_mode(POCE_SOFTC sc)
1187{
1188 struct oce_mbx mbx;
1189 struct mbx_common_set_function_cap *fwcmd;
1190 int rc = 0;
1191
1192 bzero(&mbx, sizeof(struct oce_mbx));
1193
1194 fwcmd = (struct mbx_common_set_function_cap *)&mbx.payload;
1195 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1196 MBX_SUBSYSTEM_COMMON,
1197 OPCODE_COMMON_SET_FUNCTIONAL_CAPS,
1198 MBX_TIMEOUT_SEC,
1199 sizeof(struct mbx_common_set_function_cap),
1200 OCE_MBX_VER_V0);
1201
1202 fwcmd->params.req.valid_capability_flags = CAP_SW_TIMESTAMPS |
1203 CAP_BE3_NATIVE_ERX_API;
1204
1205 fwcmd->params.req.capability_flags = CAP_BE3_NATIVE_ERX_API;
1206
1207 mbx.u0.s.embedded = 1;
1208 mbx.payload_length = sizeof(struct mbx_common_set_function_cap);
1209 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1210
1211 rc = oce_mbox_post(sc, &mbx, NULL);
1212 //if (rc != 0) This can fail in legacy mode. So skip
1213 // FN_LEAVE(rc);
1214
1215 sc->be3_native = fwcmd->params.rsp.capability_flags
1216 & CAP_BE3_NATIVE_ERX_API;
1217
1218 return 0;
1219}
1220
1221
1222
1223int
1224oce_mbox_cmd_set_loopback(POCE_SOFTC sc, uint8_t port_num,
1225 uint8_t loopback_type, uint8_t enable)
1226{
1227 struct oce_mbx mbx;
1228 struct mbx_lowlevel_set_loopback_mode *fwcmd;
1229 int rc = 0;
1230
1231
1232 bzero(&mbx, sizeof(struct oce_mbx));
1233
1234 fwcmd = (struct mbx_lowlevel_set_loopback_mode *)&mbx.payload;
1235 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1236 MBX_SUBSYSTEM_LOWLEVEL,
1237 OPCODE_LOWLEVEL_SET_LOOPBACK_MODE,
1238 MBX_TIMEOUT_SEC,
1239 sizeof(struct mbx_lowlevel_set_loopback_mode),
1240 OCE_MBX_VER_V0);
1241
1242 fwcmd->params.req.src_port = port_num;
1243 fwcmd->params.req.dest_port = port_num;
1244 fwcmd->params.req.loopback_type = loopback_type;
1245 fwcmd->params.req.loopback_state = enable;
1246
1247 mbx.u0.s.embedded = 1;
1248 mbx.payload_length = sizeof(struct mbx_lowlevel_set_loopback_mode);
1249 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1250
1251 rc = oce_mbox_post(sc, &mbx, NULL);
1252
1253 return rc;
1254
1255}
1256
1257int
1258oce_mbox_cmd_test_loopback(POCE_SOFTC sc, uint32_t port_num,
1259 uint32_t loopback_type, uint32_t pkt_size, uint32_t num_pkts,
1260 uint64_t pattern)
1261{
1262
1263 struct oce_mbx mbx;
1264 struct mbx_lowlevel_test_loopback_mode *fwcmd;
1265 int rc = 0;
1266
1267
1268 bzero(&mbx, sizeof(struct oce_mbx));
1269
1270 fwcmd = (struct mbx_lowlevel_test_loopback_mode *)&mbx.payload;
1271 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1272 MBX_SUBSYSTEM_LOWLEVEL,
1273 OPCODE_LOWLEVEL_TEST_LOOPBACK,
1274 MBX_TIMEOUT_SEC,
1275 sizeof(struct mbx_lowlevel_test_loopback_mode),
1276 OCE_MBX_VER_V0);
1277
1278 fwcmd->params.req.pattern = pattern;
1279 fwcmd->params.req.src_port = port_num;
1280 fwcmd->params.req.dest_port = port_num;
1281 fwcmd->params.req.pkt_size = pkt_size;
1282 fwcmd->params.req.num_pkts = num_pkts;
1283 fwcmd->params.req.loopback_type = loopback_type;
1284
1285 mbx.u0.s.embedded = 1;
1286 mbx.payload_length = sizeof(struct mbx_lowlevel_test_loopback_mode);
1287 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ);
1288
1289 rc = oce_mbox_post(sc, &mbx, NULL);
1290 if (rc)
1291 return rc;
1292
1293 return(fwcmd->params.rsp.status);
1294}
1295
1296int
1297oce_mbox_write_flashrom(POCE_SOFTC sc, uint32_t optype,uint32_t opcode,
1298 POCE_DMA_MEM pdma_mem, uint32_t num_bytes)
1299{
1300
1301 struct oce_mbx mbx;
1302 struct oce_mq_sge *sgl = NULL;
1303 struct mbx_common_read_write_flashrom *fwcmd = NULL;
1304 int rc = 0, payload_len = 0;
1305
1306 bzero(&mbx, sizeof(struct oce_mbx));
1307 fwcmd = OCE_DMAPTR(pdma_mem, struct mbx_common_read_write_flashrom);
1308 payload_len = sizeof(struct mbx_common_read_write_flashrom) + 32*1024;
1309
1310 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1311 MBX_SUBSYSTEM_COMMON,
1312 OPCODE_COMMON_WRITE_FLASHROM,
1313 LONG_TIMEOUT,
1314 payload_len,
1315 OCE_MBX_VER_V0);
1316
1317 fwcmd->flash_op_type = optype;
1318 fwcmd->flash_op_code = opcode;
1319 fwcmd->data_buffer_size = num_bytes;
1320
1321 mbx.u0.s.embedded = 0; /*Non embeded*/
1322 mbx.payload_length = payload_len;
1323 mbx.u0.s.sge_count = 1;
1324
1325 sgl = &mbx.payload.u0.u1.sgl[0];
1326 sgl->pa_hi = upper_32_bits(pdma_mem->paddr);
1327 sgl->pa_lo = pdma_mem->paddr & 0xFFFFFFFF;
1328 sgl->length = payload_len;
1329
1330 /* post the command */
1331 if (rc) {
1332 device_printf(sc->dev, "Write FlashROM mbox post failed\n");
1333 } else {
1334 rc = fwcmd->hdr.u0.rsp.status;
1335 }
1336
1337 return rc;
1338
1339}
1340
1341int
1342oce_mbox_get_flashrom_crc(POCE_SOFTC sc, uint8_t *flash_crc,
1343 uint32_t offset, uint32_t optype)
1344{
1345
1346 int rc = 0, payload_len = 0;
1347 struct oce_mbx mbx;
1348 struct mbx_common_read_write_flashrom *fwcmd;
1349
1350 bzero(&mbx, sizeof(struct oce_mbx));
1351
1352 fwcmd = (struct mbx_common_read_write_flashrom *)&mbx.payload;
1353
1354 /* Firmware requires extra 4 bytes with this ioctl. Since there
1355 is enough room in the mbx payload it should be good enough
1356 Reference: Bug 14853
1357 */
1358 payload_len = sizeof(struct mbx_common_read_write_flashrom) + 4;
1359
1360 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1361 MBX_SUBSYSTEM_COMMON,
1362 OPCODE_COMMON_READ_FLASHROM,
1363 MBX_TIMEOUT_SEC,
1364 payload_len,
1365 OCE_MBX_VER_V0);
1366
1367 fwcmd->flash_op_type = optype;
1368 fwcmd->flash_op_code = FLASHROM_OPER_REPORT;
1369 fwcmd->data_offset = offset;
1370 fwcmd->data_buffer_size = 0x4;
1371
1372 mbx.u0.s.embedded = 1;
1373 mbx.payload_length = payload_len;
1374
1375 /* post the command */
1376 rc = oce_mbox_post(sc, &mbx, NULL);
1377 if (rc) {
1378 device_printf(sc->dev, "Read FlashROM CRC mbox post failed\n");
1379 } else {
1380 bcopy(fwcmd->data_buffer, flash_crc, 4);
1381 rc = fwcmd->hdr.u0.rsp.status;
1382 }
1383 return rc;
1384}
1385
1386int
1387oce_mbox_get_phy_info(POCE_SOFTC sc, struct oce_phy_info *phy_info)
1388{
1389
1390 struct oce_mbx mbx;
1391 struct mbx_common_phy_info *fwcmd;
1392 int rc = 0;
1393
1394 bzero(&mbx, sizeof(struct oce_mbx));
1395
1396 fwcmd = (struct mbx_common_phy_info *)&mbx.payload;
1397 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1398 MBX_SUBSYSTEM_COMMON,
1399 OPCODE_COMMON_GET_PHY_CONFIG,
1400 MBX_TIMEOUT_SEC,
1401 sizeof(struct mbx_common_phy_info),
1402 OCE_MBX_VER_V0);
1403
1404 mbx.u0.s.embedded = 1;
1405 mbx.payload_length = sizeof(struct mbx_common_phy_info);
1406
1407 /* now post the command */
1408 rc = oce_mbox_post(sc, &mbx, NULL);
1409 if (rc) {
1410 device_printf(sc->dev, "Read PHY info mbox post failed\n");
1411 } else {
1412 rc = fwcmd->hdr.u0.rsp.status;
1413 phy_info->phy_type = fwcmd->params.rsp.phy_info.phy_type;
1414 phy_info->interface_type =
1415 fwcmd->params.rsp.phy_info.interface_type;
1416 phy_info->auto_speeds_supported =
1417 fwcmd->params.rsp.phy_info.auto_speeds_supported;
1418 phy_info->fixed_speeds_supported =
1419 fwcmd->params.rsp.phy_info.fixed_speeds_supported;
1420 phy_info->misc_params =fwcmd->params.rsp.phy_info.misc_params;
1421
1422 }
1423 return rc;
1424
1425}
1426
1427
1428int
1429oce_mbox_lancer_write_flashrom(POCE_SOFTC sc, uint32_t data_size,
1430 uint32_t data_offset, POCE_DMA_MEM pdma_mem,
1431 uint32_t *written_data, uint32_t *additional_status)
1432{
1433
1434 struct oce_mbx mbx;
1435 struct mbx_lancer_common_write_object *fwcmd = NULL;
1436 int rc = 0, payload_len = 0;
1437
1438 bzero(&mbx, sizeof(struct oce_mbx));
1439 payload_len = sizeof(struct mbx_lancer_common_write_object);
1440
1441 mbx.u0.s.embedded = 1;/* Embedded */
1442 mbx.payload_length = payload_len;
1443 fwcmd = (struct mbx_lancer_common_write_object *)&mbx.payload;
1444
1445 /* initialize the ioctl header */
1446 mbx_common_req_hdr_init(&fwcmd->params.req.hdr, 0, 0,
1447 MBX_SUBSYSTEM_COMMON,
1448 OPCODE_COMMON_WRITE_OBJECT,
1449 LONG_TIMEOUT,
1450 payload_len,
1451 OCE_MBX_VER_V0);
1452
1453 fwcmd->params.req.write_length = data_size;
1454 if (data_size == 0)
1455 fwcmd->params.req.eof = 1;
1456 else
1457 fwcmd->params.req.eof = 0;
1458
1459 strcpy(fwcmd->params.req.object_name, "/prg");
1460 fwcmd->params.req.descriptor_count = 1;
1461 fwcmd->params.req.write_offset = data_offset;
1462 fwcmd->params.req.buffer_length = data_size;
1463 fwcmd->params.req.address_lower = pdma_mem->paddr & 0xFFFFFFFF;
1464 fwcmd->params.req.address_upper = upper_32_bits(pdma_mem->paddr);
1465
1466 /* post the command */
1467 rc = oce_mbox_post(sc, &mbx, NULL);
1468 if (rc) {
1469 device_printf(sc->dev,
1470 "Write Lancer FlashROM mbox post failed\n");
1471 } else {
1472 *written_data = fwcmd->params.rsp.actual_write_length;
1473 *additional_status = fwcmd->params.rsp.additional_status;
1474 rc = fwcmd->params.rsp.status;
1475 }
1476 return rc;
1477
1478}
1479
1480
1481
1482int
1483oce_mbox_create_rq(struct oce_rq *rq)
1484{
1485
1486 struct oce_mbx mbx;
1487 struct mbx_create_nic_rq *fwcmd;
1488 POCE_SOFTC sc = rq->parent;
1489 int rc, num_pages = 0;
1490
1491 if (rq->qstate == QCREATED)
1492 return 0;
1493
1494 bzero(&mbx, sizeof(struct oce_mbx));
1495
1496 fwcmd = (struct mbx_create_nic_rq *)&mbx.payload;
1497 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1498 MBX_SUBSYSTEM_NIC,
1499 NIC_CREATE_RQ, MBX_TIMEOUT_SEC,
1500 sizeof(struct mbx_create_nic_rq),
1501 OCE_MBX_VER_V0);
1502
1503 /* oce_page_list will also prepare pages */
1504 num_pages = oce_page_list(rq->ring, &fwcmd->params.req.pages[0]);
1505
1506 if (IS_XE201(sc)) {
1507 fwcmd->params.req.frag_size = rq->cfg.frag_size/2048;
1508 fwcmd->params.req.page_size = 1;
1509 fwcmd->hdr.u0.req.version = OCE_MBX_VER_V1;
1510 } else
1511 fwcmd->params.req.frag_size = OCE_LOG2(rq->cfg.frag_size);
1512 fwcmd->params.req.num_pages = num_pages;
1513 fwcmd->params.req.cq_id = rq->cq->cq_id;
1514 fwcmd->params.req.if_id = sc->if_id;
1515 fwcmd->params.req.max_frame_size = rq->cfg.mtu;
1516 fwcmd->params.req.is_rss_queue = rq->cfg.is_rss_queue;
1517
1518 mbx.u0.s.embedded = 1;
1519 mbx.payload_length = sizeof(struct mbx_create_nic_rq);
1520
1521 rc = oce_mbox_post(sc, &mbx, NULL);
1522 if (rc)
1523 goto error;
1524
1525 rq->rq_id = fwcmd->params.rsp.rq_id;
1526 rq->rss_cpuid = fwcmd->params.rsp.rss_cpuid;
1527
1528 return 0;
1529error:
1530 device_printf(sc->dev, "Mbox Create RQ failed\n");
1531 return rc;
1532
1533}
1534
1535
1536
1537int
1538oce_mbox_create_wq(struct oce_wq *wq)
1539{
1540 struct oce_mbx mbx;
1541 struct mbx_create_nic_wq *fwcmd;
1542 POCE_SOFTC sc = wq->parent;
1543 int rc = 0, version, num_pages;
1544
1545 bzero(&mbx, sizeof(struct oce_mbx));
1546
1547 fwcmd = (struct mbx_create_nic_wq *)&mbx.payload;
1548 if (IS_XE201(sc)) {
1549 version = OCE_MBX_VER_V1;
1550 fwcmd->params.req.if_id = sc->if_id;
1551 } else
1552 version = OCE_MBX_VER_V0;
1553
1554 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1555 MBX_SUBSYSTEM_NIC,
1556 NIC_CREATE_WQ, MBX_TIMEOUT_SEC,
1557 sizeof(struct mbx_create_nic_wq),
1558 version);
1559
1560 num_pages = oce_page_list(wq->ring, &fwcmd->params.req.pages[0]);
1561
1562 fwcmd->params.req.nic_wq_type = wq->cfg.wq_type;
1563 fwcmd->params.req.num_pages = num_pages;
1564 fwcmd->params.req.wq_size = OCE_LOG2(wq->cfg.q_len) + 1;
1565 fwcmd->params.req.cq_id = wq->cq->cq_id;
1566 fwcmd->params.req.ulp_num = 1;
1567
1568 mbx.u0.s.embedded = 1;
1569 mbx.payload_length = sizeof(struct mbx_create_nic_wq);
1570
1571 rc = oce_mbox_post(sc, &mbx, NULL);
1572 if (rc)
1573 goto error;
1574
1575 wq->wq_id = LE_16(fwcmd->params.rsp.wq_id);
1576
1577 return 0;
1578error:
1579 device_printf(sc->dev, "Mbox Create WQ failed\n");
1580 return rc;
1581
1582}
1583
1584
1585
1586int
1587oce_mbox_create_eq(struct oce_eq *eq)
1588{
1589 struct oce_mbx mbx;
1590 struct mbx_create_common_eq *fwcmd;
1591 POCE_SOFTC sc = eq->parent;
1592 int rc = 0;
1593 uint32_t num_pages;
1594
1595 bzero(&mbx, sizeof(struct oce_mbx));
1596
1597 fwcmd = (struct mbx_create_common_eq *)&mbx.payload;
1598
1599 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1600 MBX_SUBSYSTEM_COMMON,
1601 OPCODE_COMMON_CREATE_EQ, MBX_TIMEOUT_SEC,
1602 sizeof(struct mbx_create_common_eq),
1603 OCE_MBX_VER_V0);
1604
1605 num_pages = oce_page_list(eq->ring, &fwcmd->params.req.pages[0]);
1606 fwcmd->params.req.ctx.num_pages = num_pages;
1607 fwcmd->params.req.ctx.valid = 1;
1608 fwcmd->params.req.ctx.size = (eq->eq_cfg.item_size == 4) ? 0 : 1;
1609 fwcmd->params.req.ctx.count = OCE_LOG2(eq->eq_cfg.q_len / 256);
1610 fwcmd->params.req.ctx.armed = 0;
1611 fwcmd->params.req.ctx.delay_mult = eq->eq_cfg.cur_eqd;
1612
1613
1614 mbx.u0.s.embedded = 1;
1615 mbx.payload_length = sizeof(struct mbx_create_common_eq);
1616
1617 rc = oce_mbox_post(sc, &mbx, NULL);
1618 if (rc)
1619 goto error;
1620
1621 eq->eq_id = LE_16(fwcmd->params.rsp.eq_id);
1622
1623 return 0;
1624error:
1625 device_printf(sc->dev, "Mbox Create EQ failed\n");
1626 return rc;
1627}
1628
1629
1630
1631int
1632oce_mbox_cq_create(struct oce_cq *cq, uint32_t ncoalesce, uint32_t is_eventable)
1633{
1634 struct oce_mbx mbx;
1635 struct mbx_create_common_cq *fwcmd;
1636 POCE_SOFTC sc = cq->parent;
1637 uint8_t version;
1638 oce_cq_ctx_t *ctx;
1639 uint32_t num_pages, page_size;
1640 int rc = 0;
1641
1642
1643 bzero(&mbx, sizeof(struct oce_mbx));
1644
1645 fwcmd = (struct mbx_create_common_cq *)&mbx.payload;
1646
1647 if (IS_XE201(sc))
1648 version = OCE_MBX_VER_V2;
1649 else
1650 version = OCE_MBX_VER_V0;
1651
1652 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0,
1653 MBX_SUBSYSTEM_COMMON,
1654 OPCODE_COMMON_CREATE_CQ,
1655 MBX_TIMEOUT_SEC,
1656 sizeof(struct mbx_create_common_cq),
1657 version);
1658
1659 ctx = &fwcmd->params.req.cq_ctx;
1660
1661 num_pages = oce_page_list(cq->ring, &fwcmd->params.req.pages[0]);
1662 page_size = 1; /* 1 for 4K */
1663
1664 if (version == OCE_MBX_VER_V2) {
1665 ctx->v2.num_pages = LE_16(num_pages);
1666 ctx->v2.page_size = page_size;
1667 ctx->v2.eventable = is_eventable;
1668 ctx->v2.valid = 1;
1669 ctx->v2.count = OCE_LOG2(cq->cq_cfg.q_len / 256);
1670 ctx->v2.nodelay = cq->cq_cfg.nodelay;
1671 ctx->v2.coalesce_wm = ncoalesce;
1672 ctx->v2.armed = 0;
1673 ctx->v2.eq_id = cq->eq->eq_id;
1674 if (ctx->v2.count == 3) {
1675 if (cq->cq_cfg.q_len > (4*1024)-1)
1676 ctx->v2.cqe_count = (4*1024)-1;
1677 else
1678 ctx->v2.cqe_count = cq->cq_cfg.q_len;
1679 }
1680 } else {
1681 ctx->v0.num_pages = LE_16(num_pages);
1682 ctx->v0.eventable = is_eventable;
1683 ctx->v0.valid = 1;
1684 ctx->v0.count = OCE_LOG2(cq->cq_cfg.q_len / 256);
1685 ctx->v0.nodelay = cq->cq_cfg.nodelay;
1686 ctx->v0.coalesce_wm = ncoalesce;
1687 ctx->v0.armed = 0;
1688 ctx->v0.eq_id = cq->eq->eq_id;
1689 }
1690
1691 mbx.u0.s.embedded = 1;
1692 mbx.payload_length = sizeof(struct mbx_create_common_cq);
1693
1694 rc = oce_mbox_post(sc, &mbx, NULL);
1695 if (rc)
1696 goto error;
1697
1698 cq->cq_id = LE_16(fwcmd->params.rsp.cq_id);
1699
1700 return 0;
1701error:
1702 device_printf(sc->dev, "Mbox Create CQ failed\n");
1703 return rc;
1704
1705}