1 /*- 2 * Copyright (C) 2013 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 /* $FreeBSD$ */ 40 41 #include "oce_if.h" 42 43 /***************************************************** 44 * local queue functions 45 *****************************************************/ 46 47 static struct oce_wq *oce_wq_init(POCE_SOFTC sc, 48 uint32_t q_len, uint32_t wq_type); 49 static int oce_wq_create(struct oce_wq *wq, struct oce_eq *eq); 50 static void oce_wq_free(struct oce_wq *wq); 51 static void oce_wq_del(struct oce_wq *wq); 52 static struct oce_rq *oce_rq_init(POCE_SOFTC sc, 53 uint32_t q_len, 54 uint32_t frag_size, 55 uint32_t mtu, uint32_t rss); 56 static int oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq); 57 static void oce_rq_free(struct oce_rq *rq); 58 static void oce_rq_del(struct oce_rq *rq); 59 static struct oce_eq *oce_eq_create(POCE_SOFTC sc, 60 uint32_t q_len, 61 uint32_t item_size, 62 uint32_t eq_delay, 63 uint32_t vector); 64 static void oce_eq_del(struct oce_eq *eq); 65 static struct oce_mq *oce_mq_create(POCE_SOFTC sc, 66 struct oce_eq *eq, uint32_t q_len); 67 static void oce_mq_free(struct oce_mq *mq); 68 static int oce_destroy_q(POCE_SOFTC sc, struct oce_mbx 69 *mbx, size_t req_size, enum qtype qtype, int version); 70 struct oce_cq *oce_cq_create(POCE_SOFTC sc, 71 struct oce_eq *eq, 72 uint32_t q_len, 73 uint32_t item_size, 74 uint32_t sol_event, 75 uint32_t is_eventable, 76 uint32_t nodelay, uint32_t ncoalesce); 77 static void oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq); 78 79 80 81 /** 82 * @brief Create and initialize all the queues on the board 83 * @param sc software handle to the device 84 * @returns 0 if successful, or error 85 **/ 86 int 87 oce_queue_init_all(POCE_SOFTC sc) 88 { 89 int rc = 0, i, vector; 90 struct oce_wq *wq; 91 struct oce_rq *rq; 92 struct oce_aic_obj *aic; 93 94 /* alloc TX/RX queues */ 95 for_all_wq_queues(sc, wq, i) { 96 sc->wq[i] = oce_wq_init(sc, sc->tx_ring_size, 97 NIC_WQ_TYPE_STANDARD); 98 if (!sc->wq[i]) 99 goto error; 100 101 } 102 103 for_all_rq_queues(sc, rq, i) { 104 sc->rq[i] = oce_rq_init(sc, sc->rx_ring_size, sc->rq_frag_size, 105 OCE_MAX_JUMBO_FRAME_SIZE, 106 (i == 0) ? 0 : is_rss_enabled(sc)); 107 if (!sc->rq[i]) 108 goto error; 109 } 110 111 /* Create network interface on card */ 112 if (oce_create_nw_interface(sc)) 113 goto error; 114 115 /* create all of the event queues */ 116 for (vector = 0; vector < sc->intr_count; vector++) { 117 /* setup aic defaults for each event queue */ 118 aic = &sc->aic_obj[vector]; 119 aic->max_eqd = OCE_MAX_EQD; 120 aic->min_eqd = OCE_MIN_EQD; 121 aic->et_eqd = OCE_MIN_EQD; 122 aic->enable = TRUE; 123 124 sc->eq[vector] = oce_eq_create(sc, sc->enable_hwlro ? EQ_LEN_2048 : EQ_LEN_1024, 125 EQE_SIZE_4,0, vector); 126 127 if (!sc->eq[vector]) 128 goto error; 129 } 130 131 /* create Tx, Rx and mcc queues */ 132 for_all_wq_queues(sc, wq, i) { 133 rc = oce_wq_create(wq, sc->eq[i]); 134 if (rc) 135 goto error; 136 wq->queue_index = i; 137 TASK_INIT(&wq->txtask, 1, oce_tx_task, wq); 138 } 139 140 for_all_rq_queues(sc, rq, i) { 141 rc = oce_rq_create(rq, sc->if_id, 142 sc->eq[(i == 0) ? 0:(i-1)]); 143 if (rc) 144 goto error; 145 rq->queue_index = i; 146 } 147 148 sc->mq = oce_mq_create(sc, sc->eq[0], 64); 149 if (!sc->mq) 150 goto error; 151 152 return rc; 153 154 error: 155 oce_queue_release_all(sc); 156 return 1; 157 } 158 159 160 161 /** 162 * @brief Releases all mailbox queues created 163 * @param sc software handle to the device 164 */ 165 void 166 oce_queue_release_all(POCE_SOFTC sc) 167 { 168 int i = 0; 169 struct oce_wq *wq; 170 struct oce_rq *rq; 171 struct oce_eq *eq; 172 173 /* before deleting lro queues, we have to disable hwlro */ 174 if(sc->enable_hwlro) 175 oce_mbox_nic_set_iface_lro_config(sc, 0); 176 177 for_all_rq_queues(sc, rq, i) { 178 if (rq) { 179 oce_rq_del(sc->rq[i]); 180 oce_rq_free(sc->rq[i]); 181 } 182 } 183 184 for_all_wq_queues(sc, wq, i) { 185 if (wq) { 186 oce_wq_del(sc->wq[i]); 187 oce_wq_free(sc->wq[i]); 188 } 189 } 190 191 if (sc->mq) 192 oce_mq_free(sc->mq); 193 194 for_all_evnt_queues(sc, eq, i) { 195 if (eq) 196 oce_eq_del(sc->eq[i]); 197 } 198 } 199 200 201 202 /** 203 * @brief Function to create a WQ for NIC Tx 204 * @param sc software handle to the device 205 * @param qlen number of entries in the queue 206 * @param wq_type work queue type 207 * @returns the pointer to the WQ created or NULL on failure 208 */ 209 static struct 210 oce_wq *oce_wq_init(POCE_SOFTC sc, uint32_t q_len, uint32_t wq_type) 211 { 212 struct oce_wq *wq; 213 int rc = 0, i; 214 215 /* q_len must be min 256 and max 2k */ 216 if (q_len < 256 || q_len > 2048) { 217 device_printf(sc->dev, 218 "Invalid q length. Must be " 219 "[256, 2000]: 0x%x\n", q_len); 220 return NULL; 221 } 222 223 /* allocate wq */ 224 wq = malloc(sizeof(struct oce_wq), M_DEVBUF, M_NOWAIT | M_ZERO); 225 if (!wq) 226 return NULL; 227 228 /* Set the wq config */ 229 wq->cfg.q_len = q_len; 230 wq->cfg.wq_type = (uint8_t) wq_type; 231 wq->cfg.eqd = OCE_DEFAULT_WQ_EQD; 232 wq->cfg.nbufs = 2 * wq->cfg.q_len; 233 wq->cfg.nhdl = 2 * wq->cfg.q_len; 234 235 wq->parent = (void *)sc; 236 237 rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 238 1, 0, 239 BUS_SPACE_MAXADDR, 240 BUS_SPACE_MAXADDR, 241 NULL, NULL, 242 OCE_MAX_TX_SIZE, 243 OCE_MAX_TX_ELEMENTS, 244 PAGE_SIZE, 0, NULL, NULL, &wq->tag); 245 246 if (rc) 247 goto free_wq; 248 249 250 for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) { 251 rc = bus_dmamap_create(wq->tag, 0, &wq->pckts[i].map); 252 if (rc) 253 goto free_wq; 254 } 255 256 wq->ring = oce_create_ring_buffer(sc, q_len, NIC_WQE_SIZE); 257 if (!wq->ring) 258 goto free_wq; 259 260 261 LOCK_CREATE(&wq->tx_lock, "TX_lock"); 262 LOCK_CREATE(&wq->tx_compl_lock, "WQ_HANDLER_LOCK"); 263 264 #if __FreeBSD_version >= 800000 265 /* Allocate buf ring for multiqueue*/ 266 wq->br = buf_ring_alloc(4096, M_DEVBUF, 267 M_WAITOK, &wq->tx_lock.mutex); 268 if (!wq->br) 269 goto free_wq; 270 #endif 271 return wq; 272 273 274 free_wq: 275 device_printf(sc->dev, "Create WQ failed\n"); 276 oce_wq_free(wq); 277 return NULL; 278 } 279 280 281 282 /** 283 * @brief Frees the work queue 284 * @param wq pointer to work queue to free 285 */ 286 static void 287 oce_wq_free(struct oce_wq *wq) 288 { 289 POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 290 int i; 291 292 taskqueue_drain(taskqueue_swi, &wq->txtask); 293 294 if (wq->ring != NULL) { 295 oce_destroy_ring_buffer(sc, wq->ring); 296 wq->ring = NULL; 297 } 298 299 for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) { 300 if (wq->pckts[i].map != NULL) { 301 bus_dmamap_unload(wq->tag, wq->pckts[i].map); 302 bus_dmamap_destroy(wq->tag, wq->pckts[i].map); 303 wq->pckts[i].map = NULL; 304 } 305 } 306 307 if (wq->tag != NULL) 308 bus_dma_tag_destroy(wq->tag); 309 if (wq->br != NULL) 310 buf_ring_free(wq->br, M_DEVBUF); 311 312 LOCK_DESTROY(&wq->tx_lock); 313 LOCK_DESTROY(&wq->tx_compl_lock); 314 free(wq, M_DEVBUF); 315 } 316 317 318 319 /** 320 * @brief Create a work queue 321 * @param wq pointer to work queue 322 * @param eq pointer to associated event queue 323 */ 324 static int 325 oce_wq_create(struct oce_wq *wq, struct oce_eq *eq) 326 { 327 POCE_SOFTC sc = wq->parent; 328 struct oce_cq *cq; 329 int rc = 0; 330 331 /* create the CQ */ 332 cq = oce_cq_create(sc, 333 eq, 334 CQ_LEN_1024, 335 sizeof(struct oce_nic_tx_cqe), 0, 1, 0, 3); 336 if (!cq) 337 return ENXIO; 338 339 340 wq->cq = cq; 341 342 rc = oce_mbox_create_wq(wq); 343 if (rc) 344 goto error; 345 346 wq->qstate = QCREATED; 347 wq->wq_free = wq->cfg.q_len; 348 wq->ring->cidx = 0; 349 wq->ring->pidx = 0; 350 351 eq->cq[eq->cq_valid] = cq; 352 eq->cq_valid++; 353 cq->cb_arg = wq; 354 cq->cq_handler = oce_wq_handler; 355 356 return 0; 357 358 error: 359 device_printf(sc->dev, "WQ create failed\n"); 360 oce_wq_del(wq); 361 return rc; 362 } 363 364 365 366 367 /** 368 * @brief Delete a work queue 369 * @param wq pointer to work queue 370 */ 371 static void 372 oce_wq_del(struct oce_wq *wq) 373 { 374 struct oce_mbx mbx; 375 struct mbx_delete_nic_wq *fwcmd; 376 POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 377 378 if (wq->qstate == QCREATED) { 379 bzero(&mbx, sizeof(struct oce_mbx)); 380 /* now fill the command */ 381 fwcmd = (struct mbx_delete_nic_wq *)&mbx.payload; 382 fwcmd->params.req.wq_id = wq->wq_id; 383 (void)oce_destroy_q(sc, &mbx, 384 sizeof(struct mbx_delete_nic_wq), QTYPE_WQ, 0); 385 wq->qstate = QDELETED; 386 } 387 388 if (wq->cq != NULL) { 389 oce_cq_del(sc, wq->cq); 390 wq->cq = NULL; 391 } 392 } 393 394 395 396 /** 397 * @brief function to allocate receive queue resources 398 * @param sc software handle to the device 399 * @param q_len length of receive queue 400 * @param frag_size size of an receive queue fragment 401 * @param mtu maximum transmission unit 402 * @param rss is-rss-queue flag 403 * @returns the pointer to the RQ created or NULL on failure 404 */ 405 static struct 406 oce_rq *oce_rq_init(POCE_SOFTC sc, 407 uint32_t q_len, 408 uint32_t frag_size, 409 uint32_t mtu, uint32_t rss) 410 { 411 struct oce_rq *rq; 412 int rc = 0, i; 413 414 if (OCE_LOG2(frag_size) <= 0) 415 return NULL; 416 417 if ((q_len == 0) || (q_len > 1024)) 418 return NULL; 419 420 /* allocate the rq */ 421 rq = malloc(sizeof(struct oce_rq), M_DEVBUF, M_NOWAIT | M_ZERO); 422 if (!rq) 423 return NULL; 424 425 426 rq->cfg.q_len = q_len; 427 rq->cfg.frag_size = frag_size; 428 rq->cfg.mtu = mtu; 429 rq->cfg.eqd = 0; 430 rq->lro_pkts_queued = 0; 431 rq->cfg.is_rss_queue = rss; 432 rq->pending = 0; 433 434 rq->parent = (void *)sc; 435 436 rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 437 1, 0, 438 BUS_SPACE_MAXADDR, 439 BUS_SPACE_MAXADDR, 440 NULL, NULL, 441 oce_rq_buf_size, 442 1, oce_rq_buf_size, 0, NULL, NULL, &rq->tag); 443 if (rc) 444 goto free_rq; 445 446 for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) { 447 rc = bus_dmamap_create(rq->tag, 0, &rq->pckts[i].map); 448 if (rc) 449 goto free_rq; 450 } 451 452 /* create the ring buffer */ 453 rq->ring = oce_create_ring_buffer(sc, q_len, 454 sizeof(struct oce_nic_rqe)); 455 if (!rq->ring) 456 goto free_rq; 457 458 LOCK_CREATE(&rq->rx_lock, "RX_lock"); 459 460 return rq; 461 462 free_rq: 463 device_printf(sc->dev, "Create RQ failed\n"); 464 oce_rq_free(rq); 465 return NULL; 466 } 467 468 469 470 471 /** 472 * @brief Free a receive queue 473 * @param rq pointer to receive queue 474 */ 475 static void 476 oce_rq_free(struct oce_rq *rq) 477 { 478 POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 479 int i = 0 ; 480 481 if (rq->ring != NULL) { 482 oce_destroy_ring_buffer(sc, rq->ring); 483 rq->ring = NULL; 484 } 485 for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) { 486 if (rq->pckts[i].map != NULL) { 487 bus_dmamap_unload(rq->tag, rq->pckts[i].map); 488 bus_dmamap_destroy(rq->tag, rq->pckts[i].map); 489 rq->pckts[i].map = NULL; 490 } 491 if (rq->pckts[i].mbuf) { 492 m_free(rq->pckts[i].mbuf); 493 rq->pckts[i].mbuf = NULL; 494 } 495 } 496 497 if (rq->tag != NULL) 498 bus_dma_tag_destroy(rq->tag); 499 500 LOCK_DESTROY(&rq->rx_lock); 501 free(rq, M_DEVBUF); 502 } 503 504 505 506 507 /** 508 * @brief Create a receive queue 509 * @param rq receive queue 510 * @param if_id interface identifier index` 511 * @param eq pointer to event queue 512 */ 513 static int 514 oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq) 515 { 516 POCE_SOFTC sc = rq->parent; 517 struct oce_cq *cq; 518 519 cq = oce_cq_create(sc, eq, 520 sc->enable_hwlro ? CQ_LEN_2048 : CQ_LEN_1024, 521 sizeof(struct oce_nic_rx_cqe), 0, 1, 0, 3); 522 523 if (!cq) 524 return ENXIO; 525 526 rq->cq = cq; 527 rq->cfg.if_id = if_id; 528 529 /* Dont create RQ here. Create in if_activate */ 530 rq->qstate = 0; 531 rq->ring->cidx = 0; 532 rq->ring->pidx = 0; 533 eq->cq[eq->cq_valid] = cq; 534 eq->cq_valid++; 535 cq->cb_arg = rq; 536 cq->cq_handler = oce_rq_handler; 537 538 return 0; 539 540 } 541 542 543 544 545 /** 546 * @brief Delete a receive queue 547 * @param rq receive queue 548 */ 549 static void 550 oce_rq_del(struct oce_rq *rq) 551 { 552 POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 553 struct oce_mbx mbx; 554 struct mbx_delete_nic_rq *fwcmd; 555 struct mbx_delete_nic_rq_v1 *fwcmd1; 556 557 if (rq->qstate == QCREATED) { 558 bzero(&mbx, sizeof(mbx)); 559 if(!rq->islro) { 560 fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload; 561 fwcmd->params.req.rq_id = rq->rq_id; 562 (void)oce_destroy_q(sc, &mbx, sizeof(struct mbx_delete_nic_rq), QTYPE_RQ, 0); 563 }else { 564 fwcmd1 = (struct mbx_delete_nic_rq_v1 *)&mbx.payload; 565 fwcmd1->params.req.rq_id = rq->rq_id; 566 fwcmd1->params.req.rq_flags = (NIC_RQ_FLAGS_RSS | NIC_RQ_FLAGS_LRO); 567 (void)oce_destroy_q(sc, &mbx, sizeof(struct mbx_delete_nic_rq_v1), QTYPE_RQ, 1); 568 } 569 rq->qstate = QDELETED; 570 } 571 572 if (rq->cq != NULL) { 573 oce_cq_del(sc, rq->cq); 574 rq->cq = NULL; 575 } 576 } 577 578 579 580 /** 581 * @brief function to create an event queue 582 * @param sc software handle to the device 583 * @param q_len length of event queue 584 * @param item_size size of an event queue item 585 * @param eq_delay event queue delay 586 * @retval eq success, pointer to event queue 587 * @retval NULL failure 588 */ 589 static struct 590 oce_eq *oce_eq_create(POCE_SOFTC sc, uint32_t q_len, 591 uint32_t item_size, 592 uint32_t eq_delay, 593 uint32_t vector) 594 { 595 struct oce_eq *eq; 596 int rc = 0; 597 598 /* allocate an eq */ 599 eq = malloc(sizeof(struct oce_eq), M_DEVBUF, M_NOWAIT | M_ZERO); 600 if (eq == NULL) 601 return NULL; 602 603 eq->parent = (void *)sc; 604 eq->eq_id = 0xffff; 605 eq->ring = oce_create_ring_buffer(sc, q_len, item_size); 606 if (!eq->ring) 607 goto free_eq; 608 609 eq->eq_cfg.q_len = q_len; 610 eq->eq_cfg.item_size = item_size; 611 eq->eq_cfg.cur_eqd = (uint8_t) eq_delay; 612 613 rc = oce_mbox_create_eq(eq); 614 if (rc) 615 goto free_eq; 616 617 sc->intrs[sc->neqs++].eq = eq; 618 619 return eq; 620 621 free_eq: 622 oce_eq_del(eq); 623 return NULL; 624 } 625 626 627 628 629 /** 630 * @brief Function to delete an event queue 631 * @param eq pointer to an event queue 632 */ 633 static void 634 oce_eq_del(struct oce_eq *eq) 635 { 636 struct oce_mbx mbx; 637 struct mbx_destroy_common_eq *fwcmd; 638 POCE_SOFTC sc = (POCE_SOFTC) eq->parent; 639 640 if (eq->eq_id != 0xffff) { 641 bzero(&mbx, sizeof(mbx)); 642 fwcmd = (struct mbx_destroy_common_eq *)&mbx.payload; 643 fwcmd->params.req.id = eq->eq_id; 644 (void)oce_destroy_q(sc, &mbx, 645 sizeof(struct mbx_destroy_common_eq), QTYPE_EQ, 0); 646 } 647 648 if (eq->ring != NULL) { 649 oce_destroy_ring_buffer(sc, eq->ring); 650 eq->ring = NULL; 651 } 652 653 free(eq, M_DEVBUF); 654 655 } 656 657 658 659 660 /** 661 * @brief Function to create an MQ 662 * @param sc software handle to the device 663 * @param eq the EQ to associate with the MQ for event notification 664 * @param q_len the number of entries to create in the MQ 665 * @returns pointer to the created MQ, failure otherwise 666 */ 667 static struct oce_mq * 668 oce_mq_create(POCE_SOFTC sc, struct oce_eq *eq, uint32_t q_len) 669 { 670 struct oce_mbx mbx; 671 struct mbx_create_common_mq_ex *fwcmd = NULL; 672 struct oce_mq *mq = NULL; 673 int rc = 0; 674 struct oce_cq *cq; 675 oce_mq_ext_ctx_t *ctx; 676 uint32_t num_pages; 677 uint32_t page_size; 678 int version; 679 680 cq = oce_cq_create(sc, eq, CQ_LEN_256, 681 sizeof(struct oce_mq_cqe), 1, 1, 0, 0); 682 if (!cq) 683 return NULL; 684 685 /* allocate the mq */ 686 mq = malloc(sizeof(struct oce_mq), M_DEVBUF, M_NOWAIT | M_ZERO); 687 if (!mq) { 688 oce_cq_del(sc, cq); 689 goto error; 690 } 691 692 mq->parent = sc; 693 694 mq->ring = oce_create_ring_buffer(sc, q_len, sizeof(struct oce_mbx)); 695 if (!mq->ring) 696 goto error; 697 698 bzero(&mbx, sizeof(struct oce_mbx)); 699 700 IS_XE201(sc) ? (version = OCE_MBX_VER_V1) : (version = OCE_MBX_VER_V0); 701 fwcmd = (struct mbx_create_common_mq_ex *)&mbx.payload; 702 mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0, 703 MBX_SUBSYSTEM_COMMON, 704 OPCODE_COMMON_CREATE_MQ_EXT, 705 MBX_TIMEOUT_SEC, 706 sizeof(struct mbx_create_common_mq_ex), 707 version); 708 709 num_pages = oce_page_list(mq->ring, &fwcmd->params.req.pages[0]); 710 page_size = mq->ring->num_items * mq->ring->item_size; 711 712 ctx = &fwcmd->params.req.context; 713 714 if (IS_XE201(sc)) { 715 ctx->v1.num_pages = num_pages; 716 ctx->v1.ring_size = OCE_LOG2(q_len) + 1; 717 ctx->v1.cq_id = cq->cq_id; 718 ctx->v1.valid = 1; 719 ctx->v1.async_cq_id = cq->cq_id; 720 ctx->v1.async_cq_valid = 1; 721 /* Subscribe to Link State and Group 5 Events(bits 1 & 5 set) */ 722 ctx->v1.async_evt_bitmap |= LE_32(0x00000022); 723 ctx->v1.async_evt_bitmap |= LE_32(1 << ASYNC_EVENT_CODE_DEBUG); 724 ctx->v1.async_evt_bitmap |= 725 LE_32(1 << ASYNC_EVENT_CODE_SLIPORT); 726 } 727 else { 728 ctx->v0.num_pages = num_pages; 729 ctx->v0.cq_id = cq->cq_id; 730 ctx->v0.ring_size = OCE_LOG2(q_len) + 1; 731 ctx->v0.valid = 1; 732 /* Subscribe to Link State and Group5 Events(bits 1 & 5 set) */ 733 ctx->v0.async_evt_bitmap = 0xffffffff; 734 } 735 736 mbx.u0.s.embedded = 1; 737 mbx.payload_length = sizeof(struct mbx_create_common_mq_ex); 738 DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ); 739 740 rc = oce_mbox_post(sc, &mbx, NULL); 741 if (!rc) 742 rc = fwcmd->hdr.u0.rsp.status; 743 if (rc) { 744 device_printf(sc->dev,"%s failed - cmd status: %d\n", 745 __FUNCTION__, rc); 746 goto error; 747 } 748 mq->mq_id = LE_16(fwcmd->params.rsp.mq_id); 749 mq->cq = cq; 750 eq->cq[eq->cq_valid] = cq; 751 eq->cq_valid++; 752 mq->cq->eq = eq; 753 mq->cfg.q_len = (uint8_t) q_len; 754 mq->cfg.eqd = 0; 755 mq->qstate = QCREATED; 756 757 mq->cq->cb_arg = mq; 758 mq->cq->cq_handler = oce_mq_handler; 759 760 return mq; 761 762 error: 763 device_printf(sc->dev, "MQ create failed\n"); 764 oce_mq_free(mq); 765 mq = NULL; 766 return mq; 767 } 768 769 770 771 772 773 /** 774 * @brief Function to free a mailbox queue 775 * @param mq pointer to a mailbox queue 776 */ 777 static void 778 oce_mq_free(struct oce_mq *mq) 779 { 780 POCE_SOFTC sc = (POCE_SOFTC) mq->parent; 781 struct oce_mbx mbx; 782 struct mbx_destroy_common_mq *fwcmd; 783 784 if (!mq) 785 return; 786 787 if (mq->ring != NULL) { 788 oce_destroy_ring_buffer(sc, mq->ring); 789 mq->ring = NULL; 790 if (mq->qstate == QCREATED) { 791 bzero(&mbx, sizeof (struct oce_mbx)); 792 fwcmd = (struct mbx_destroy_common_mq *)&mbx.payload; 793 fwcmd->params.req.id = mq->mq_id; 794 (void) oce_destroy_q(sc, &mbx, 795 sizeof (struct mbx_destroy_common_mq), 796 QTYPE_MQ, 0); 797 } 798 mq->qstate = QDELETED; 799 } 800 801 if (mq->cq != NULL) { 802 oce_cq_del(sc, mq->cq); 803 mq->cq = NULL; 804 } 805 806 free(mq, M_DEVBUF); 807 mq = NULL; 808 } 809 810 811 812 /** 813 * @brief Function to delete a EQ, CQ, MQ, WQ or RQ 814 * @param sc sofware handle to the device 815 * @param mbx mailbox command to send to the fw to delete the queue 816 * (mbx contains the queue information to delete) 817 * @param req_size the size of the mbx payload dependent on the qtype 818 * @param qtype the type of queue i.e. EQ, CQ, MQ, WQ or RQ 819 * @returns 0 on success, failure otherwise 820 */ 821 static int 822 oce_destroy_q(POCE_SOFTC sc, struct oce_mbx *mbx, size_t req_size, 823 enum qtype qtype, int version) 824 { 825 struct mbx_hdr *hdr = (struct mbx_hdr *)&mbx->payload; 826 int opcode; 827 int subsys; 828 int rc = 0; 829 830 switch (qtype) { 831 case QTYPE_EQ: 832 opcode = OPCODE_COMMON_DESTROY_EQ; 833 subsys = MBX_SUBSYSTEM_COMMON; 834 break; 835 case QTYPE_CQ: 836 opcode = OPCODE_COMMON_DESTROY_CQ; 837 subsys = MBX_SUBSYSTEM_COMMON; 838 break; 839 case QTYPE_MQ: 840 opcode = OPCODE_COMMON_DESTROY_MQ; 841 subsys = MBX_SUBSYSTEM_COMMON; 842 break; 843 case QTYPE_WQ: 844 opcode = NIC_DELETE_WQ; 845 subsys = MBX_SUBSYSTEM_NIC; 846 break; 847 case QTYPE_RQ: 848 opcode = NIC_DELETE_RQ; 849 subsys = MBX_SUBSYSTEM_NIC; 850 break; 851 default: 852 return EINVAL; 853 } 854 855 mbx_common_req_hdr_init(hdr, 0, 0, subsys, 856 opcode, MBX_TIMEOUT_SEC, req_size, 857 version); 858 859 mbx->u0.s.embedded = 1; 860 mbx->payload_length = (uint32_t) req_size; 861 DW_SWAP(u32ptr(mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ); 862 863 rc = oce_mbox_post(sc, mbx, NULL); 864 if (!rc) 865 rc = hdr->u0.rsp.status; 866 if (rc) 867 device_printf(sc->dev,"%s failed - cmd status: %d\n", 868 __FUNCTION__, rc); 869 return rc; 870 } 871 872 873 874 /** 875 * @brief Function to create a completion queue 876 * @param sc software handle to the device 877 * @param eq optional eq to be associated with to the cq 878 * @param q_len length of completion queue 879 * @param item_size size of completion queue items 880 * @param sol_event command context event 881 * @param is_eventable event table 882 * @param nodelay no delay flag 883 * @param ncoalesce no coalescence flag 884 * @returns pointer to the cq created, NULL on failure 885 */ 886 struct oce_cq * 887 oce_cq_create(POCE_SOFTC sc, struct oce_eq *eq, 888 uint32_t q_len, 889 uint32_t item_size, 890 uint32_t sol_event, 891 uint32_t is_eventable, 892 uint32_t nodelay, uint32_t ncoalesce) 893 { 894 struct oce_cq *cq = NULL; 895 int rc = 0; 896 897 cq = malloc(sizeof(struct oce_cq), M_DEVBUF, M_NOWAIT | M_ZERO); 898 if (!cq) 899 return NULL; 900 901 cq->ring = oce_create_ring_buffer(sc, q_len, item_size); 902 if (!cq->ring) 903 goto error; 904 905 cq->parent = sc; 906 cq->eq = eq; 907 cq->cq_cfg.q_len = q_len; 908 cq->cq_cfg.item_size = item_size; 909 cq->cq_cfg.nodelay = (uint8_t) nodelay; 910 911 rc = oce_mbox_cq_create(cq, ncoalesce, is_eventable); 912 if (rc) 913 goto error; 914 915 sc->cq[sc->ncqs++] = cq; 916 917 return cq; 918 919 error: 920 device_printf(sc->dev, "CQ create failed\n"); 921 oce_cq_del(sc, cq); 922 return NULL; 923 } 924 925 926 927 /** 928 * @brief Deletes the completion queue 929 * @param sc software handle to the device 930 * @param cq pointer to a completion queue 931 */ 932 static void 933 oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq) 934 { 935 struct oce_mbx mbx; 936 struct mbx_destroy_common_cq *fwcmd; 937 938 if (cq->ring != NULL) { 939 940 bzero(&mbx, sizeof(struct oce_mbx)); 941 /* now fill the command */ 942 fwcmd = (struct mbx_destroy_common_cq *)&mbx.payload; 943 fwcmd->params.req.id = cq->cq_id; 944 (void)oce_destroy_q(sc, &mbx, 945 sizeof(struct mbx_destroy_common_cq), QTYPE_CQ, 0); 946 /*NOW destroy the ring */ 947 oce_destroy_ring_buffer(sc, cq->ring); 948 cq->ring = NULL; 949 } 950 951 free(cq, M_DEVBUF); 952 cq = NULL; 953 } 954 955 956 957 /** 958 * @brief Start a receive queue 959 * @param rq pointer to a receive queue 960 */ 961 int 962 oce_start_rq(struct oce_rq *rq) 963 { 964 POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 965 int rc; 966 967 if(sc->enable_hwlro) 968 rc = oce_alloc_rx_bufs(rq, 960); 969 else 970 rc = oce_alloc_rx_bufs(rq, rq->cfg.q_len - 1); 971 972 if (rc == 0) 973 oce_arm_cq(rq->parent, rq->cq->cq_id, 0, TRUE); 974 975 return rc; 976 } 977 978 979 980 /** 981 * @brief Start a work queue 982 * @param wq pointer to a work queue 983 */ 984 int 985 oce_start_wq(struct oce_wq *wq) 986 { 987 oce_arm_cq(wq->parent, wq->cq->cq_id, 0, TRUE); 988 return 0; 989 } 990 991 992 993 /** 994 * @brief Start a mailbox queue 995 * @param mq pointer to a mailbox queue 996 */ 997 int 998 oce_start_mq(struct oce_mq *mq) 999 { 1000 oce_arm_cq(mq->parent, mq->cq->cq_id, 0, TRUE); 1001 return 0; 1002 } 1003 1004 1005 1006 /** 1007 * @brief Function to arm an EQ so that it can generate events 1008 * @param sc software handle to the device 1009 * @param qid id of the EQ returned by the fw at the time of creation 1010 * @param npopped number of EQEs to arm 1011 * @param rearm rearm bit enable/disable 1012 * @param clearint bit to clear the interrupt condition because of which 1013 * EQEs are generated 1014 */ 1015 void 1016 oce_arm_eq(POCE_SOFTC sc, 1017 int16_t qid, int npopped, uint32_t rearm, uint32_t clearint) 1018 { 1019 eq_db_t eq_db = { 0 }; 1020 1021 eq_db.bits.rearm = rearm; 1022 eq_db.bits.event = 1; 1023 eq_db.bits.num_popped = npopped; 1024 eq_db.bits.clrint = clearint; 1025 eq_db.bits.qid = qid; 1026 OCE_WRITE_REG32(sc, db, PD_EQ_DB, eq_db.dw0); 1027 1028 } 1029 1030 1031 1032 1033 /** 1034 * @brief Function to arm a CQ with CQEs 1035 * @param sc software handle to the device 1036 * @param qid id of the CQ returned by the fw at the time of creation 1037 * @param npopped number of CQEs to arm 1038 * @param rearm rearm bit enable/disable 1039 */ 1040 void oce_arm_cq(POCE_SOFTC sc, int16_t qid, int npopped, uint32_t rearm) 1041 { 1042 cq_db_t cq_db = { 0 }; 1043 1044 cq_db.bits.rearm = rearm; 1045 cq_db.bits.num_popped = npopped; 1046 cq_db.bits.event = 0; 1047 cq_db.bits.qid = qid; 1048 OCE_WRITE_REG32(sc, db, PD_CQ_DB, cq_db.dw0); 1049 1050 } 1051 1052 1053 1054 1055 /* 1056 * @brief function to cleanup the eqs used during stop 1057 * @param eq pointer to event queue structure 1058 * @returns the number of EQs processed 1059 */ 1060 void 1061 oce_drain_eq(struct oce_eq *eq) 1062 { 1063 1064 struct oce_eqe *eqe; 1065 uint16_t num_eqe = 0; 1066 POCE_SOFTC sc = eq->parent; 1067 1068 do { 1069 eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 1070 if (eqe->evnt == 0) 1071 break; 1072 eqe->evnt = 0; 1073 bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 1074 BUS_DMASYNC_POSTWRITE); 1075 num_eqe++; 1076 RING_GET(eq->ring, 1); 1077 1078 } while (TRUE); 1079 1080 oce_arm_eq(sc, eq->eq_id, num_eqe, FALSE, TRUE); 1081 1082 } 1083 1084 1085 1086 void 1087 oce_drain_wq_cq(struct oce_wq *wq) 1088 { 1089 POCE_SOFTC sc = wq->parent; 1090 struct oce_cq *cq = wq->cq; 1091 struct oce_nic_tx_cqe *cqe; 1092 int num_cqes = 0; 1093 1094 bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, 1095 BUS_DMASYNC_POSTWRITE); 1096 1097 do { 1098 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1099 if (cqe->u0.dw[3] == 0) 1100 break; 1101 cqe->u0.dw[3] = 0; 1102 bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, 1103 BUS_DMASYNC_POSTWRITE); 1104 RING_GET(cq->ring, 1); 1105 num_cqes++; 1106 1107 } while (TRUE); 1108 1109 oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1110 1111 } 1112 1113 1114 /* 1115 * @brief function to drain a MCQ and process its CQEs 1116 * @param dev software handle to the device 1117 * @param cq pointer to the cq to drain 1118 * @returns the number of CQEs processed 1119 */ 1120 void 1121 oce_drain_mq_cq(void *arg) 1122 { 1123 /* TODO: additional code. */ 1124 return; 1125 } 1126 1127 1128 1129 /** 1130 * @brief function to process a Recieve queue 1131 * @param arg pointer to the RQ to charge 1132 * @return number of cqes processed 1133 */ 1134 void 1135 oce_drain_rq_cq(struct oce_rq *rq) 1136 { 1137 struct oce_nic_rx_cqe *cqe; 1138 uint16_t num_cqe = 0; 1139 struct oce_cq *cq; 1140 POCE_SOFTC sc; 1141 1142 sc = rq->parent; 1143 cq = rq->cq; 1144 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1145 /* dequeue till you reach an invalid cqe */ 1146 while (RQ_CQE_VALID(cqe)) { 1147 RQ_CQE_INVALIDATE(cqe); 1148 RING_GET(cq->ring, 1); 1149 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, 1150 struct oce_nic_rx_cqe); 1151 num_cqe++; 1152 } 1153 oce_arm_cq(sc, cq->cq_id, num_cqe, FALSE); 1154 1155 return; 1156 } 1157 1158 1159 void 1160 oce_free_posted_rxbuf(struct oce_rq *rq) 1161 { 1162 struct oce_packet_desc *pd; 1163 1164 while (rq->pending) { 1165 1166 pd = &rq->pckts[rq->ring->cidx]; 1167 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1168 bus_dmamap_unload(rq->tag, pd->map); 1169 if (pd->mbuf != NULL) { 1170 m_freem(pd->mbuf); 1171 pd->mbuf = NULL; 1172 } 1173 1174 RING_GET(rq->ring,1); 1175 rq->pending--; 1176 } 1177 1178 } 1179 1180 void 1181 oce_rx_cq_clean_hwlro(struct oce_rq *rq) 1182 { 1183 struct oce_cq *cq = rq->cq; 1184 POCE_SOFTC sc = rq->parent; 1185 struct nic_hwlro_singleton_cqe *cqe; 1186 struct nic_hwlro_cqe_part2 *cqe2; 1187 int flush_wait = 0; 1188 int flush_compl = 0; 1189 int num_frags = 0; 1190 1191 for (;;) { 1192 bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1193 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 1194 if(cqe->valid) { 1195 if(cqe->cqe_type == 0) { /* singleton cqe */ 1196 /* we should not get singleton cqe after cqe1 on same rq */ 1197 if(rq->cqe_firstpart != NULL) { 1198 device_printf(sc->dev, "Got singleton cqe after cqe1 \n"); 1199 goto exit_rx_cq_clean_hwlro; 1200 } 1201 num_frags = cqe->pkt_size / rq->cfg.frag_size; 1202 if(cqe->pkt_size % rq->cfg.frag_size) 1203 num_frags++; 1204 oce_discard_rx_comp(rq, num_frags); 1205 /* Check if CQE is flush completion */ 1206 if(!cqe->pkt_size) 1207 flush_compl = 1; 1208 cqe->valid = 0; 1209 RING_GET(cq->ring, 1); 1210 }else if(cqe->cqe_type == 0x1) { /* first part */ 1211 /* we should not get cqe1 after cqe1 on same rq */ 1212 if(rq->cqe_firstpart != NULL) { 1213 device_printf(sc->dev, "Got cqe1 after cqe1 \n"); 1214 goto exit_rx_cq_clean_hwlro; 1215 } 1216 rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe; 1217 RING_GET(cq->ring, 1); 1218 }else if(cqe->cqe_type == 0x2) { /* second part */ 1219 cqe2 = (struct nic_hwlro_cqe_part2 *)cqe; 1220 /* We should not get cqe2 without cqe1 */ 1221 if(rq->cqe_firstpart == NULL) { 1222 device_printf(sc->dev, "Got cqe2 without cqe1 \n"); 1223 goto exit_rx_cq_clean_hwlro; 1224 } 1225 num_frags = cqe2->coalesced_size / rq->cfg.frag_size; 1226 if(cqe2->coalesced_size % rq->cfg.frag_size) 1227 num_frags++; 1228 1229 /* Flush completion will always come in singleton CQE */ 1230 oce_discard_rx_comp(rq, num_frags); 1231 1232 rq->cqe_firstpart->valid = 0; 1233 cqe2->valid = 0; 1234 rq->cqe_firstpart = NULL; 1235 RING_GET(cq->ring, 1); 1236 } 1237 oce_arm_cq(sc, cq->cq_id, 1, FALSE); 1238 if(flush_compl) 1239 break; 1240 }else { 1241 if (flush_wait++ > 100) { 1242 device_printf(sc->dev, "did not receive hwlro flush compl\n"); 1243 break; 1244 } 1245 oce_arm_cq(sc, cq->cq_id, 0, TRUE); 1246 DELAY(1000); 1247 } 1248 } 1249 1250 /* After cleanup, leave the CQ in unarmed state */ 1251 oce_arm_cq(sc, cq->cq_id, 0, FALSE); 1252 1253 exit_rx_cq_clean_hwlro: 1254 return; 1255 } 1256 1257 1258 void 1259 oce_rx_cq_clean(struct oce_rq *rq) 1260 { 1261 struct oce_nic_rx_cqe *cqe; 1262 struct oce_cq *cq; 1263 POCE_SOFTC sc; 1264 int flush_wait = 0; 1265 int flush_compl = 0; 1266 sc = rq->parent; 1267 cq = rq->cq; 1268 1269 for (;;) { 1270 bus_dmamap_sync(cq->ring->dma.tag, 1271 cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1272 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1273 if(RQ_CQE_VALID(cqe)) { 1274 DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1275 oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1276 /* Check if CQE is flush completion */ 1277 if((cqe->u0.s.num_fragments==0)&&(cqe->u0.s.pkt_size == 0)&&(cqe->u0.s.error == 0)) 1278 flush_compl = 1; 1279 1280 RQ_CQE_INVALIDATE(cqe); 1281 RING_GET(cq->ring, 1); 1282 #if defined(INET6) || defined(INET) 1283 if (IF_LRO_ENABLED(sc)) 1284 oce_rx_flush_lro(rq); 1285 #endif 1286 oce_arm_cq(sc, cq->cq_id, 1, FALSE); 1287 if(flush_compl) 1288 break; 1289 }else { 1290 if (flush_wait++ > 100) { 1291 device_printf(sc->dev, "did not receive flush compl\n"); 1292 break; 1293 } 1294 oce_arm_cq(sc, cq->cq_id, 0, TRUE); 1295 DELAY(1000); 1296 } 1297 } 1298 1299 /* After cleanup, leave the CQ in unarmed state */ 1300 oce_arm_cq(sc, cq->cq_id, 0, FALSE); 1301 } 1302 1303 void 1304 oce_stop_rx(POCE_SOFTC sc) 1305 { 1306 struct oce_mbx mbx; 1307 struct mbx_delete_nic_rq *fwcmd; 1308 struct mbx_delete_nic_rq_v1 *fwcmd1; 1309 struct oce_rq *rq; 1310 int i = 0; 1311 1312 /* before deleting disable hwlro */ 1313 if(sc->enable_hwlro) 1314 oce_mbox_nic_set_iface_lro_config(sc, 0); 1315 1316 for_all_rq_queues(sc, rq, i) { 1317 if (rq->qstate == QCREATED) { 1318 /* Delete rxq in firmware */ 1319 LOCK(&rq->rx_lock); 1320 1321 bzero(&mbx, sizeof(mbx)); 1322 if(!rq->islro) { 1323 fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload; 1324 fwcmd->params.req.rq_id = rq->rq_id; 1325 (void)oce_destroy_q(sc, &mbx, sizeof(struct mbx_delete_nic_rq), QTYPE_RQ, 0); 1326 }else { 1327 fwcmd1 = (struct mbx_delete_nic_rq_v1 *)&mbx.payload; 1328 fwcmd1->params.req.rq_id = rq->rq_id; 1329 fwcmd1->params.req.rq_flags = (NIC_RQ_FLAGS_RSS | NIC_RQ_FLAGS_LRO); 1330 1331 (void)oce_destroy_q(sc,&mbx,sizeof(struct mbx_delete_nic_rq_v1),QTYPE_RQ,1); 1332 } 1333 rq->qstate = QDELETED; 1334 1335 DELAY(1000); 1336 1337 if(!rq->islro) 1338 oce_rx_cq_clean(rq); 1339 else 1340 oce_rx_cq_clean_hwlro(rq); 1341 1342 /* Free posted RX buffers that are not used */ 1343 oce_free_posted_rxbuf(rq); 1344 UNLOCK(&rq->rx_lock); 1345 } 1346 } 1347 } 1348 1349 1350 1351 int 1352 oce_start_rx(POCE_SOFTC sc) 1353 { 1354 struct oce_rq *rq; 1355 int rc = 0, i; 1356 1357 for_all_rq_queues(sc, rq, i) { 1358 if (rq->qstate == QCREATED) 1359 continue; 1360 if((i == 0) || (!sc->enable_hwlro)) { 1361 rc = oce_mbox_create_rq(rq); 1362 if (rc) 1363 goto error; 1364 rq->islro = 0; 1365 }else { 1366 rc = oce_mbox_create_rq_v2(rq); 1367 if (rc) 1368 goto error; 1369 rq->islro = 1; 1370 } 1371 /* reset queue pointers */ 1372 rq->qstate = QCREATED; 1373 rq->pending = 0; 1374 rq->ring->cidx = 0; 1375 rq->ring->pidx = 0; 1376 } 1377 1378 if(sc->enable_hwlro) { 1379 rc = oce_mbox_nic_set_iface_lro_config(sc, 1); 1380 if (rc) 1381 goto error; 1382 } 1383 1384 DELAY(1); 1385 1386 /* RSS config */ 1387 if (is_rss_enabled(sc)) { 1388 rc = oce_config_nic_rss(sc, (uint8_t) sc->if_id, RSS_ENABLE); 1389 if (rc) 1390 goto error; 1391 1392 } 1393 1394 DELAY(1); 1395 return rc; 1396 error: 1397 device_printf(sc->dev, "Start RX failed\n"); 1398 return rc; 1399 1400 } 1401 1402 1403 1404