1231437Sluigi/*- 2252869Sdelphij * Copyright (C) 2013 Emulex 3231437Sluigi * All rights reserved. 4231437Sluigi * 5231437Sluigi * Redistribution and use in source and binary forms, with or without 6231437Sluigi * modification, are permitted provided that the following conditions are met: 7231437Sluigi * 8231437Sluigi * 1. Redistributions of source code must retain the above copyright notice, 9231437Sluigi * this list of conditions and the following disclaimer. 10231437Sluigi * 11231437Sluigi * 2. Redistributions in binary form must reproduce the above copyright 12231437Sluigi * notice, this list of conditions and the following disclaimer in the 13231437Sluigi * documentation and/or other materials provided with the distribution. 14231437Sluigi * 15231437Sluigi * 3. Neither the name of the Emulex Corporation nor the names of its 16231437Sluigi * contributors may be used to endorse or promote products derived from 17231437Sluigi * this software without specific prior written permission. 18231437Sluigi * 19231437Sluigi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20231437Sluigi * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21231437Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22231437Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23231437Sluigi * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24231437Sluigi * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25231437Sluigi * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26231437Sluigi * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27231437Sluigi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28231437Sluigi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29231437Sluigi * POSSIBILITY OF SUCH DAMAGE. 30231437Sluigi * 31231437Sluigi * Contact Information: 32231437Sluigi * freebsd-drivers@emulex.com 33231437Sluigi * 34231437Sluigi * Emulex 35231437Sluigi * 3333 Susan Street 36231437Sluigi * Costa Mesa, CA 92626 37231437Sluigi */ 38231437Sluigi 39231437Sluigi/* $FreeBSD$ */ 40231437Sluigi 41231437Sluigi#include "oce_if.h" 42231437Sluigi 43231437Sluigi/***************************************************** 44231437Sluigi * local queue functions 45231437Sluigi *****************************************************/ 46231437Sluigi 47231437Sluigistatic struct oce_wq *oce_wq_init(POCE_SOFTC sc, 48231437Sluigi uint32_t q_len, uint32_t wq_type); 49231437Sluigistatic int oce_wq_create(struct oce_wq *wq, struct oce_eq *eq); 50231437Sluigistatic void oce_wq_free(struct oce_wq *wq); 51231437Sluigistatic void oce_wq_del(struct oce_wq *wq); 52231437Sluigistatic struct oce_rq *oce_rq_init(POCE_SOFTC sc, 53231437Sluigi uint32_t q_len, 54231437Sluigi uint32_t frag_size, 55231437Sluigi uint32_t mtu, uint32_t rss); 56231437Sluigistatic int oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq); 57231437Sluigistatic void oce_rq_free(struct oce_rq *rq); 58231437Sluigistatic void oce_rq_del(struct oce_rq *rq); 59231437Sluigistatic struct oce_eq *oce_eq_create(POCE_SOFTC sc, 60231437Sluigi uint32_t q_len, 61231437Sluigi uint32_t item_size, 62231437Sluigi uint32_t eq_delay, 63231437Sluigi uint32_t vector); 64231437Sluigistatic void oce_eq_del(struct oce_eq *eq); 65231437Sluigistatic struct oce_mq *oce_mq_create(POCE_SOFTC sc, 66231437Sluigi struct oce_eq *eq, uint32_t q_len); 67231437Sluigistatic void oce_mq_free(struct oce_mq *mq); 68231437Sluigistatic int oce_destroy_q(POCE_SOFTC sc, struct oce_mbx 69231437Sluigi *mbx, size_t req_size, enum qtype qtype); 70231437Sluigistruct oce_cq *oce_cq_create(POCE_SOFTC sc, 71231437Sluigi struct oce_eq *eq, 72231437Sluigi uint32_t q_len, 73231437Sluigi uint32_t item_size, 74231437Sluigi uint32_t sol_event, 75231437Sluigi uint32_t is_eventable, 76231437Sluigi uint32_t nodelay, uint32_t ncoalesce); 77231437Sluigistatic void oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq); 78231437Sluigi 79231437Sluigi 80231437Sluigi 81231437Sluigi/** 82231437Sluigi * @brief Create and initialize all the queues on the board 83231437Sluigi * @param sc software handle to the device 84231437Sluigi * @returns 0 if successful, or error 85231437Sluigi **/ 86231437Sluigiint 87231437Sluigioce_queue_init_all(POCE_SOFTC sc) 88231437Sluigi{ 89231437Sluigi int rc = 0, i, vector; 90231437Sluigi struct oce_wq *wq; 91231437Sluigi struct oce_rq *rq; 92247880Sdelphij struct oce_aic_obj *aic; 93231437Sluigi 94231437Sluigi /* alloc TX/RX queues */ 95231437Sluigi for_all_wq_queues(sc, wq, i) { 96231437Sluigi sc->wq[i] = oce_wq_init(sc, sc->tx_ring_size, 97231437Sluigi NIC_WQ_TYPE_STANDARD); 98231437Sluigi if (!sc->wq[i]) 99231437Sluigi goto error; 100231437Sluigi 101231437Sluigi } 102231437Sluigi 103231437Sluigi for_all_rq_queues(sc, rq, i) { 104231437Sluigi sc->rq[i] = oce_rq_init(sc, sc->rx_ring_size, sc->rq_frag_size, 105231437Sluigi OCE_MAX_JUMBO_FRAME_SIZE, 106252869Sdelphij (i == 0) ? 0 : is_rss_enabled(sc)); 107231437Sluigi if (!sc->rq[i]) 108231437Sluigi goto error; 109231437Sluigi } 110231437Sluigi 111231437Sluigi /* Create network interface on card */ 112231437Sluigi if (oce_create_nw_interface(sc)) 113231437Sluigi goto error; 114231437Sluigi 115231437Sluigi /* create all of the event queues */ 116231437Sluigi for (vector = 0; vector < sc->intr_count; vector++) { 117247880Sdelphij /* setup aic defaults for each event queue */ 118247880Sdelphij aic = &sc->aic_obj[vector]; 119247880Sdelphij aic->max_eqd = OCE_MAX_EQD; 120247880Sdelphij aic->min_eqd = OCE_MIN_EQD; 121247880Sdelphij aic->et_eqd = OCE_MIN_EQD; 122247880Sdelphij aic->enable = TRUE; 123247880Sdelphij 124231437Sluigi sc->eq[vector] = oce_eq_create(sc, EQ_LEN_1024, EQE_SIZE_4, 125231437Sluigi 0, vector); 126231437Sluigi if (!sc->eq[vector]) 127231437Sluigi goto error; 128231437Sluigi } 129231437Sluigi 130231437Sluigi /* create Tx, Rx and mcc queues */ 131231437Sluigi for_all_wq_queues(sc, wq, i) { 132231437Sluigi rc = oce_wq_create(wq, sc->eq[i]); 133231437Sluigi if (rc) 134231437Sluigi goto error; 135231437Sluigi wq->queue_index = i; 136231437Sluigi TASK_INIT(&wq->txtask, 1, oce_tx_task, wq); 137231437Sluigi } 138231437Sluigi 139231437Sluigi for_all_rq_queues(sc, rq, i) { 140231437Sluigi rc = oce_rq_create(rq, sc->if_id, 141231437Sluigi sc->eq[(i == 0) ? 0:(i-1)]); 142231437Sluigi if (rc) 143231437Sluigi goto error; 144231437Sluigi rq->queue_index = i; 145231437Sluigi } 146231437Sluigi 147231437Sluigi sc->mq = oce_mq_create(sc, sc->eq[0], 64); 148231437Sluigi if (!sc->mq) 149231437Sluigi goto error; 150231437Sluigi 151231437Sluigi return rc; 152231437Sluigi 153231437Sluigierror: 154231437Sluigi oce_queue_release_all(sc); 155231437Sluigi return 1; 156231437Sluigi} 157231437Sluigi 158231437Sluigi 159231437Sluigi 160231437Sluigi/** 161231437Sluigi * @brief Releases all mailbox queues created 162231437Sluigi * @param sc software handle to the device 163231437Sluigi */ 164231437Sluigivoid 165231437Sluigioce_queue_release_all(POCE_SOFTC sc) 166231437Sluigi{ 167231437Sluigi int i = 0; 168231437Sluigi struct oce_wq *wq; 169231437Sluigi struct oce_rq *rq; 170231437Sluigi struct oce_eq *eq; 171231437Sluigi 172231437Sluigi for_all_rq_queues(sc, rq, i) { 173231437Sluigi if (rq) { 174231437Sluigi oce_rq_del(sc->rq[i]); 175231437Sluigi oce_rq_free(sc->rq[i]); 176231437Sluigi } 177231437Sluigi } 178231437Sluigi 179231437Sluigi for_all_wq_queues(sc, wq, i) { 180231437Sluigi if (wq) { 181231437Sluigi oce_wq_del(sc->wq[i]); 182231437Sluigi oce_wq_free(sc->wq[i]); 183231437Sluigi } 184231437Sluigi } 185231437Sluigi 186231437Sluigi if (sc->mq) 187231437Sluigi oce_mq_free(sc->mq); 188231437Sluigi 189231437Sluigi for_all_evnt_queues(sc, eq, i) { 190231437Sluigi if (eq) 191231437Sluigi oce_eq_del(sc->eq[i]); 192231437Sluigi } 193231437Sluigi} 194231437Sluigi 195231437Sluigi 196231437Sluigi 197231437Sluigi/** 198231437Sluigi * @brief Function to create a WQ for NIC Tx 199231437Sluigi * @param sc software handle to the device 200231437Sluigi * @param qlen number of entries in the queue 201231437Sluigi * @param wq_type work queue type 202231437Sluigi * @returns the pointer to the WQ created or NULL on failure 203231437Sluigi */ 204231437Sluigistatic struct 205231437Sluigioce_wq *oce_wq_init(POCE_SOFTC sc, uint32_t q_len, uint32_t wq_type) 206231437Sluigi{ 207231437Sluigi struct oce_wq *wq; 208231437Sluigi int rc = 0, i; 209231437Sluigi 210231437Sluigi /* q_len must be min 256 and max 2k */ 211231437Sluigi if (q_len < 256 || q_len > 2048) { 212231437Sluigi device_printf(sc->dev, 213231437Sluigi "Invalid q length. Must be " 214231437Sluigi "[256, 2000]: 0x%x\n", q_len); 215231437Sluigi return NULL; 216231437Sluigi } 217231437Sluigi 218231437Sluigi /* allocate wq */ 219231437Sluigi wq = malloc(sizeof(struct oce_wq), M_DEVBUF, M_NOWAIT | M_ZERO); 220231437Sluigi if (!wq) 221231437Sluigi return NULL; 222231437Sluigi 223231437Sluigi /* Set the wq config */ 224231437Sluigi wq->cfg.q_len = q_len; 225231437Sluigi wq->cfg.wq_type = (uint8_t) wq_type; 226231437Sluigi wq->cfg.eqd = OCE_DEFAULT_WQ_EQD; 227231437Sluigi wq->cfg.nbufs = 2 * wq->cfg.q_len; 228231437Sluigi wq->cfg.nhdl = 2 * wq->cfg.q_len; 229231437Sluigi 230231437Sluigi wq->parent = (void *)sc; 231231437Sluigi 232231437Sluigi rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 233231437Sluigi 1, 0, 234231437Sluigi BUS_SPACE_MAXADDR, 235231437Sluigi BUS_SPACE_MAXADDR, 236231437Sluigi NULL, NULL, 237231437Sluigi OCE_MAX_TX_SIZE, 238231437Sluigi OCE_MAX_TX_ELEMENTS, 239231437Sluigi PAGE_SIZE, 0, NULL, NULL, &wq->tag); 240231437Sluigi 241231437Sluigi if (rc) 242231437Sluigi goto free_wq; 243231437Sluigi 244231437Sluigi 245231437Sluigi for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) { 246231437Sluigi rc = bus_dmamap_create(wq->tag, 0, &wq->pckts[i].map); 247231437Sluigi if (rc) 248231437Sluigi goto free_wq; 249231437Sluigi } 250231437Sluigi 251231437Sluigi wq->ring = oce_create_ring_buffer(sc, q_len, NIC_WQE_SIZE); 252231437Sluigi if (!wq->ring) 253231437Sluigi goto free_wq; 254231437Sluigi 255231437Sluigi 256231437Sluigi LOCK_CREATE(&wq->tx_lock, "TX_lock"); 257231437Sluigi 258231437Sluigi#if __FreeBSD_version >= 800000 259231437Sluigi /* Allocate buf ring for multiqueue*/ 260231437Sluigi wq->br = buf_ring_alloc(4096, M_DEVBUF, 261231437Sluigi M_WAITOK, &wq->tx_lock.mutex); 262231437Sluigi if (!wq->br) 263231437Sluigi goto free_wq; 264231437Sluigi#endif 265231437Sluigi return wq; 266231437Sluigi 267231437Sluigi 268231437Sluigifree_wq: 269231437Sluigi device_printf(sc->dev, "Create WQ failed\n"); 270231437Sluigi oce_wq_free(wq); 271231437Sluigi return NULL; 272231437Sluigi} 273231437Sluigi 274231437Sluigi 275231437Sluigi 276231437Sluigi/** 277231437Sluigi * @brief Frees the work queue 278231437Sluigi * @param wq pointer to work queue to free 279231437Sluigi */ 280231437Sluigistatic void 281231437Sluigioce_wq_free(struct oce_wq *wq) 282231437Sluigi{ 283231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 284231437Sluigi int i; 285231437Sluigi 286231437Sluigi taskqueue_drain(taskqueue_swi, &wq->txtask); 287231437Sluigi 288231437Sluigi if (wq->ring != NULL) { 289231437Sluigi oce_destroy_ring_buffer(sc, wq->ring); 290231437Sluigi wq->ring = NULL; 291231437Sluigi } 292231437Sluigi 293231437Sluigi for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) { 294231437Sluigi if (wq->pckts[i].map != NULL) { 295231437Sluigi bus_dmamap_unload(wq->tag, wq->pckts[i].map); 296231437Sluigi bus_dmamap_destroy(wq->tag, wq->pckts[i].map); 297231437Sluigi wq->pckts[i].map = NULL; 298231437Sluigi } 299231437Sluigi } 300231437Sluigi 301231437Sluigi if (wq->tag != NULL) 302231437Sluigi bus_dma_tag_destroy(wq->tag); 303231437Sluigi if (wq->br != NULL) 304231437Sluigi buf_ring_free(wq->br, M_DEVBUF); 305231437Sluigi 306231437Sluigi LOCK_DESTROY(&wq->tx_lock); 307231437Sluigi free(wq, M_DEVBUF); 308231437Sluigi} 309231437Sluigi 310231437Sluigi 311231437Sluigi 312231437Sluigi/** 313231437Sluigi * @brief Create a work queue 314231437Sluigi * @param wq pointer to work queue 315231437Sluigi * @param eq pointer to associated event queue 316231437Sluigi */ 317231437Sluigistatic int 318231437Sluigioce_wq_create(struct oce_wq *wq, struct oce_eq *eq) 319231437Sluigi{ 320231437Sluigi POCE_SOFTC sc = wq->parent; 321231437Sluigi struct oce_cq *cq; 322231437Sluigi int rc = 0; 323231437Sluigi 324231437Sluigi /* create the CQ */ 325231437Sluigi cq = oce_cq_create(sc, 326231437Sluigi eq, 327231437Sluigi CQ_LEN_1024, 328231437Sluigi sizeof(struct oce_nic_tx_cqe), 0, 1, 0, 3); 329231437Sluigi if (!cq) 330231437Sluigi return ENXIO; 331231437Sluigi 332231437Sluigi 333231437Sluigi wq->cq = cq; 334231437Sluigi 335231437Sluigi rc = oce_mbox_create_wq(wq); 336231437Sluigi if (rc) 337231437Sluigi goto error; 338231437Sluigi 339231437Sluigi wq->qstate = QCREATED; 340231437Sluigi wq->wq_free = wq->cfg.q_len; 341231437Sluigi wq->ring->cidx = 0; 342231437Sluigi wq->ring->pidx = 0; 343231437Sluigi 344231437Sluigi eq->cq[eq->cq_valid] = cq; 345231437Sluigi eq->cq_valid++; 346231437Sluigi cq->cb_arg = wq; 347231437Sluigi cq->cq_handler = oce_wq_handler; 348231437Sluigi 349231437Sluigi return 0; 350231437Sluigi 351231437Sluigierror: 352231437Sluigi device_printf(sc->dev, "WQ create failed\n"); 353231437Sluigi oce_wq_del(wq); 354231437Sluigi return rc; 355231437Sluigi} 356231437Sluigi 357231437Sluigi 358231437Sluigi 359231437Sluigi 360231437Sluigi/** 361231437Sluigi * @brief Delete a work queue 362231437Sluigi * @param wq pointer to work queue 363231437Sluigi */ 364231437Sluigistatic void 365231437Sluigioce_wq_del(struct oce_wq *wq) 366231437Sluigi{ 367231437Sluigi struct oce_mbx mbx; 368231437Sluigi struct mbx_delete_nic_wq *fwcmd; 369231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 370231437Sluigi 371231437Sluigi if (wq->qstate == QCREATED) { 372231437Sluigi bzero(&mbx, sizeof(struct oce_mbx)); 373231437Sluigi /* now fill the command */ 374231437Sluigi fwcmd = (struct mbx_delete_nic_wq *)&mbx.payload; 375231437Sluigi fwcmd->params.req.wq_id = wq->wq_id; 376231437Sluigi (void)oce_destroy_q(sc, &mbx, 377231437Sluigi sizeof(struct mbx_delete_nic_wq), QTYPE_WQ); 378231437Sluigi wq->qstate = QDELETED; 379231437Sluigi } 380231437Sluigi 381231437Sluigi if (wq->cq != NULL) { 382231437Sluigi oce_cq_del(sc, wq->cq); 383231437Sluigi wq->cq = NULL; 384231437Sluigi } 385231437Sluigi} 386231437Sluigi 387231437Sluigi 388231437Sluigi 389231437Sluigi/** 390231437Sluigi * @brief function to allocate receive queue resources 391231437Sluigi * @param sc software handle to the device 392231437Sluigi * @param q_len length of receive queue 393231437Sluigi * @param frag_size size of an receive queue fragment 394231437Sluigi * @param mtu maximum transmission unit 395231437Sluigi * @param rss is-rss-queue flag 396231437Sluigi * @returns the pointer to the RQ created or NULL on failure 397231437Sluigi */ 398231437Sluigistatic struct 399231437Sluigioce_rq *oce_rq_init(POCE_SOFTC sc, 400231437Sluigi uint32_t q_len, 401231437Sluigi uint32_t frag_size, 402231437Sluigi uint32_t mtu, uint32_t rss) 403231437Sluigi{ 404231437Sluigi struct oce_rq *rq; 405231437Sluigi int rc = 0, i; 406231437Sluigi 407231437Sluigi if (OCE_LOG2(frag_size) <= 0) 408231437Sluigi return NULL; 409231437Sluigi 410231437Sluigi if ((q_len == 0) || (q_len > 1024)) 411231437Sluigi return NULL; 412231437Sluigi 413231437Sluigi /* allocate the rq */ 414231437Sluigi rq = malloc(sizeof(struct oce_rq), M_DEVBUF, M_NOWAIT | M_ZERO); 415231437Sluigi if (!rq) 416231437Sluigi return NULL; 417231437Sluigi 418231437Sluigi 419231437Sluigi rq->cfg.q_len = q_len; 420231437Sluigi rq->cfg.frag_size = frag_size; 421231437Sluigi rq->cfg.mtu = mtu; 422231437Sluigi rq->cfg.eqd = 0; 423231437Sluigi rq->lro_pkts_queued = 0; 424231437Sluigi rq->cfg.is_rss_queue = rss; 425231437Sluigi rq->packets_in = 0; 426231437Sluigi rq->packets_out = 0; 427231437Sluigi rq->pending = 0; 428231437Sluigi 429231437Sluigi rq->parent = (void *)sc; 430231437Sluigi 431231437Sluigi rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 432231437Sluigi 1, 0, 433231437Sluigi BUS_SPACE_MAXADDR, 434231437Sluigi BUS_SPACE_MAXADDR, 435231437Sluigi NULL, NULL, 436231437Sluigi OCE_MAX_RX_SIZE, 437231437Sluigi 1, PAGE_SIZE, 0, NULL, NULL, &rq->tag); 438231437Sluigi 439231437Sluigi if (rc) 440231437Sluigi goto free_rq; 441231437Sluigi 442231437Sluigi for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) { 443231437Sluigi rc = bus_dmamap_create(rq->tag, 0, &rq->pckts[i].map); 444231437Sluigi if (rc) 445231437Sluigi goto free_rq; 446231437Sluigi } 447231437Sluigi 448231437Sluigi /* create the ring buffer */ 449231437Sluigi rq->ring = oce_create_ring_buffer(sc, q_len, 450231437Sluigi sizeof(struct oce_nic_rqe)); 451231437Sluigi if (!rq->ring) 452231437Sluigi goto free_rq; 453231437Sluigi 454231437Sluigi LOCK_CREATE(&rq->rx_lock, "RX_lock"); 455231437Sluigi 456231437Sluigi return rq; 457231437Sluigi 458231437Sluigifree_rq: 459231437Sluigi device_printf(sc->dev, "Create RQ failed\n"); 460231437Sluigi oce_rq_free(rq); 461231437Sluigi return NULL; 462231437Sluigi} 463231437Sluigi 464231437Sluigi 465231437Sluigi 466231437Sluigi 467231437Sluigi/** 468231437Sluigi * @brief Free a receive queue 469231437Sluigi * @param rq pointer to receive queue 470231437Sluigi */ 471231437Sluigistatic void 472231437Sluigioce_rq_free(struct oce_rq *rq) 473231437Sluigi{ 474231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 475231437Sluigi int i = 0 ; 476231437Sluigi 477231437Sluigi if (rq->ring != NULL) { 478231437Sluigi oce_destroy_ring_buffer(sc, rq->ring); 479231437Sluigi rq->ring = NULL; 480231437Sluigi } 481231437Sluigi for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) { 482231437Sluigi if (rq->pckts[i].map != NULL) { 483231437Sluigi bus_dmamap_unload(rq->tag, rq->pckts[i].map); 484231437Sluigi bus_dmamap_destroy(rq->tag, rq->pckts[i].map); 485231437Sluigi rq->pckts[i].map = NULL; 486231437Sluigi } 487231437Sluigi if (rq->pckts[i].mbuf) { 488231437Sluigi m_free(rq->pckts[i].mbuf); 489231437Sluigi rq->pckts[i].mbuf = NULL; 490231437Sluigi } 491231437Sluigi } 492231437Sluigi 493231437Sluigi if (rq->tag != NULL) 494231437Sluigi bus_dma_tag_destroy(rq->tag); 495231437Sluigi 496231437Sluigi LOCK_DESTROY(&rq->rx_lock); 497231437Sluigi free(rq, M_DEVBUF); 498231437Sluigi} 499231437Sluigi 500231437Sluigi 501231437Sluigi 502231437Sluigi 503231437Sluigi/** 504231437Sluigi * @brief Create a receive queue 505231437Sluigi * @param rq receive queue 506231437Sluigi * @param if_id interface identifier index` 507231437Sluigi * @param eq pointer to event queue 508231437Sluigi */ 509231437Sluigistatic int 510231437Sluigioce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq) 511231437Sluigi{ 512231437Sluigi POCE_SOFTC sc = rq->parent; 513231437Sluigi struct oce_cq *cq; 514231437Sluigi 515231437Sluigi cq = oce_cq_create(sc, 516231437Sluigi eq, 517231437Sluigi CQ_LEN_1024, 518231437Sluigi sizeof(struct oce_nic_rx_cqe), 0, 1, 0, 3); 519231437Sluigi if (!cq) 520231437Sluigi return ENXIO; 521231437Sluigi 522231437Sluigi rq->cq = cq; 523231437Sluigi rq->cfg.if_id = if_id; 524231437Sluigi 525231437Sluigi /* Dont create RQ here. Create in if_activate */ 526231437Sluigi rq->qstate = 0; 527231437Sluigi rq->ring->cidx = 0; 528231437Sluigi rq->ring->pidx = 0; 529231437Sluigi eq->cq[eq->cq_valid] = cq; 530231437Sluigi eq->cq_valid++; 531231437Sluigi cq->cb_arg = rq; 532231437Sluigi cq->cq_handler = oce_rq_handler; 533231437Sluigi 534231437Sluigi return 0; 535231437Sluigi 536231437Sluigi} 537231437Sluigi 538231437Sluigi 539231437Sluigi 540231437Sluigi 541231437Sluigi/** 542231437Sluigi * @brief Delete a receive queue 543231437Sluigi * @param rq receive queue 544231437Sluigi */ 545231437Sluigistatic void 546231437Sluigioce_rq_del(struct oce_rq *rq) 547231437Sluigi{ 548231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 549231437Sluigi struct oce_mbx mbx; 550231437Sluigi struct mbx_delete_nic_rq *fwcmd; 551231437Sluigi 552231437Sluigi if (rq->qstate == QCREATED) { 553231437Sluigi bzero(&mbx, sizeof(mbx)); 554231437Sluigi 555231437Sluigi fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload; 556231437Sluigi fwcmd->params.req.rq_id = rq->rq_id; 557231437Sluigi (void)oce_destroy_q(sc, &mbx, 558231437Sluigi sizeof(struct mbx_delete_nic_rq), QTYPE_RQ); 559231437Sluigi rq->qstate = QDELETED; 560231437Sluigi } 561231437Sluigi 562231437Sluigi if (rq->cq != NULL) { 563231437Sluigi oce_cq_del(sc, rq->cq); 564231437Sluigi rq->cq = NULL; 565231437Sluigi } 566231437Sluigi} 567231437Sluigi 568231437Sluigi 569231437Sluigi 570231437Sluigi/** 571231437Sluigi * @brief function to create an event queue 572231437Sluigi * @param sc software handle to the device 573231437Sluigi * @param q_len length of event queue 574231437Sluigi * @param item_size size of an event queue item 575231437Sluigi * @param eq_delay event queue delay 576231437Sluigi * @retval eq success, pointer to event queue 577231437Sluigi * @retval NULL failure 578231437Sluigi */ 579231437Sluigistatic struct 580231437Sluigioce_eq *oce_eq_create(POCE_SOFTC sc, uint32_t q_len, 581231437Sluigi uint32_t item_size, 582231437Sluigi uint32_t eq_delay, 583231437Sluigi uint32_t vector) 584231437Sluigi{ 585231437Sluigi struct oce_eq *eq; 586231437Sluigi int rc = 0; 587231437Sluigi 588231437Sluigi /* allocate an eq */ 589231437Sluigi eq = malloc(sizeof(struct oce_eq), M_DEVBUF, M_NOWAIT | M_ZERO); 590231437Sluigi if (eq == NULL) 591231437Sluigi return NULL; 592231437Sluigi 593231437Sluigi eq->parent = (void *)sc; 594231437Sluigi eq->eq_id = 0xffff; 595231437Sluigi eq->ring = oce_create_ring_buffer(sc, q_len, item_size); 596231437Sluigi if (!eq->ring) 597231437Sluigi goto free_eq; 598231437Sluigi 599231437Sluigi eq->eq_cfg.q_len = q_len; 600231437Sluigi eq->eq_cfg.item_size = item_size; 601231437Sluigi eq->eq_cfg.cur_eqd = (uint8_t) eq_delay; 602231437Sluigi 603231437Sluigi rc = oce_mbox_create_eq(eq); 604231437Sluigi if (rc) 605231437Sluigi goto free_eq; 606231437Sluigi 607231437Sluigi sc->intrs[sc->neqs++].eq = eq; 608231437Sluigi 609231437Sluigi return eq; 610231437Sluigi 611231437Sluigifree_eq: 612231437Sluigi oce_eq_del(eq); 613231437Sluigi return NULL; 614231437Sluigi} 615231437Sluigi 616231437Sluigi 617231437Sluigi 618231437Sluigi 619231437Sluigi/** 620231437Sluigi * @brief Function to delete an event queue 621231437Sluigi * @param eq pointer to an event queue 622231437Sluigi */ 623231437Sluigistatic void 624231437Sluigioce_eq_del(struct oce_eq *eq) 625231437Sluigi{ 626231437Sluigi struct oce_mbx mbx; 627231437Sluigi struct mbx_destroy_common_eq *fwcmd; 628231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) eq->parent; 629231437Sluigi 630231437Sluigi if (eq->eq_id != 0xffff) { 631231437Sluigi bzero(&mbx, sizeof(mbx)); 632231437Sluigi fwcmd = (struct mbx_destroy_common_eq *)&mbx.payload; 633231437Sluigi fwcmd->params.req.id = eq->eq_id; 634231437Sluigi (void)oce_destroy_q(sc, &mbx, 635231437Sluigi sizeof(struct mbx_destroy_common_eq), QTYPE_EQ); 636231437Sluigi } 637231437Sluigi 638231437Sluigi if (eq->ring != NULL) { 639231437Sluigi oce_destroy_ring_buffer(sc, eq->ring); 640231437Sluigi eq->ring = NULL; 641231437Sluigi } 642231437Sluigi 643231437Sluigi free(eq, M_DEVBUF); 644231437Sluigi 645231437Sluigi} 646231437Sluigi 647231437Sluigi 648231437Sluigi 649231437Sluigi 650231437Sluigi/** 651231437Sluigi * @brief Function to create an MQ 652231437Sluigi * @param sc software handle to the device 653231437Sluigi * @param eq the EQ to associate with the MQ for event notification 654231437Sluigi * @param q_len the number of entries to create in the MQ 655231437Sluigi * @returns pointer to the created MQ, failure otherwise 656231437Sluigi */ 657231437Sluigistatic struct oce_mq * 658231437Sluigioce_mq_create(POCE_SOFTC sc, struct oce_eq *eq, uint32_t q_len) 659231437Sluigi{ 660231437Sluigi struct oce_mbx mbx; 661231879Sluigi struct mbx_create_common_mq_ex *fwcmd = NULL; 662231437Sluigi struct oce_mq *mq = NULL; 663231437Sluigi int rc = 0; 664231437Sluigi struct oce_cq *cq; 665231879Sluigi oce_mq_ext_ctx_t *ctx; 666231437Sluigi uint32_t num_pages; 667231437Sluigi uint32_t page_size; 668247880Sdelphij int version; 669231437Sluigi 670231437Sluigi cq = oce_cq_create(sc, eq, CQ_LEN_256, 671231437Sluigi sizeof(struct oce_mq_cqe), 1, 1, 0, 0); 672231437Sluigi if (!cq) 673231437Sluigi return NULL; 674231437Sluigi 675231437Sluigi /* allocate the mq */ 676231437Sluigi mq = malloc(sizeof(struct oce_mq), M_DEVBUF, M_NOWAIT | M_ZERO); 677231437Sluigi if (!mq) { 678231437Sluigi oce_cq_del(sc, cq); 679231437Sluigi goto error; 680231437Sluigi } 681231437Sluigi 682231437Sluigi mq->parent = sc; 683231437Sluigi 684231437Sluigi mq->ring = oce_create_ring_buffer(sc, q_len, sizeof(struct oce_mbx)); 685231437Sluigi if (!mq->ring) 686231437Sluigi goto error; 687231437Sluigi 688231437Sluigi bzero(&mbx, sizeof(struct oce_mbx)); 689231437Sluigi 690247880Sdelphij IS_XE201(sc) ? (version = OCE_MBX_VER_V1) : (version = OCE_MBX_VER_V0); 691231879Sluigi fwcmd = (struct mbx_create_common_mq_ex *)&mbx.payload; 692231437Sluigi mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0, 693231437Sluigi MBX_SUBSYSTEM_COMMON, 694231879Sluigi OPCODE_COMMON_CREATE_MQ_EXT, 695231437Sluigi MBX_TIMEOUT_SEC, 696231879Sluigi sizeof(struct mbx_create_common_mq_ex), 697231437Sluigi version); 698231437Sluigi 699231437Sluigi num_pages = oce_page_list(mq->ring, &fwcmd->params.req.pages[0]); 700231437Sluigi page_size = mq->ring->num_items * mq->ring->item_size; 701231437Sluigi 702231437Sluigi ctx = &fwcmd->params.req.context; 703231437Sluigi 704247880Sdelphij if (IS_XE201(sc)) { 705247880Sdelphij ctx->v1.num_pages = num_pages; 706247880Sdelphij ctx->v1.ring_size = OCE_LOG2(q_len) + 1; 707247880Sdelphij ctx->v1.cq_id = cq->cq_id; 708247880Sdelphij ctx->v1.valid = 1; 709247880Sdelphij ctx->v1.async_cq_id = cq->cq_id; 710247880Sdelphij ctx->v1.async_cq_valid = 1; 711247880Sdelphij /* Subscribe to Link State and Group 5 Events(bits 1 & 5 set) */ 712247880Sdelphij ctx->v1.async_evt_bitmap |= LE_32(0x00000022); 713247880Sdelphij ctx->v1.async_evt_bitmap |= LE_32(1 << ASYNC_EVENT_CODE_DEBUG); 714247880Sdelphij ctx->v1.async_evt_bitmap |= 715247880Sdelphij LE_32(1 << ASYNC_EVENT_CODE_SLIPORT); 716247880Sdelphij } 717247880Sdelphij else { 718247880Sdelphij ctx->v0.num_pages = num_pages; 719247880Sdelphij ctx->v0.cq_id = cq->cq_id; 720247880Sdelphij ctx->v0.ring_size = OCE_LOG2(q_len) + 1; 721247880Sdelphij ctx->v0.valid = 1; 722247880Sdelphij /* Subscribe to Link State and Group5 Events(bits 1 & 5 set) */ 723247880Sdelphij ctx->v0.async_evt_bitmap = 0xffffffff; 724247880Sdelphij } 725247880Sdelphij 726231437Sluigi mbx.u0.s.embedded = 1; 727231879Sluigi mbx.payload_length = sizeof(struct mbx_create_common_mq_ex); 728231437Sluigi DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ); 729231437Sluigi 730231437Sluigi rc = oce_mbox_post(sc, &mbx, NULL); 731247880Sdelphij if (!rc) 732247880Sdelphij rc = fwcmd->hdr.u0.rsp.status; 733247880Sdelphij if (rc) { 734247880Sdelphij device_printf(sc->dev,"%s failed - cmd status: %d\n", 735247880Sdelphij __FUNCTION__, rc); 736231437Sluigi goto error; 737247880Sdelphij } 738231437Sluigi mq->mq_id = LE_16(fwcmd->params.rsp.mq_id); 739231437Sluigi mq->cq = cq; 740231437Sluigi eq->cq[eq->cq_valid] = cq; 741231437Sluigi eq->cq_valid++; 742231437Sluigi mq->cq->eq = eq; 743231437Sluigi mq->cfg.q_len = (uint8_t) q_len; 744231437Sluigi mq->cfg.eqd = 0; 745231437Sluigi mq->qstate = QCREATED; 746231437Sluigi 747231437Sluigi mq->cq->cb_arg = mq; 748231437Sluigi mq->cq->cq_handler = oce_mq_handler; 749231437Sluigi 750231437Sluigi return mq; 751231437Sluigi 752231437Sluigierror: 753231437Sluigi device_printf(sc->dev, "MQ create failed\n"); 754231437Sluigi oce_mq_free(mq); 755231437Sluigi mq = NULL; 756231437Sluigi return mq; 757231437Sluigi} 758231437Sluigi 759231437Sluigi 760231437Sluigi 761231437Sluigi 762231437Sluigi 763231437Sluigi/** 764231437Sluigi * @brief Function to free a mailbox queue 765231437Sluigi * @param mq pointer to a mailbox queue 766231437Sluigi */ 767231437Sluigistatic void 768231437Sluigioce_mq_free(struct oce_mq *mq) 769231437Sluigi{ 770231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) mq->parent; 771231437Sluigi struct oce_mbx mbx; 772231437Sluigi struct mbx_destroy_common_mq *fwcmd; 773231437Sluigi 774231437Sluigi if (!mq) 775231437Sluigi return; 776231437Sluigi 777231437Sluigi if (mq->ring != NULL) { 778231437Sluigi oce_destroy_ring_buffer(sc, mq->ring); 779231437Sluigi mq->ring = NULL; 780231437Sluigi if (mq->qstate == QCREATED) { 781231437Sluigi bzero(&mbx, sizeof (struct oce_mbx)); 782231437Sluigi fwcmd = (struct mbx_destroy_common_mq *)&mbx.payload; 783231437Sluigi fwcmd->params.req.id = mq->mq_id; 784231437Sluigi (void) oce_destroy_q(sc, &mbx, 785231437Sluigi sizeof (struct mbx_destroy_common_mq), 786231437Sluigi QTYPE_MQ); 787231437Sluigi } 788231437Sluigi mq->qstate = QDELETED; 789231437Sluigi } 790231437Sluigi 791231437Sluigi if (mq->cq != NULL) { 792231437Sluigi oce_cq_del(sc, mq->cq); 793231437Sluigi mq->cq = NULL; 794231437Sluigi } 795231437Sluigi 796231437Sluigi free(mq, M_DEVBUF); 797231437Sluigi mq = NULL; 798231437Sluigi} 799231437Sluigi 800231437Sluigi 801231437Sluigi 802231437Sluigi/** 803231437Sluigi * @brief Function to delete a EQ, CQ, MQ, WQ or RQ 804231437Sluigi * @param sc sofware handle to the device 805231437Sluigi * @param mbx mailbox command to send to the fw to delete the queue 806231437Sluigi * (mbx contains the queue information to delete) 807231437Sluigi * @param req_size the size of the mbx payload dependent on the qtype 808231437Sluigi * @param qtype the type of queue i.e. EQ, CQ, MQ, WQ or RQ 809231437Sluigi * @returns 0 on success, failure otherwise 810231437Sluigi */ 811231437Sluigistatic int 812231437Sluigioce_destroy_q(POCE_SOFTC sc, struct oce_mbx *mbx, size_t req_size, 813231437Sluigi enum qtype qtype) 814231437Sluigi{ 815231437Sluigi struct mbx_hdr *hdr = (struct mbx_hdr *)&mbx->payload; 816231437Sluigi int opcode; 817231437Sluigi int subsys; 818231437Sluigi int rc = 0; 819231437Sluigi 820231437Sluigi switch (qtype) { 821231437Sluigi case QTYPE_EQ: 822231437Sluigi opcode = OPCODE_COMMON_DESTROY_EQ; 823231437Sluigi subsys = MBX_SUBSYSTEM_COMMON; 824231437Sluigi break; 825231437Sluigi case QTYPE_CQ: 826231437Sluigi opcode = OPCODE_COMMON_DESTROY_CQ; 827231437Sluigi subsys = MBX_SUBSYSTEM_COMMON; 828231437Sluigi break; 829231437Sluigi case QTYPE_MQ: 830231437Sluigi opcode = OPCODE_COMMON_DESTROY_MQ; 831231437Sluigi subsys = MBX_SUBSYSTEM_COMMON; 832231437Sluigi break; 833231437Sluigi case QTYPE_WQ: 834231437Sluigi opcode = NIC_DELETE_WQ; 835231437Sluigi subsys = MBX_SUBSYSTEM_NIC; 836231437Sluigi break; 837231437Sluigi case QTYPE_RQ: 838231437Sluigi opcode = NIC_DELETE_RQ; 839231437Sluigi subsys = MBX_SUBSYSTEM_NIC; 840231437Sluigi break; 841231437Sluigi default: 842231437Sluigi return EINVAL; 843231437Sluigi } 844231437Sluigi 845231437Sluigi mbx_common_req_hdr_init(hdr, 0, 0, subsys, 846231437Sluigi opcode, MBX_TIMEOUT_SEC, req_size, 847231437Sluigi OCE_MBX_VER_V0); 848231437Sluigi 849231437Sluigi mbx->u0.s.embedded = 1; 850231437Sluigi mbx->payload_length = (uint32_t) req_size; 851231437Sluigi DW_SWAP(u32ptr(mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ); 852231437Sluigi 853231437Sluigi rc = oce_mbox_post(sc, mbx, NULL); 854247880Sdelphij if (!rc) 855247880Sdelphij rc = hdr->u0.rsp.status; 856247880Sdelphij if (rc) 857247880Sdelphij device_printf(sc->dev,"%s failed - cmd status: %d\n", 858247880Sdelphij __FUNCTION__, rc); 859231437Sluigi return rc; 860231437Sluigi} 861231437Sluigi 862231437Sluigi 863231437Sluigi 864231437Sluigi/** 865231437Sluigi * @brief Function to create a completion queue 866231437Sluigi * @param sc software handle to the device 867231437Sluigi * @param eq optional eq to be associated with to the cq 868231437Sluigi * @param q_len length of completion queue 869231437Sluigi * @param item_size size of completion queue items 870231437Sluigi * @param sol_event command context event 871231437Sluigi * @param is_eventable event table 872231437Sluigi * @param nodelay no delay flag 873231437Sluigi * @param ncoalesce no coalescence flag 874231437Sluigi * @returns pointer to the cq created, NULL on failure 875231437Sluigi */ 876231437Sluigistruct oce_cq * 877231437Sluigioce_cq_create(POCE_SOFTC sc, struct oce_eq *eq, 878231437Sluigi uint32_t q_len, 879231437Sluigi uint32_t item_size, 880231437Sluigi uint32_t sol_event, 881231437Sluigi uint32_t is_eventable, 882231437Sluigi uint32_t nodelay, uint32_t ncoalesce) 883231437Sluigi{ 884231437Sluigi struct oce_cq *cq = NULL; 885231437Sluigi int rc = 0; 886231437Sluigi 887231437Sluigi cq = malloc(sizeof(struct oce_cq), M_DEVBUF, M_NOWAIT | M_ZERO); 888231437Sluigi if (!cq) 889231437Sluigi return NULL; 890231437Sluigi 891231437Sluigi cq->ring = oce_create_ring_buffer(sc, q_len, item_size); 892231437Sluigi if (!cq->ring) 893231437Sluigi goto error; 894231437Sluigi 895231437Sluigi cq->parent = sc; 896231437Sluigi cq->eq = eq; 897231437Sluigi cq->cq_cfg.q_len = q_len; 898231437Sluigi cq->cq_cfg.item_size = item_size; 899231437Sluigi cq->cq_cfg.nodelay = (uint8_t) nodelay; 900231437Sluigi 901231437Sluigi rc = oce_mbox_cq_create(cq, ncoalesce, is_eventable); 902231437Sluigi if (rc) 903231437Sluigi goto error; 904231437Sluigi 905231437Sluigi sc->cq[sc->ncqs++] = cq; 906231437Sluigi 907231437Sluigi return cq; 908231437Sluigi 909231437Sluigierror: 910231437Sluigi device_printf(sc->dev, "CQ create failed\n"); 911231437Sluigi oce_cq_del(sc, cq); 912231437Sluigi return NULL; 913231437Sluigi} 914231437Sluigi 915231437Sluigi 916231437Sluigi 917231437Sluigi/** 918231437Sluigi * @brief Deletes the completion queue 919231437Sluigi * @param sc software handle to the device 920231437Sluigi * @param cq pointer to a completion queue 921231437Sluigi */ 922231437Sluigistatic void 923231437Sluigioce_cq_del(POCE_SOFTC sc, struct oce_cq *cq) 924231437Sluigi{ 925231437Sluigi struct oce_mbx mbx; 926231437Sluigi struct mbx_destroy_common_cq *fwcmd; 927231437Sluigi 928231437Sluigi if (cq->ring != NULL) { 929231437Sluigi 930231437Sluigi bzero(&mbx, sizeof(struct oce_mbx)); 931231437Sluigi /* now fill the command */ 932231437Sluigi fwcmd = (struct mbx_destroy_common_cq *)&mbx.payload; 933231437Sluigi fwcmd->params.req.id = cq->cq_id; 934231437Sluigi (void)oce_destroy_q(sc, &mbx, 935231437Sluigi sizeof(struct mbx_destroy_common_cq), QTYPE_CQ); 936231437Sluigi /*NOW destroy the ring */ 937231437Sluigi oce_destroy_ring_buffer(sc, cq->ring); 938231437Sluigi cq->ring = NULL; 939231437Sluigi } 940231437Sluigi 941231437Sluigi free(cq, M_DEVBUF); 942231437Sluigi cq = NULL; 943231437Sluigi} 944231437Sluigi 945231437Sluigi 946231437Sluigi 947231437Sluigi/** 948231437Sluigi * @brief Start a receive queue 949231437Sluigi * @param rq pointer to a receive queue 950231437Sluigi */ 951231437Sluigiint 952231437Sluigioce_start_rq(struct oce_rq *rq) 953231437Sluigi{ 954231437Sluigi int rc; 955231437Sluigi 956231437Sluigi rc = oce_alloc_rx_bufs(rq, rq->cfg.q_len); 957231437Sluigi 958231437Sluigi if (rc == 0) 959231437Sluigi oce_arm_cq(rq->parent, rq->cq->cq_id, 0, TRUE); 960231437Sluigi return rc; 961231437Sluigi} 962231437Sluigi 963231437Sluigi 964231437Sluigi 965231437Sluigi/** 966231437Sluigi * @brief Start a work queue 967231437Sluigi * @param wq pointer to a work queue 968231437Sluigi */ 969231437Sluigiint 970231437Sluigioce_start_wq(struct oce_wq *wq) 971231437Sluigi{ 972231437Sluigi oce_arm_cq(wq->parent, wq->cq->cq_id, 0, TRUE); 973231437Sluigi return 0; 974231437Sluigi} 975231437Sluigi 976231437Sluigi 977231437Sluigi 978231437Sluigi/** 979231437Sluigi * @brief Start a mailbox queue 980231437Sluigi * @param mq pointer to a mailbox queue 981231437Sluigi */ 982231437Sluigiint 983231437Sluigioce_start_mq(struct oce_mq *mq) 984231437Sluigi{ 985231437Sluigi oce_arm_cq(mq->parent, mq->cq->cq_id, 0, TRUE); 986231437Sluigi return 0; 987231437Sluigi} 988231437Sluigi 989231437Sluigi 990231437Sluigi 991231437Sluigi/** 992231437Sluigi * @brief Function to arm an EQ so that it can generate events 993231437Sluigi * @param sc software handle to the device 994231437Sluigi * @param qid id of the EQ returned by the fw at the time of creation 995231437Sluigi * @param npopped number of EQEs to arm 996231437Sluigi * @param rearm rearm bit enable/disable 997231437Sluigi * @param clearint bit to clear the interrupt condition because of which 998231437Sluigi * EQEs are generated 999231437Sluigi */ 1000231437Sluigivoid 1001231437Sluigioce_arm_eq(POCE_SOFTC sc, 1002231437Sluigi int16_t qid, int npopped, uint32_t rearm, uint32_t clearint) 1003231437Sluigi{ 1004231437Sluigi eq_db_t eq_db = { 0 }; 1005231437Sluigi 1006231437Sluigi eq_db.bits.rearm = rearm; 1007231437Sluigi eq_db.bits.event = 1; 1008231437Sluigi eq_db.bits.num_popped = npopped; 1009231437Sluigi eq_db.bits.clrint = clearint; 1010231437Sluigi eq_db.bits.qid = qid; 1011231437Sluigi OCE_WRITE_REG32(sc, db, PD_EQ_DB, eq_db.dw0); 1012231437Sluigi 1013231437Sluigi} 1014231437Sluigi 1015231437Sluigi 1016231437Sluigi 1017231437Sluigi 1018231437Sluigi/** 1019231437Sluigi * @brief Function to arm a CQ with CQEs 1020231437Sluigi * @param sc software handle to the device 1021231437Sluigi * @param qid id of the CQ returned by the fw at the time of creation 1022231437Sluigi * @param npopped number of CQEs to arm 1023231437Sluigi * @param rearm rearm bit enable/disable 1024231437Sluigi */ 1025231437Sluigivoid oce_arm_cq(POCE_SOFTC sc, int16_t qid, int npopped, uint32_t rearm) 1026231437Sluigi{ 1027231437Sluigi cq_db_t cq_db = { 0 }; 1028231437Sluigi 1029231437Sluigi cq_db.bits.rearm = rearm; 1030231437Sluigi cq_db.bits.num_popped = npopped; 1031231437Sluigi cq_db.bits.event = 0; 1032231437Sluigi cq_db.bits.qid = qid; 1033231437Sluigi OCE_WRITE_REG32(sc, db, PD_CQ_DB, cq_db.dw0); 1034231437Sluigi 1035231437Sluigi} 1036231437Sluigi 1037231437Sluigi 1038231437Sluigi 1039231437Sluigi 1040231437Sluigi/* 1041231437Sluigi * @brief function to cleanup the eqs used during stop 1042231437Sluigi * @param eq pointer to event queue structure 1043231437Sluigi * @returns the number of EQs processed 1044231437Sluigi */ 1045231437Sluigivoid 1046231437Sluigioce_drain_eq(struct oce_eq *eq) 1047231437Sluigi{ 1048231437Sluigi 1049231437Sluigi struct oce_eqe *eqe; 1050231437Sluigi uint16_t num_eqe = 0; 1051231437Sluigi POCE_SOFTC sc = eq->parent; 1052231437Sluigi 1053231437Sluigi do { 1054231437Sluigi eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 1055231437Sluigi if (eqe->evnt == 0) 1056231437Sluigi break; 1057231437Sluigi eqe->evnt = 0; 1058231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 1059231437Sluigi BUS_DMASYNC_POSTWRITE); 1060231437Sluigi num_eqe++; 1061231437Sluigi RING_GET(eq->ring, 1); 1062231437Sluigi 1063231437Sluigi } while (TRUE); 1064231437Sluigi 1065231437Sluigi oce_arm_eq(sc, eq->eq_id, num_eqe, FALSE, TRUE); 1066231437Sluigi 1067231437Sluigi} 1068231437Sluigi 1069231437Sluigi 1070231437Sluigi 1071231437Sluigivoid 1072231437Sluigioce_drain_wq_cq(struct oce_wq *wq) 1073231437Sluigi{ 1074231437Sluigi POCE_SOFTC sc = wq->parent; 1075231437Sluigi struct oce_cq *cq = wq->cq; 1076231437Sluigi struct oce_nic_tx_cqe *cqe; 1077231437Sluigi int num_cqes = 0; 1078231437Sluigi 1079231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, 1080231437Sluigi BUS_DMASYNC_POSTWRITE); 1081231437Sluigi 1082231437Sluigi do { 1083231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1084231437Sluigi if (cqe->u0.dw[3] == 0) 1085231437Sluigi break; 1086231437Sluigi cqe->u0.dw[3] = 0; 1087231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, 1088231437Sluigi BUS_DMASYNC_POSTWRITE); 1089231437Sluigi RING_GET(cq->ring, 1); 1090231437Sluigi num_cqes++; 1091231437Sluigi 1092231437Sluigi } while (TRUE); 1093231437Sluigi 1094231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1095231437Sluigi 1096231437Sluigi} 1097231437Sluigi 1098231437Sluigi 1099231437Sluigi/* 1100231437Sluigi * @brief function to drain a MCQ and process its CQEs 1101231437Sluigi * @param dev software handle to the device 1102231437Sluigi * @param cq pointer to the cq to drain 1103231437Sluigi * @returns the number of CQEs processed 1104231437Sluigi */ 1105231437Sluigivoid 1106231437Sluigioce_drain_mq_cq(void *arg) 1107231437Sluigi{ 1108231437Sluigi /* TODO: additional code. */ 1109231437Sluigi return; 1110231437Sluigi} 1111231437Sluigi 1112231437Sluigi 1113231437Sluigi 1114231437Sluigi/** 1115231437Sluigi * @brief function to process a Recieve queue 1116231437Sluigi * @param arg pointer to the RQ to charge 1117231437Sluigi * @return number of cqes processed 1118231437Sluigi */ 1119231437Sluigivoid 1120231437Sluigioce_drain_rq_cq(struct oce_rq *rq) 1121231437Sluigi{ 1122231437Sluigi struct oce_nic_rx_cqe *cqe; 1123231437Sluigi uint16_t num_cqe = 0; 1124231437Sluigi struct oce_cq *cq; 1125231437Sluigi POCE_SOFTC sc; 1126231437Sluigi 1127231437Sluigi sc = rq->parent; 1128231437Sluigi cq = rq->cq; 1129231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1130231437Sluigi /* dequeue till you reach an invalid cqe */ 1131231437Sluigi while (RQ_CQE_VALID(cqe)) { 1132231437Sluigi RQ_CQE_INVALIDATE(cqe); 1133231437Sluigi RING_GET(cq->ring, 1); 1134231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, 1135231437Sluigi struct oce_nic_rx_cqe); 1136231437Sluigi num_cqe++; 1137231437Sluigi } 1138231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqe, FALSE); 1139231437Sluigi 1140231437Sluigi return; 1141231437Sluigi} 1142231437Sluigi 1143231437Sluigi 1144231437Sluigivoid 1145231437Sluigioce_free_posted_rxbuf(struct oce_rq *rq) 1146231437Sluigi{ 1147231437Sluigi struct oce_packet_desc *pd; 1148231437Sluigi 1149231437Sluigi while (rq->pending) { 1150231437Sluigi 1151231437Sluigi pd = &rq->pckts[rq->packets_out]; 1152231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1153231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1154231437Sluigi if (pd->mbuf != NULL) { 1155231437Sluigi m_freem(pd->mbuf); 1156231437Sluigi pd->mbuf = NULL; 1157231437Sluigi } 1158231437Sluigi 1159231437Sluigi if ((rq->packets_out + 1) == OCE_RQ_PACKET_ARRAY_SIZE) 1160231437Sluigi rq->packets_out = 0; 1161231437Sluigi else 1162231437Sluigi rq->packets_out++; 1163231437Sluigi 1164231437Sluigi rq->pending--; 1165231437Sluigi } 1166231437Sluigi 1167231437Sluigi} 1168231437Sluigi 1169231437Sluigivoid 1170231437Sluigioce_stop_rx(POCE_SOFTC sc) 1171231437Sluigi{ 1172231437Sluigi struct oce_mbx mbx; 1173231437Sluigi struct mbx_delete_nic_rq *fwcmd; 1174231437Sluigi struct oce_rq *rq; 1175231437Sluigi int i = 0; 1176231437Sluigi 1177231437Sluigi for_all_rq_queues(sc, rq, i) { 1178231437Sluigi if (rq->qstate == QCREATED) { 1179231437Sluigi /* Delete rxq in firmware */ 1180231437Sluigi 1181231437Sluigi bzero(&mbx, sizeof(mbx)); 1182231437Sluigi fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload; 1183231437Sluigi fwcmd->params.req.rq_id = rq->rq_id; 1184231437Sluigi 1185231437Sluigi (void)oce_destroy_q(sc, &mbx, 1186231437Sluigi sizeof(struct mbx_delete_nic_rq), QTYPE_RQ); 1187231437Sluigi 1188231437Sluigi rq->qstate = QDELETED; 1189231437Sluigi 1190231437Sluigi DELAY(1); 1191231437Sluigi 1192231437Sluigi /* Free posted RX buffers that are not used */ 1193231437Sluigi oce_free_posted_rxbuf(rq); 1194231437Sluigi 1195231437Sluigi } 1196231437Sluigi } 1197231437Sluigi} 1198231437Sluigi 1199231437Sluigi 1200231437Sluigi 1201231437Sluigiint 1202231437Sluigioce_start_rx(POCE_SOFTC sc) 1203231437Sluigi{ 1204231437Sluigi struct oce_rq *rq; 1205231437Sluigi int rc = 0, i; 1206231437Sluigi 1207231437Sluigi for_all_rq_queues(sc, rq, i) { 1208231437Sluigi if (rq->qstate == QCREATED) 1209231437Sluigi continue; 1210231437Sluigi rc = oce_mbox_create_rq(rq); 1211231437Sluigi if (rc) 1212231437Sluigi goto error; 1213231437Sluigi /* reset queue pointers */ 1214231437Sluigi rq->qstate = QCREATED; 1215231437Sluigi rq->pending = 0; 1216231437Sluigi rq->ring->cidx = 0; 1217231437Sluigi rq->ring->pidx = 0; 1218231437Sluigi rq->packets_in = 0; 1219231437Sluigi rq->packets_out = 0; 1220231437Sluigi } 1221231437Sluigi 1222231437Sluigi DELAY(1); 1223231437Sluigi 1224231437Sluigi /* RSS config */ 1225252869Sdelphij if (is_rss_enabled(sc)) { 1226231437Sluigi rc = oce_config_nic_rss(sc, (uint8_t) sc->if_id, RSS_ENABLE); 1227231437Sluigi if (rc) 1228231437Sluigi goto error; 1229231437Sluigi 1230231437Sluigi } 1231231437Sluigi 1232231437Sluigi return rc; 1233231437Sluigierror: 1234231437Sluigi device_printf(sc->dev, "Start RX failed\n"); 1235231437Sluigi return rc; 1236231437Sluigi 1237231437Sluigi} 1238231437Sluigi 1239231437Sluigi 1240231437Sluigi 1241