12f345d8eSLuigi Rizzo /*- 27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 37282444bSPedro F. Giffuni * 4291a1934SXin LI * Copyright (C) 2013 Emulex 52f345d8eSLuigi Rizzo * All rights reserved. 62f345d8eSLuigi Rizzo * 72f345d8eSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 82f345d8eSLuigi Rizzo * modification, are permitted provided that the following conditions are met: 92f345d8eSLuigi Rizzo * 102f345d8eSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright notice, 112f345d8eSLuigi Rizzo * this list of conditions and the following disclaimer. 122f345d8eSLuigi Rizzo * 132f345d8eSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 142f345d8eSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 152f345d8eSLuigi Rizzo * documentation and/or other materials provided with the distribution. 162f345d8eSLuigi Rizzo * 172f345d8eSLuigi Rizzo * 3. Neither the name of the Emulex Corporation nor the names of its 182f345d8eSLuigi Rizzo * contributors may be used to endorse or promote products derived from 192f345d8eSLuigi Rizzo * this software without specific prior written permission. 202f345d8eSLuigi Rizzo * 212f345d8eSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 222f345d8eSLuigi Rizzo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 232f345d8eSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 242f345d8eSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 252f345d8eSLuigi Rizzo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 262f345d8eSLuigi Rizzo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 272f345d8eSLuigi Rizzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 282f345d8eSLuigi Rizzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 292f345d8eSLuigi Rizzo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 302f345d8eSLuigi Rizzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 312f345d8eSLuigi Rizzo * POSSIBILITY OF SUCH DAMAGE. 322f345d8eSLuigi Rizzo * 332f345d8eSLuigi Rizzo * Contact Information: 342f345d8eSLuigi Rizzo * freebsd-drivers@emulex.com 352f345d8eSLuigi Rizzo * 362f345d8eSLuigi Rizzo * Emulex 372f345d8eSLuigi Rizzo * 3333 Susan Street 382f345d8eSLuigi Rizzo * Costa Mesa, CA 92626 392f345d8eSLuigi Rizzo */ 402f345d8eSLuigi Rizzo 412f345d8eSLuigi Rizzo /* $FreeBSD$ */ 422f345d8eSLuigi Rizzo 432f345d8eSLuigi Rizzo #include "oce_if.h" 442f345d8eSLuigi Rizzo 452f345d8eSLuigi Rizzo /***************************************************** 462f345d8eSLuigi Rizzo * local queue functions 472f345d8eSLuigi Rizzo *****************************************************/ 482f345d8eSLuigi Rizzo 492f345d8eSLuigi Rizzo static struct oce_wq *oce_wq_init(POCE_SOFTC sc, 502f345d8eSLuigi Rizzo uint32_t q_len, uint32_t wq_type); 512f345d8eSLuigi Rizzo static int oce_wq_create(struct oce_wq *wq, struct oce_eq *eq); 522f345d8eSLuigi Rizzo static void oce_wq_free(struct oce_wq *wq); 532f345d8eSLuigi Rizzo static void oce_wq_del(struct oce_wq *wq); 542f345d8eSLuigi Rizzo static struct oce_rq *oce_rq_init(POCE_SOFTC sc, 552f345d8eSLuigi Rizzo uint32_t q_len, 562f345d8eSLuigi Rizzo uint32_t frag_size, 572f345d8eSLuigi Rizzo uint32_t mtu, uint32_t rss); 582f345d8eSLuigi Rizzo static int oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq); 592f345d8eSLuigi Rizzo static void oce_rq_free(struct oce_rq *rq); 602f345d8eSLuigi Rizzo static void oce_rq_del(struct oce_rq *rq); 612f345d8eSLuigi Rizzo static struct oce_eq *oce_eq_create(POCE_SOFTC sc, 622f345d8eSLuigi Rizzo uint32_t q_len, 632f345d8eSLuigi Rizzo uint32_t item_size, 642f345d8eSLuigi Rizzo uint32_t eq_delay, 652f345d8eSLuigi Rizzo uint32_t vector); 662f345d8eSLuigi Rizzo static void oce_eq_del(struct oce_eq *eq); 672f345d8eSLuigi Rizzo static struct oce_mq *oce_mq_create(POCE_SOFTC sc, 682f345d8eSLuigi Rizzo struct oce_eq *eq, uint32_t q_len); 692f345d8eSLuigi Rizzo static void oce_mq_free(struct oce_mq *mq); 702f345d8eSLuigi Rizzo static int oce_destroy_q(POCE_SOFTC sc, struct oce_mbx 71c2625e6eSJosh Paetzel *mbx, size_t req_size, enum qtype qtype, int version); 722f345d8eSLuigi Rizzo struct oce_cq *oce_cq_create(POCE_SOFTC sc, 732f345d8eSLuigi Rizzo struct oce_eq *eq, 742f345d8eSLuigi Rizzo uint32_t q_len, 752f345d8eSLuigi Rizzo uint32_t item_size, 762f345d8eSLuigi Rizzo uint32_t sol_event, 772f345d8eSLuigi Rizzo uint32_t is_eventable, 782f345d8eSLuigi Rizzo uint32_t nodelay, uint32_t ncoalesce); 792f345d8eSLuigi Rizzo static void oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq); 802f345d8eSLuigi Rizzo 812f345d8eSLuigi Rizzo /** 822f345d8eSLuigi Rizzo * @brief Create and initialize all the queues on the board 832f345d8eSLuigi Rizzo * @param sc software handle to the device 842f345d8eSLuigi Rizzo * @returns 0 if successful, or error 852f345d8eSLuigi Rizzo **/ 862f345d8eSLuigi Rizzo int 872f345d8eSLuigi Rizzo oce_queue_init_all(POCE_SOFTC sc) 882f345d8eSLuigi Rizzo { 892f345d8eSLuigi Rizzo int rc = 0, i, vector; 902f345d8eSLuigi Rizzo struct oce_wq *wq; 912f345d8eSLuigi Rizzo struct oce_rq *rq; 92cdaba892SXin LI struct oce_aic_obj *aic; 932f345d8eSLuigi Rizzo 942f345d8eSLuigi Rizzo /* alloc TX/RX queues */ 952f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 962f345d8eSLuigi Rizzo sc->wq[i] = oce_wq_init(sc, sc->tx_ring_size, 972f345d8eSLuigi Rizzo NIC_WQ_TYPE_STANDARD); 982f345d8eSLuigi Rizzo if (!sc->wq[i]) 992f345d8eSLuigi Rizzo goto error; 1002f345d8eSLuigi Rizzo 1012f345d8eSLuigi Rizzo } 1022f345d8eSLuigi Rizzo 1032f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 1042f345d8eSLuigi Rizzo sc->rq[i] = oce_rq_init(sc, sc->rx_ring_size, sc->rq_frag_size, 1052f345d8eSLuigi Rizzo OCE_MAX_JUMBO_FRAME_SIZE, 106291a1934SXin LI (i == 0) ? 0 : is_rss_enabled(sc)); 1072f345d8eSLuigi Rizzo if (!sc->rq[i]) 1082f345d8eSLuigi Rizzo goto error; 1092f345d8eSLuigi Rizzo } 1102f345d8eSLuigi Rizzo 1112f345d8eSLuigi Rizzo /* Create network interface on card */ 1122f345d8eSLuigi Rizzo if (oce_create_nw_interface(sc)) 1132f345d8eSLuigi Rizzo goto error; 1142f345d8eSLuigi Rizzo 1152f345d8eSLuigi Rizzo /* create all of the event queues */ 1162f345d8eSLuigi Rizzo for (vector = 0; vector < sc->intr_count; vector++) { 117cdaba892SXin LI /* setup aic defaults for each event queue */ 118cdaba892SXin LI aic = &sc->aic_obj[vector]; 119cdaba892SXin LI aic->max_eqd = OCE_MAX_EQD; 120cdaba892SXin LI aic->min_eqd = OCE_MIN_EQD; 121cdaba892SXin LI aic->et_eqd = OCE_MIN_EQD; 122cdaba892SXin LI aic->enable = TRUE; 123cdaba892SXin LI 124c2625e6eSJosh Paetzel sc->eq[vector] = oce_eq_create(sc, sc->enable_hwlro ? EQ_LEN_2048 : EQ_LEN_1024, 125c2625e6eSJosh Paetzel EQE_SIZE_4,0, vector); 126c2625e6eSJosh Paetzel 1272f345d8eSLuigi Rizzo if (!sc->eq[vector]) 1282f345d8eSLuigi Rizzo goto error; 1292f345d8eSLuigi Rizzo } 1302f345d8eSLuigi Rizzo 1312f345d8eSLuigi Rizzo /* create Tx, Rx and mcc queues */ 1322f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 1332f345d8eSLuigi Rizzo rc = oce_wq_create(wq, sc->eq[i]); 1342f345d8eSLuigi Rizzo if (rc) 1352f345d8eSLuigi Rizzo goto error; 1362f345d8eSLuigi Rizzo wq->queue_index = i; 1372f345d8eSLuigi Rizzo TASK_INIT(&wq->txtask, 1, oce_tx_task, wq); 1382f345d8eSLuigi Rizzo } 1392f345d8eSLuigi Rizzo 1402f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 1412f345d8eSLuigi Rizzo rc = oce_rq_create(rq, sc->if_id, 1422f345d8eSLuigi Rizzo sc->eq[(i == 0) ? 0:(i-1)]); 1432f345d8eSLuigi Rizzo if (rc) 1442f345d8eSLuigi Rizzo goto error; 1452f345d8eSLuigi Rizzo rq->queue_index = i; 1462f345d8eSLuigi Rizzo } 1472f345d8eSLuigi Rizzo 1482f345d8eSLuigi Rizzo sc->mq = oce_mq_create(sc, sc->eq[0], 64); 1492f345d8eSLuigi Rizzo if (!sc->mq) 1502f345d8eSLuigi Rizzo goto error; 1512f345d8eSLuigi Rizzo 1522f345d8eSLuigi Rizzo return rc; 1532f345d8eSLuigi Rizzo 1542f345d8eSLuigi Rizzo error: 1552f345d8eSLuigi Rizzo oce_queue_release_all(sc); 1562f345d8eSLuigi Rizzo return 1; 1572f345d8eSLuigi Rizzo } 1582f345d8eSLuigi Rizzo 1592f345d8eSLuigi Rizzo /** 1602f345d8eSLuigi Rizzo * @brief Releases all mailbox queues created 1612f345d8eSLuigi Rizzo * @param sc software handle to the device 1622f345d8eSLuigi Rizzo */ 1632f345d8eSLuigi Rizzo void 1642f345d8eSLuigi Rizzo oce_queue_release_all(POCE_SOFTC sc) 1652f345d8eSLuigi Rizzo { 1662f345d8eSLuigi Rizzo int i = 0; 1672f345d8eSLuigi Rizzo struct oce_wq *wq; 1682f345d8eSLuigi Rizzo struct oce_rq *rq; 1692f345d8eSLuigi Rizzo struct oce_eq *eq; 1702f345d8eSLuigi Rizzo 171c2625e6eSJosh Paetzel /* before deleting lro queues, we have to disable hwlro */ 172c2625e6eSJosh Paetzel if(sc->enable_hwlro) 173c2625e6eSJosh Paetzel oce_mbox_nic_set_iface_lro_config(sc, 0); 174c2625e6eSJosh Paetzel 1752f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 1762f345d8eSLuigi Rizzo if (rq) { 1772f345d8eSLuigi Rizzo oce_rq_del(sc->rq[i]); 1782f345d8eSLuigi Rizzo oce_rq_free(sc->rq[i]); 1792f345d8eSLuigi Rizzo } 1802f345d8eSLuigi Rizzo } 1812f345d8eSLuigi Rizzo 1822f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 1832f345d8eSLuigi Rizzo if (wq) { 1842f345d8eSLuigi Rizzo oce_wq_del(sc->wq[i]); 1852f345d8eSLuigi Rizzo oce_wq_free(sc->wq[i]); 1862f345d8eSLuigi Rizzo } 1872f345d8eSLuigi Rizzo } 1882f345d8eSLuigi Rizzo 1892f345d8eSLuigi Rizzo if (sc->mq) 1902f345d8eSLuigi Rizzo oce_mq_free(sc->mq); 1912f345d8eSLuigi Rizzo 1922f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) { 1932f345d8eSLuigi Rizzo if (eq) 1942f345d8eSLuigi Rizzo oce_eq_del(sc->eq[i]); 1952f345d8eSLuigi Rizzo } 1962f345d8eSLuigi Rizzo } 1972f345d8eSLuigi Rizzo 1982f345d8eSLuigi Rizzo /** 1992f345d8eSLuigi Rizzo * @brief Function to create a WQ for NIC Tx 2002f345d8eSLuigi Rizzo * @param sc software handle to the device 2012f345d8eSLuigi Rizzo * @param qlen number of entries in the queue 2022f345d8eSLuigi Rizzo * @param wq_type work queue type 2032f345d8eSLuigi Rizzo * @returns the pointer to the WQ created or NULL on failure 2042f345d8eSLuigi Rizzo */ 2052f345d8eSLuigi Rizzo static struct 2062f345d8eSLuigi Rizzo oce_wq *oce_wq_init(POCE_SOFTC sc, uint32_t q_len, uint32_t wq_type) 2072f345d8eSLuigi Rizzo { 2082f345d8eSLuigi Rizzo struct oce_wq *wq; 2092f345d8eSLuigi Rizzo int rc = 0, i; 2102f345d8eSLuigi Rizzo 2112f345d8eSLuigi Rizzo /* q_len must be min 256 and max 2k */ 2122f345d8eSLuigi Rizzo if (q_len < 256 || q_len > 2048) { 2132f345d8eSLuigi Rizzo device_printf(sc->dev, 2142f345d8eSLuigi Rizzo "Invalid q length. Must be " 2152f345d8eSLuigi Rizzo "[256, 2000]: 0x%x\n", q_len); 2162f345d8eSLuigi Rizzo return NULL; 2172f345d8eSLuigi Rizzo } 2182f345d8eSLuigi Rizzo 2192f345d8eSLuigi Rizzo /* allocate wq */ 2202f345d8eSLuigi Rizzo wq = malloc(sizeof(struct oce_wq), M_DEVBUF, M_NOWAIT | M_ZERO); 2212f345d8eSLuigi Rizzo if (!wq) 2222f345d8eSLuigi Rizzo return NULL; 2232f345d8eSLuigi Rizzo 2242f345d8eSLuigi Rizzo /* Set the wq config */ 2252f345d8eSLuigi Rizzo wq->cfg.q_len = q_len; 2262f345d8eSLuigi Rizzo wq->cfg.wq_type = (uint8_t) wq_type; 2272f345d8eSLuigi Rizzo wq->cfg.eqd = OCE_DEFAULT_WQ_EQD; 2282f345d8eSLuigi Rizzo wq->cfg.nbufs = 2 * wq->cfg.q_len; 2292f345d8eSLuigi Rizzo wq->cfg.nhdl = 2 * wq->cfg.q_len; 2302f345d8eSLuigi Rizzo 2312f345d8eSLuigi Rizzo wq->parent = (void *)sc; 2322f345d8eSLuigi Rizzo 2332f345d8eSLuigi Rizzo rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 2342f345d8eSLuigi Rizzo 1, 0, 2352f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 2362f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 2372f345d8eSLuigi Rizzo NULL, NULL, 2382f345d8eSLuigi Rizzo OCE_MAX_TX_SIZE, 2392f345d8eSLuigi Rizzo OCE_MAX_TX_ELEMENTS, 2402f345d8eSLuigi Rizzo PAGE_SIZE, 0, NULL, NULL, &wq->tag); 2412f345d8eSLuigi Rizzo 2422f345d8eSLuigi Rizzo if (rc) 2432f345d8eSLuigi Rizzo goto free_wq; 2442f345d8eSLuigi Rizzo 2452f345d8eSLuigi Rizzo for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) { 2462f345d8eSLuigi Rizzo rc = bus_dmamap_create(wq->tag, 0, &wq->pckts[i].map); 2472f345d8eSLuigi Rizzo if (rc) 2482f345d8eSLuigi Rizzo goto free_wq; 2492f345d8eSLuigi Rizzo } 2502f345d8eSLuigi Rizzo 2512f345d8eSLuigi Rizzo wq->ring = oce_create_ring_buffer(sc, q_len, NIC_WQE_SIZE); 2522f345d8eSLuigi Rizzo if (!wq->ring) 2532f345d8eSLuigi Rizzo goto free_wq; 2542f345d8eSLuigi Rizzo 2552f345d8eSLuigi Rizzo LOCK_CREATE(&wq->tx_lock, "TX_lock"); 256c2625e6eSJosh Paetzel LOCK_CREATE(&wq->tx_compl_lock, "WQ_HANDLER_LOCK"); 2572f345d8eSLuigi Rizzo 2582f345d8eSLuigi Rizzo /* Allocate buf ring for multiqueue*/ 2592f345d8eSLuigi Rizzo wq->br = buf_ring_alloc(4096, M_DEVBUF, 2602f345d8eSLuigi Rizzo M_WAITOK, &wq->tx_lock.mutex); 2612f345d8eSLuigi Rizzo if (!wq->br) 2622f345d8eSLuigi Rizzo goto free_wq; 2632f345d8eSLuigi Rizzo return wq; 2642f345d8eSLuigi Rizzo 2652f345d8eSLuigi Rizzo free_wq: 2662f345d8eSLuigi Rizzo device_printf(sc->dev, "Create WQ failed\n"); 2672f345d8eSLuigi Rizzo oce_wq_free(wq); 2682f345d8eSLuigi Rizzo return NULL; 2692f345d8eSLuigi Rizzo } 2702f345d8eSLuigi Rizzo 2712f345d8eSLuigi Rizzo /** 2722f345d8eSLuigi Rizzo * @brief Frees the work queue 2732f345d8eSLuigi Rizzo * @param wq pointer to work queue to free 2742f345d8eSLuigi Rizzo */ 2752f345d8eSLuigi Rizzo static void 2762f345d8eSLuigi Rizzo oce_wq_free(struct oce_wq *wq) 2772f345d8eSLuigi Rizzo { 2782f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 2792f345d8eSLuigi Rizzo int i; 2802f345d8eSLuigi Rizzo 2812f345d8eSLuigi Rizzo taskqueue_drain(taskqueue_swi, &wq->txtask); 2822f345d8eSLuigi Rizzo 2832f345d8eSLuigi Rizzo if (wq->ring != NULL) { 2842f345d8eSLuigi Rizzo oce_destroy_ring_buffer(sc, wq->ring); 2852f345d8eSLuigi Rizzo wq->ring = NULL; 2862f345d8eSLuigi Rizzo } 2872f345d8eSLuigi Rizzo 2882f345d8eSLuigi Rizzo for (i = 0; i < OCE_WQ_PACKET_ARRAY_SIZE; i++) { 2892f345d8eSLuigi Rizzo if (wq->pckts[i].map != NULL) { 2902f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, wq->pckts[i].map); 2912f345d8eSLuigi Rizzo bus_dmamap_destroy(wq->tag, wq->pckts[i].map); 2922f345d8eSLuigi Rizzo wq->pckts[i].map = NULL; 2932f345d8eSLuigi Rizzo } 2942f345d8eSLuigi Rizzo } 2952f345d8eSLuigi Rizzo 2962f345d8eSLuigi Rizzo if (wq->tag != NULL) 2972f345d8eSLuigi Rizzo bus_dma_tag_destroy(wq->tag); 2982f345d8eSLuigi Rizzo if (wq->br != NULL) 2992f345d8eSLuigi Rizzo buf_ring_free(wq->br, M_DEVBUF); 3002f345d8eSLuigi Rizzo 3012f345d8eSLuigi Rizzo LOCK_DESTROY(&wq->tx_lock); 302c2625e6eSJosh Paetzel LOCK_DESTROY(&wq->tx_compl_lock); 3032f345d8eSLuigi Rizzo free(wq, M_DEVBUF); 3042f345d8eSLuigi Rizzo } 3052f345d8eSLuigi Rizzo 3062f345d8eSLuigi Rizzo /** 3072f345d8eSLuigi Rizzo * @brief Create a work queue 3082f345d8eSLuigi Rizzo * @param wq pointer to work queue 3092f345d8eSLuigi Rizzo * @param eq pointer to associated event queue 3102f345d8eSLuigi Rizzo */ 3112f345d8eSLuigi Rizzo static int 3122f345d8eSLuigi Rizzo oce_wq_create(struct oce_wq *wq, struct oce_eq *eq) 3132f345d8eSLuigi Rizzo { 3142f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 3152f345d8eSLuigi Rizzo struct oce_cq *cq; 3162f345d8eSLuigi Rizzo int rc = 0; 3172f345d8eSLuigi Rizzo 3182f345d8eSLuigi Rizzo /* create the CQ */ 3192f345d8eSLuigi Rizzo cq = oce_cq_create(sc, 3202f345d8eSLuigi Rizzo eq, 3212f345d8eSLuigi Rizzo CQ_LEN_1024, 3222f345d8eSLuigi Rizzo sizeof(struct oce_nic_tx_cqe), 0, 1, 0, 3); 3232f345d8eSLuigi Rizzo if (!cq) 3242f345d8eSLuigi Rizzo return ENXIO; 3252f345d8eSLuigi Rizzo 3262f345d8eSLuigi Rizzo wq->cq = cq; 3272f345d8eSLuigi Rizzo 3282f345d8eSLuigi Rizzo rc = oce_mbox_create_wq(wq); 3292f345d8eSLuigi Rizzo if (rc) 3302f345d8eSLuigi Rizzo goto error; 3312f345d8eSLuigi Rizzo 3322f345d8eSLuigi Rizzo wq->qstate = QCREATED; 3332f345d8eSLuigi Rizzo wq->wq_free = wq->cfg.q_len; 3342f345d8eSLuigi Rizzo wq->ring->cidx = 0; 3352f345d8eSLuigi Rizzo wq->ring->pidx = 0; 3362f345d8eSLuigi Rizzo 3372f345d8eSLuigi Rizzo eq->cq[eq->cq_valid] = cq; 3382f345d8eSLuigi Rizzo eq->cq_valid++; 3392f345d8eSLuigi Rizzo cq->cb_arg = wq; 3402f345d8eSLuigi Rizzo cq->cq_handler = oce_wq_handler; 3412f345d8eSLuigi Rizzo 3422f345d8eSLuigi Rizzo return 0; 3432f345d8eSLuigi Rizzo 3442f345d8eSLuigi Rizzo error: 3452f345d8eSLuigi Rizzo device_printf(sc->dev, "WQ create failed\n"); 3462f345d8eSLuigi Rizzo oce_wq_del(wq); 3472f345d8eSLuigi Rizzo return rc; 3482f345d8eSLuigi Rizzo } 3492f345d8eSLuigi Rizzo 3502f345d8eSLuigi Rizzo /** 3512f345d8eSLuigi Rizzo * @brief Delete a work queue 3522f345d8eSLuigi Rizzo * @param wq pointer to work queue 3532f345d8eSLuigi Rizzo */ 3542f345d8eSLuigi Rizzo static void 3552f345d8eSLuigi Rizzo oce_wq_del(struct oce_wq *wq) 3562f345d8eSLuigi Rizzo { 3572f345d8eSLuigi Rizzo struct oce_mbx mbx; 3582f345d8eSLuigi Rizzo struct mbx_delete_nic_wq *fwcmd; 3592f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 3602f345d8eSLuigi Rizzo 3612f345d8eSLuigi Rizzo if (wq->qstate == QCREATED) { 3622f345d8eSLuigi Rizzo bzero(&mbx, sizeof(struct oce_mbx)); 3632f345d8eSLuigi Rizzo /* now fill the command */ 3642f345d8eSLuigi Rizzo fwcmd = (struct mbx_delete_nic_wq *)&mbx.payload; 3652f345d8eSLuigi Rizzo fwcmd->params.req.wq_id = wq->wq_id; 3662f345d8eSLuigi Rizzo (void)oce_destroy_q(sc, &mbx, 367c2625e6eSJosh Paetzel sizeof(struct mbx_delete_nic_wq), QTYPE_WQ, 0); 3682f345d8eSLuigi Rizzo wq->qstate = QDELETED; 3692f345d8eSLuigi Rizzo } 3702f345d8eSLuigi Rizzo 3712f345d8eSLuigi Rizzo if (wq->cq != NULL) { 3722f345d8eSLuigi Rizzo oce_cq_del(sc, wq->cq); 3732f345d8eSLuigi Rizzo wq->cq = NULL; 3742f345d8eSLuigi Rizzo } 3752f345d8eSLuigi Rizzo } 3762f345d8eSLuigi Rizzo 3772f345d8eSLuigi Rizzo /** 3782f345d8eSLuigi Rizzo * @brief function to allocate receive queue resources 3792f345d8eSLuigi Rizzo * @param sc software handle to the device 3802f345d8eSLuigi Rizzo * @param q_len length of receive queue 3812f345d8eSLuigi Rizzo * @param frag_size size of an receive queue fragment 3822f345d8eSLuigi Rizzo * @param mtu maximum transmission unit 3832f345d8eSLuigi Rizzo * @param rss is-rss-queue flag 3842f345d8eSLuigi Rizzo * @returns the pointer to the RQ created or NULL on failure 3852f345d8eSLuigi Rizzo */ 3862f345d8eSLuigi Rizzo static struct 3872f345d8eSLuigi Rizzo oce_rq *oce_rq_init(POCE_SOFTC sc, 3882f345d8eSLuigi Rizzo uint32_t q_len, 3892f345d8eSLuigi Rizzo uint32_t frag_size, 3902f345d8eSLuigi Rizzo uint32_t mtu, uint32_t rss) 3912f345d8eSLuigi Rizzo { 3922f345d8eSLuigi Rizzo struct oce_rq *rq; 3932f345d8eSLuigi Rizzo int rc = 0, i; 3942f345d8eSLuigi Rizzo 3952f345d8eSLuigi Rizzo if (OCE_LOG2(frag_size) <= 0) 3962f345d8eSLuigi Rizzo return NULL; 3972f345d8eSLuigi Rizzo 3982f345d8eSLuigi Rizzo if ((q_len == 0) || (q_len > 1024)) 3992f345d8eSLuigi Rizzo return NULL; 4002f345d8eSLuigi Rizzo 4012f345d8eSLuigi Rizzo /* allocate the rq */ 4022f345d8eSLuigi Rizzo rq = malloc(sizeof(struct oce_rq), M_DEVBUF, M_NOWAIT | M_ZERO); 4032f345d8eSLuigi Rizzo if (!rq) 4042f345d8eSLuigi Rizzo return NULL; 4052f345d8eSLuigi Rizzo 4062f345d8eSLuigi Rizzo rq->cfg.q_len = q_len; 4072f345d8eSLuigi Rizzo rq->cfg.frag_size = frag_size; 4082f345d8eSLuigi Rizzo rq->cfg.mtu = mtu; 4092f345d8eSLuigi Rizzo rq->cfg.eqd = 0; 4102f345d8eSLuigi Rizzo rq->lro_pkts_queued = 0; 4112f345d8eSLuigi Rizzo rq->cfg.is_rss_queue = rss; 4122f345d8eSLuigi Rizzo rq->pending = 0; 4132f345d8eSLuigi Rizzo 4142f345d8eSLuigi Rizzo rq->parent = (void *)sc; 4152f345d8eSLuigi Rizzo 4162f345d8eSLuigi Rizzo rc = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4172f345d8eSLuigi Rizzo 1, 0, 4182f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 4192f345d8eSLuigi Rizzo BUS_SPACE_MAXADDR, 4202f345d8eSLuigi Rizzo NULL, NULL, 421c2625e6eSJosh Paetzel oce_rq_buf_size, 422c2625e6eSJosh Paetzel 1, oce_rq_buf_size, 0, NULL, NULL, &rq->tag); 4232f345d8eSLuigi Rizzo if (rc) 4242f345d8eSLuigi Rizzo goto free_rq; 4252f345d8eSLuigi Rizzo 4262f345d8eSLuigi Rizzo for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) { 4272f345d8eSLuigi Rizzo rc = bus_dmamap_create(rq->tag, 0, &rq->pckts[i].map); 4282f345d8eSLuigi Rizzo if (rc) 4292f345d8eSLuigi Rizzo goto free_rq; 4302f345d8eSLuigi Rizzo } 4312f345d8eSLuigi Rizzo 4322f345d8eSLuigi Rizzo /* create the ring buffer */ 4332f345d8eSLuigi Rizzo rq->ring = oce_create_ring_buffer(sc, q_len, 4342f345d8eSLuigi Rizzo sizeof(struct oce_nic_rqe)); 4352f345d8eSLuigi Rizzo if (!rq->ring) 4362f345d8eSLuigi Rizzo goto free_rq; 4372f345d8eSLuigi Rizzo 4382f345d8eSLuigi Rizzo LOCK_CREATE(&rq->rx_lock, "RX_lock"); 4392f345d8eSLuigi Rizzo 4402f345d8eSLuigi Rizzo return rq; 4412f345d8eSLuigi Rizzo 4422f345d8eSLuigi Rizzo free_rq: 4432f345d8eSLuigi Rizzo device_printf(sc->dev, "Create RQ failed\n"); 4442f345d8eSLuigi Rizzo oce_rq_free(rq); 4452f345d8eSLuigi Rizzo return NULL; 4462f345d8eSLuigi Rizzo } 4472f345d8eSLuigi Rizzo 4482f345d8eSLuigi Rizzo /** 4492f345d8eSLuigi Rizzo * @brief Free a receive queue 4502f345d8eSLuigi Rizzo * @param rq pointer to receive queue 4512f345d8eSLuigi Rizzo */ 4522f345d8eSLuigi Rizzo static void 4532f345d8eSLuigi Rizzo oce_rq_free(struct oce_rq *rq) 4542f345d8eSLuigi Rizzo { 4552f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 4562f345d8eSLuigi Rizzo int i = 0 ; 4572f345d8eSLuigi Rizzo 4582f345d8eSLuigi Rizzo if (rq->ring != NULL) { 4592f345d8eSLuigi Rizzo oce_destroy_ring_buffer(sc, rq->ring); 4602f345d8eSLuigi Rizzo rq->ring = NULL; 4612f345d8eSLuigi Rizzo } 4622f345d8eSLuigi Rizzo for (i = 0; i < OCE_RQ_PACKET_ARRAY_SIZE; i++) { 4632f345d8eSLuigi Rizzo if (rq->pckts[i].map != NULL) { 4642f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, rq->pckts[i].map); 4652f345d8eSLuigi Rizzo bus_dmamap_destroy(rq->tag, rq->pckts[i].map); 4662f345d8eSLuigi Rizzo rq->pckts[i].map = NULL; 4672f345d8eSLuigi Rizzo } 4682f345d8eSLuigi Rizzo if (rq->pckts[i].mbuf) { 4692f345d8eSLuigi Rizzo m_free(rq->pckts[i].mbuf); 4702f345d8eSLuigi Rizzo rq->pckts[i].mbuf = NULL; 4712f345d8eSLuigi Rizzo } 4722f345d8eSLuigi Rizzo } 4732f345d8eSLuigi Rizzo 4742f345d8eSLuigi Rizzo if (rq->tag != NULL) 4752f345d8eSLuigi Rizzo bus_dma_tag_destroy(rq->tag); 4762f345d8eSLuigi Rizzo 4772f345d8eSLuigi Rizzo LOCK_DESTROY(&rq->rx_lock); 4782f345d8eSLuigi Rizzo free(rq, M_DEVBUF); 4792f345d8eSLuigi Rizzo } 4802f345d8eSLuigi Rizzo 4812f345d8eSLuigi Rizzo /** 4822f345d8eSLuigi Rizzo * @brief Create a receive queue 4832f345d8eSLuigi Rizzo * @param rq receive queue 4842f345d8eSLuigi Rizzo * @param if_id interface identifier index` 4852f345d8eSLuigi Rizzo * @param eq pointer to event queue 4862f345d8eSLuigi Rizzo */ 4872f345d8eSLuigi Rizzo static int 4882f345d8eSLuigi Rizzo oce_rq_create(struct oce_rq *rq, uint32_t if_id, struct oce_eq *eq) 4892f345d8eSLuigi Rizzo { 4902f345d8eSLuigi Rizzo POCE_SOFTC sc = rq->parent; 4912f345d8eSLuigi Rizzo struct oce_cq *cq; 4922f345d8eSLuigi Rizzo 493c2625e6eSJosh Paetzel cq = oce_cq_create(sc, eq, 494c2625e6eSJosh Paetzel sc->enable_hwlro ? CQ_LEN_2048 : CQ_LEN_1024, 4952f345d8eSLuigi Rizzo sizeof(struct oce_nic_rx_cqe), 0, 1, 0, 3); 496c2625e6eSJosh Paetzel 4972f345d8eSLuigi Rizzo if (!cq) 4982f345d8eSLuigi Rizzo return ENXIO; 4992f345d8eSLuigi Rizzo 5002f345d8eSLuigi Rizzo rq->cq = cq; 5012f345d8eSLuigi Rizzo rq->cfg.if_id = if_id; 5022f345d8eSLuigi Rizzo 5032f345d8eSLuigi Rizzo /* Dont create RQ here. Create in if_activate */ 5042f345d8eSLuigi Rizzo rq->qstate = 0; 5052f345d8eSLuigi Rizzo rq->ring->cidx = 0; 5062f345d8eSLuigi Rizzo rq->ring->pidx = 0; 5072f345d8eSLuigi Rizzo eq->cq[eq->cq_valid] = cq; 5082f345d8eSLuigi Rizzo eq->cq_valid++; 5092f345d8eSLuigi Rizzo cq->cb_arg = rq; 5102f345d8eSLuigi Rizzo cq->cq_handler = oce_rq_handler; 5112f345d8eSLuigi Rizzo 5122f345d8eSLuigi Rizzo return 0; 5132f345d8eSLuigi Rizzo 5142f345d8eSLuigi Rizzo } 5152f345d8eSLuigi Rizzo 5162f345d8eSLuigi Rizzo /** 5172f345d8eSLuigi Rizzo * @brief Delete a receive queue 5182f345d8eSLuigi Rizzo * @param rq receive queue 5192f345d8eSLuigi Rizzo */ 5202f345d8eSLuigi Rizzo static void 5212f345d8eSLuigi Rizzo oce_rq_del(struct oce_rq *rq) 5222f345d8eSLuigi Rizzo { 5232f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 5242f345d8eSLuigi Rizzo struct oce_mbx mbx; 5252f345d8eSLuigi Rizzo struct mbx_delete_nic_rq *fwcmd; 526c2625e6eSJosh Paetzel struct mbx_delete_nic_rq_v1 *fwcmd1; 5272f345d8eSLuigi Rizzo 5282f345d8eSLuigi Rizzo if (rq->qstate == QCREATED) { 5292f345d8eSLuigi Rizzo bzero(&mbx, sizeof(mbx)); 530c2625e6eSJosh Paetzel if(!rq->islro) { 5312f345d8eSLuigi Rizzo fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload; 5322f345d8eSLuigi Rizzo fwcmd->params.req.rq_id = rq->rq_id; 533c2625e6eSJosh Paetzel (void)oce_destroy_q(sc, &mbx, sizeof(struct mbx_delete_nic_rq), QTYPE_RQ, 0); 534c2625e6eSJosh Paetzel }else { 535c2625e6eSJosh Paetzel fwcmd1 = (struct mbx_delete_nic_rq_v1 *)&mbx.payload; 536c2625e6eSJosh Paetzel fwcmd1->params.req.rq_id = rq->rq_id; 537c2625e6eSJosh Paetzel fwcmd1->params.req.rq_flags = (NIC_RQ_FLAGS_RSS | NIC_RQ_FLAGS_LRO); 538c2625e6eSJosh Paetzel (void)oce_destroy_q(sc, &mbx, sizeof(struct mbx_delete_nic_rq_v1), QTYPE_RQ, 1); 539c2625e6eSJosh Paetzel } 5402f345d8eSLuigi Rizzo rq->qstate = QDELETED; 5412f345d8eSLuigi Rizzo } 5422f345d8eSLuigi Rizzo 5432f345d8eSLuigi Rizzo if (rq->cq != NULL) { 5442f345d8eSLuigi Rizzo oce_cq_del(sc, rq->cq); 5452f345d8eSLuigi Rizzo rq->cq = NULL; 5462f345d8eSLuigi Rizzo } 5472f345d8eSLuigi Rizzo } 5482f345d8eSLuigi Rizzo 5492f345d8eSLuigi Rizzo /** 5502f345d8eSLuigi Rizzo * @brief function to create an event queue 5512f345d8eSLuigi Rizzo * @param sc software handle to the device 5522f345d8eSLuigi Rizzo * @param q_len length of event queue 5532f345d8eSLuigi Rizzo * @param item_size size of an event queue item 5542f345d8eSLuigi Rizzo * @param eq_delay event queue delay 5552f345d8eSLuigi Rizzo * @retval eq success, pointer to event queue 5562f345d8eSLuigi Rizzo * @retval NULL failure 5572f345d8eSLuigi Rizzo */ 5582f345d8eSLuigi Rizzo static struct 5592f345d8eSLuigi Rizzo oce_eq *oce_eq_create(POCE_SOFTC sc, uint32_t q_len, 5602f345d8eSLuigi Rizzo uint32_t item_size, 5612f345d8eSLuigi Rizzo uint32_t eq_delay, 5622f345d8eSLuigi Rizzo uint32_t vector) 5632f345d8eSLuigi Rizzo { 5642f345d8eSLuigi Rizzo struct oce_eq *eq; 5652f345d8eSLuigi Rizzo int rc = 0; 5662f345d8eSLuigi Rizzo 5672f345d8eSLuigi Rizzo /* allocate an eq */ 5682f345d8eSLuigi Rizzo eq = malloc(sizeof(struct oce_eq), M_DEVBUF, M_NOWAIT | M_ZERO); 5692f345d8eSLuigi Rizzo if (eq == NULL) 5702f345d8eSLuigi Rizzo return NULL; 5712f345d8eSLuigi Rizzo 5722f345d8eSLuigi Rizzo eq->parent = (void *)sc; 5732f345d8eSLuigi Rizzo eq->eq_id = 0xffff; 5742f345d8eSLuigi Rizzo eq->ring = oce_create_ring_buffer(sc, q_len, item_size); 5752f345d8eSLuigi Rizzo if (!eq->ring) 5762f345d8eSLuigi Rizzo goto free_eq; 5772f345d8eSLuigi Rizzo 5782f345d8eSLuigi Rizzo eq->eq_cfg.q_len = q_len; 5792f345d8eSLuigi Rizzo eq->eq_cfg.item_size = item_size; 5802f345d8eSLuigi Rizzo eq->eq_cfg.cur_eqd = (uint8_t) eq_delay; 5812f345d8eSLuigi Rizzo 5822f345d8eSLuigi Rizzo rc = oce_mbox_create_eq(eq); 5832f345d8eSLuigi Rizzo if (rc) 5842f345d8eSLuigi Rizzo goto free_eq; 5852f345d8eSLuigi Rizzo 5862f345d8eSLuigi Rizzo sc->intrs[sc->neqs++].eq = eq; 5872f345d8eSLuigi Rizzo 5882f345d8eSLuigi Rizzo return eq; 5892f345d8eSLuigi Rizzo 5902f345d8eSLuigi Rizzo free_eq: 5912f345d8eSLuigi Rizzo oce_eq_del(eq); 5922f345d8eSLuigi Rizzo return NULL; 5932f345d8eSLuigi Rizzo } 5942f345d8eSLuigi Rizzo 5952f345d8eSLuigi Rizzo /** 5962f345d8eSLuigi Rizzo * @brief Function to delete an event queue 5972f345d8eSLuigi Rizzo * @param eq pointer to an event queue 5982f345d8eSLuigi Rizzo */ 5992f345d8eSLuigi Rizzo static void 6002f345d8eSLuigi Rizzo oce_eq_del(struct oce_eq *eq) 6012f345d8eSLuigi Rizzo { 6022f345d8eSLuigi Rizzo struct oce_mbx mbx; 6032f345d8eSLuigi Rizzo struct mbx_destroy_common_eq *fwcmd; 6042f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) eq->parent; 6052f345d8eSLuigi Rizzo 6062f345d8eSLuigi Rizzo if (eq->eq_id != 0xffff) { 6072f345d8eSLuigi Rizzo bzero(&mbx, sizeof(mbx)); 6082f345d8eSLuigi Rizzo fwcmd = (struct mbx_destroy_common_eq *)&mbx.payload; 6092f345d8eSLuigi Rizzo fwcmd->params.req.id = eq->eq_id; 6102f345d8eSLuigi Rizzo (void)oce_destroy_q(sc, &mbx, 611c2625e6eSJosh Paetzel sizeof(struct mbx_destroy_common_eq), QTYPE_EQ, 0); 6122f345d8eSLuigi Rizzo } 6132f345d8eSLuigi Rizzo 6142f345d8eSLuigi Rizzo if (eq->ring != NULL) { 6152f345d8eSLuigi Rizzo oce_destroy_ring_buffer(sc, eq->ring); 6162f345d8eSLuigi Rizzo eq->ring = NULL; 6172f345d8eSLuigi Rizzo } 6182f345d8eSLuigi Rizzo 6192f345d8eSLuigi Rizzo free(eq, M_DEVBUF); 6202f345d8eSLuigi Rizzo 6212f345d8eSLuigi Rizzo } 6222f345d8eSLuigi Rizzo 6232f345d8eSLuigi Rizzo /** 6242f345d8eSLuigi Rizzo * @brief Function to create an MQ 6252f345d8eSLuigi Rizzo * @param sc software handle to the device 6262f345d8eSLuigi Rizzo * @param eq the EQ to associate with the MQ for event notification 6272f345d8eSLuigi Rizzo * @param q_len the number of entries to create in the MQ 6282f345d8eSLuigi Rizzo * @returns pointer to the created MQ, failure otherwise 6292f345d8eSLuigi Rizzo */ 6302f345d8eSLuigi Rizzo static struct oce_mq * 6312f345d8eSLuigi Rizzo oce_mq_create(POCE_SOFTC sc, struct oce_eq *eq, uint32_t q_len) 6322f345d8eSLuigi Rizzo { 6332f345d8eSLuigi Rizzo struct oce_mbx mbx; 6349bd3250aSLuigi Rizzo struct mbx_create_common_mq_ex *fwcmd = NULL; 6352f345d8eSLuigi Rizzo struct oce_mq *mq = NULL; 6362f345d8eSLuigi Rizzo int rc = 0; 6372f345d8eSLuigi Rizzo struct oce_cq *cq; 6389bd3250aSLuigi Rizzo oce_mq_ext_ctx_t *ctx; 6392f345d8eSLuigi Rizzo uint32_t num_pages; 6402f345d8eSLuigi Rizzo uint32_t page_size; 641cdaba892SXin LI int version; 6422f345d8eSLuigi Rizzo 6432f345d8eSLuigi Rizzo cq = oce_cq_create(sc, eq, CQ_LEN_256, 6442f345d8eSLuigi Rizzo sizeof(struct oce_mq_cqe), 1, 1, 0, 0); 6452f345d8eSLuigi Rizzo if (!cq) 6462f345d8eSLuigi Rizzo return NULL; 6472f345d8eSLuigi Rizzo 6482f345d8eSLuigi Rizzo /* allocate the mq */ 6492f345d8eSLuigi Rizzo mq = malloc(sizeof(struct oce_mq), M_DEVBUF, M_NOWAIT | M_ZERO); 6502f345d8eSLuigi Rizzo if (!mq) { 6512f345d8eSLuigi Rizzo oce_cq_del(sc, cq); 6522f345d8eSLuigi Rizzo goto error; 6532f345d8eSLuigi Rizzo } 6542f345d8eSLuigi Rizzo 6552f345d8eSLuigi Rizzo mq->parent = sc; 6562f345d8eSLuigi Rizzo 6572f345d8eSLuigi Rizzo mq->ring = oce_create_ring_buffer(sc, q_len, sizeof(struct oce_mbx)); 6582f345d8eSLuigi Rizzo if (!mq->ring) 6592f345d8eSLuigi Rizzo goto error; 6602f345d8eSLuigi Rizzo 6612f345d8eSLuigi Rizzo bzero(&mbx, sizeof(struct oce_mbx)); 6622f345d8eSLuigi Rizzo 663cdaba892SXin LI IS_XE201(sc) ? (version = OCE_MBX_VER_V1) : (version = OCE_MBX_VER_V0); 6649bd3250aSLuigi Rizzo fwcmd = (struct mbx_create_common_mq_ex *)&mbx.payload; 6652f345d8eSLuigi Rizzo mbx_common_req_hdr_init(&fwcmd->hdr, 0, 0, 6662f345d8eSLuigi Rizzo MBX_SUBSYSTEM_COMMON, 6679bd3250aSLuigi Rizzo OPCODE_COMMON_CREATE_MQ_EXT, 6682f345d8eSLuigi Rizzo MBX_TIMEOUT_SEC, 6699bd3250aSLuigi Rizzo sizeof(struct mbx_create_common_mq_ex), 6702f345d8eSLuigi Rizzo version); 6712f345d8eSLuigi Rizzo 6722f345d8eSLuigi Rizzo num_pages = oce_page_list(mq->ring, &fwcmd->params.req.pages[0]); 6732f345d8eSLuigi Rizzo page_size = mq->ring->num_items * mq->ring->item_size; 6742f345d8eSLuigi Rizzo 6752f345d8eSLuigi Rizzo ctx = &fwcmd->params.req.context; 676cdaba892SXin LI 677cdaba892SXin LI if (IS_XE201(sc)) { 678cdaba892SXin LI ctx->v1.num_pages = num_pages; 679cdaba892SXin LI ctx->v1.ring_size = OCE_LOG2(q_len) + 1; 680cdaba892SXin LI ctx->v1.cq_id = cq->cq_id; 681cdaba892SXin LI ctx->v1.valid = 1; 682cdaba892SXin LI ctx->v1.async_cq_id = cq->cq_id; 683cdaba892SXin LI ctx->v1.async_cq_valid = 1; 684cdaba892SXin LI /* Subscribe to Link State and Group 5 Events(bits 1 & 5 set) */ 685cdaba892SXin LI ctx->v1.async_evt_bitmap |= LE_32(0x00000022); 686cdaba892SXin LI ctx->v1.async_evt_bitmap |= LE_32(1 << ASYNC_EVENT_CODE_DEBUG); 687cdaba892SXin LI ctx->v1.async_evt_bitmap |= 688cdaba892SXin LI LE_32(1 << ASYNC_EVENT_CODE_SLIPORT); 689cdaba892SXin LI } 690cdaba892SXin LI else { 6912f345d8eSLuigi Rizzo ctx->v0.num_pages = num_pages; 6922f345d8eSLuigi Rizzo ctx->v0.cq_id = cq->cq_id; 6932f345d8eSLuigi Rizzo ctx->v0.ring_size = OCE_LOG2(q_len) + 1; 6942f345d8eSLuigi Rizzo ctx->v0.valid = 1; 695cdaba892SXin LI /* Subscribe to Link State and Group5 Events(bits 1 & 5 set) */ 6969bd3250aSLuigi Rizzo ctx->v0.async_evt_bitmap = 0xffffffff; 697cdaba892SXin LI } 6982f345d8eSLuigi Rizzo 6992f345d8eSLuigi Rizzo mbx.u0.s.embedded = 1; 7009bd3250aSLuigi Rizzo mbx.payload_length = sizeof(struct mbx_create_common_mq_ex); 7012f345d8eSLuigi Rizzo DW_SWAP(u32ptr(&mbx), mbx.payload_length + OCE_BMBX_RHDR_SZ); 7022f345d8eSLuigi Rizzo 7032f345d8eSLuigi Rizzo rc = oce_mbox_post(sc, &mbx, NULL); 704cdaba892SXin LI if (!rc) 705cdaba892SXin LI rc = fwcmd->hdr.u0.rsp.status; 706cdaba892SXin LI if (rc) { 707cdaba892SXin LI device_printf(sc->dev,"%s failed - cmd status: %d\n", 708cdaba892SXin LI __FUNCTION__, rc); 7092f345d8eSLuigi Rizzo goto error; 710cdaba892SXin LI } 7112f345d8eSLuigi Rizzo mq->mq_id = LE_16(fwcmd->params.rsp.mq_id); 7122f345d8eSLuigi Rizzo mq->cq = cq; 7132f345d8eSLuigi Rizzo eq->cq[eq->cq_valid] = cq; 7142f345d8eSLuigi Rizzo eq->cq_valid++; 7152f345d8eSLuigi Rizzo mq->cq->eq = eq; 7162f345d8eSLuigi Rizzo mq->cfg.q_len = (uint8_t) q_len; 7172f345d8eSLuigi Rizzo mq->cfg.eqd = 0; 7182f345d8eSLuigi Rizzo mq->qstate = QCREATED; 7192f345d8eSLuigi Rizzo 7202f345d8eSLuigi Rizzo mq->cq->cb_arg = mq; 7212f345d8eSLuigi Rizzo mq->cq->cq_handler = oce_mq_handler; 7222f345d8eSLuigi Rizzo 7232f345d8eSLuigi Rizzo return mq; 7242f345d8eSLuigi Rizzo 7252f345d8eSLuigi Rizzo error: 7262f345d8eSLuigi Rizzo device_printf(sc->dev, "MQ create failed\n"); 7272f345d8eSLuigi Rizzo oce_mq_free(mq); 7282f345d8eSLuigi Rizzo mq = NULL; 7292f345d8eSLuigi Rizzo return mq; 7302f345d8eSLuigi Rizzo } 7312f345d8eSLuigi Rizzo 7322f345d8eSLuigi Rizzo /** 7332f345d8eSLuigi Rizzo * @brief Function to free a mailbox queue 7342f345d8eSLuigi Rizzo * @param mq pointer to a mailbox queue 7352f345d8eSLuigi Rizzo */ 7362f345d8eSLuigi Rizzo static void 7372f345d8eSLuigi Rizzo oce_mq_free(struct oce_mq *mq) 7382f345d8eSLuigi Rizzo { 7392f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) mq->parent; 7402f345d8eSLuigi Rizzo struct oce_mbx mbx; 7412f345d8eSLuigi Rizzo struct mbx_destroy_common_mq *fwcmd; 7422f345d8eSLuigi Rizzo 7432f345d8eSLuigi Rizzo if (!mq) 7442f345d8eSLuigi Rizzo return; 7452f345d8eSLuigi Rizzo 7462f345d8eSLuigi Rizzo if (mq->ring != NULL) { 7472f345d8eSLuigi Rizzo oce_destroy_ring_buffer(sc, mq->ring); 7482f345d8eSLuigi Rizzo mq->ring = NULL; 7492f345d8eSLuigi Rizzo if (mq->qstate == QCREATED) { 7502f345d8eSLuigi Rizzo bzero(&mbx, sizeof (struct oce_mbx)); 7512f345d8eSLuigi Rizzo fwcmd = (struct mbx_destroy_common_mq *)&mbx.payload; 7522f345d8eSLuigi Rizzo fwcmd->params.req.id = mq->mq_id; 7532f345d8eSLuigi Rizzo (void) oce_destroy_q(sc, &mbx, 7542f345d8eSLuigi Rizzo sizeof (struct mbx_destroy_common_mq), 755c2625e6eSJosh Paetzel QTYPE_MQ, 0); 7562f345d8eSLuigi Rizzo } 7572f345d8eSLuigi Rizzo mq->qstate = QDELETED; 7582f345d8eSLuigi Rizzo } 7592f345d8eSLuigi Rizzo 7602f345d8eSLuigi Rizzo if (mq->cq != NULL) { 7612f345d8eSLuigi Rizzo oce_cq_del(sc, mq->cq); 7622f345d8eSLuigi Rizzo mq->cq = NULL; 7632f345d8eSLuigi Rizzo } 7642f345d8eSLuigi Rizzo 7652f345d8eSLuigi Rizzo free(mq, M_DEVBUF); 7662f345d8eSLuigi Rizzo mq = NULL; 7672f345d8eSLuigi Rizzo } 7682f345d8eSLuigi Rizzo 7692f345d8eSLuigi Rizzo /** 7702f345d8eSLuigi Rizzo * @brief Function to delete a EQ, CQ, MQ, WQ or RQ 7712f345d8eSLuigi Rizzo * @param sc sofware handle to the device 7722f345d8eSLuigi Rizzo * @param mbx mailbox command to send to the fw to delete the queue 7732f345d8eSLuigi Rizzo * (mbx contains the queue information to delete) 7742f345d8eSLuigi Rizzo * @param req_size the size of the mbx payload dependent on the qtype 7752f345d8eSLuigi Rizzo * @param qtype the type of queue i.e. EQ, CQ, MQ, WQ or RQ 7762f345d8eSLuigi Rizzo * @returns 0 on success, failure otherwise 7772f345d8eSLuigi Rizzo */ 7782f345d8eSLuigi Rizzo static int 7792f345d8eSLuigi Rizzo oce_destroy_q(POCE_SOFTC sc, struct oce_mbx *mbx, size_t req_size, 780c2625e6eSJosh Paetzel enum qtype qtype, int version) 7812f345d8eSLuigi Rizzo { 7822f345d8eSLuigi Rizzo struct mbx_hdr *hdr = (struct mbx_hdr *)&mbx->payload; 7832f345d8eSLuigi Rizzo int opcode; 7842f345d8eSLuigi Rizzo int subsys; 7852f345d8eSLuigi Rizzo int rc = 0; 7862f345d8eSLuigi Rizzo 7872f345d8eSLuigi Rizzo switch (qtype) { 7882f345d8eSLuigi Rizzo case QTYPE_EQ: 7892f345d8eSLuigi Rizzo opcode = OPCODE_COMMON_DESTROY_EQ; 7902f345d8eSLuigi Rizzo subsys = MBX_SUBSYSTEM_COMMON; 7912f345d8eSLuigi Rizzo break; 7922f345d8eSLuigi Rizzo case QTYPE_CQ: 7932f345d8eSLuigi Rizzo opcode = OPCODE_COMMON_DESTROY_CQ; 7942f345d8eSLuigi Rizzo subsys = MBX_SUBSYSTEM_COMMON; 7952f345d8eSLuigi Rizzo break; 7962f345d8eSLuigi Rizzo case QTYPE_MQ: 7972f345d8eSLuigi Rizzo opcode = OPCODE_COMMON_DESTROY_MQ; 7982f345d8eSLuigi Rizzo subsys = MBX_SUBSYSTEM_COMMON; 7992f345d8eSLuigi Rizzo break; 8002f345d8eSLuigi Rizzo case QTYPE_WQ: 8012f345d8eSLuigi Rizzo opcode = NIC_DELETE_WQ; 8022f345d8eSLuigi Rizzo subsys = MBX_SUBSYSTEM_NIC; 8032f345d8eSLuigi Rizzo break; 8042f345d8eSLuigi Rizzo case QTYPE_RQ: 8052f345d8eSLuigi Rizzo opcode = NIC_DELETE_RQ; 8062f345d8eSLuigi Rizzo subsys = MBX_SUBSYSTEM_NIC; 8072f345d8eSLuigi Rizzo break; 8082f345d8eSLuigi Rizzo default: 8092f345d8eSLuigi Rizzo return EINVAL; 8102f345d8eSLuigi Rizzo } 8112f345d8eSLuigi Rizzo 8122f345d8eSLuigi Rizzo mbx_common_req_hdr_init(hdr, 0, 0, subsys, 8132f345d8eSLuigi Rizzo opcode, MBX_TIMEOUT_SEC, req_size, 814c2625e6eSJosh Paetzel version); 8152f345d8eSLuigi Rizzo 8162f345d8eSLuigi Rizzo mbx->u0.s.embedded = 1; 8172f345d8eSLuigi Rizzo mbx->payload_length = (uint32_t) req_size; 8182f345d8eSLuigi Rizzo DW_SWAP(u32ptr(mbx), mbx->payload_length + OCE_BMBX_RHDR_SZ); 8192f345d8eSLuigi Rizzo 8202f345d8eSLuigi Rizzo rc = oce_mbox_post(sc, mbx, NULL); 821cdaba892SXin LI if (!rc) 822cdaba892SXin LI rc = hdr->u0.rsp.status; 823cdaba892SXin LI if (rc) 824cdaba892SXin LI device_printf(sc->dev,"%s failed - cmd status: %d\n", 825cdaba892SXin LI __FUNCTION__, rc); 8262f345d8eSLuigi Rizzo return rc; 8272f345d8eSLuigi Rizzo } 8282f345d8eSLuigi Rizzo 8292f345d8eSLuigi Rizzo /** 8302f345d8eSLuigi Rizzo * @brief Function to create a completion queue 8312f345d8eSLuigi Rizzo * @param sc software handle to the device 8322f345d8eSLuigi Rizzo * @param eq optional eq to be associated with to the cq 8332f345d8eSLuigi Rizzo * @param q_len length of completion queue 8342f345d8eSLuigi Rizzo * @param item_size size of completion queue items 8352f345d8eSLuigi Rizzo * @param sol_event command context event 8362f345d8eSLuigi Rizzo * @param is_eventable event table 8372f345d8eSLuigi Rizzo * @param nodelay no delay flag 8382f345d8eSLuigi Rizzo * @param ncoalesce no coalescence flag 8392f345d8eSLuigi Rizzo * @returns pointer to the cq created, NULL on failure 8402f345d8eSLuigi Rizzo */ 8412f345d8eSLuigi Rizzo struct oce_cq * 8422f345d8eSLuigi Rizzo oce_cq_create(POCE_SOFTC sc, struct oce_eq *eq, 8432f345d8eSLuigi Rizzo uint32_t q_len, 8442f345d8eSLuigi Rizzo uint32_t item_size, 8452f345d8eSLuigi Rizzo uint32_t sol_event, 8462f345d8eSLuigi Rizzo uint32_t is_eventable, 8472f345d8eSLuigi Rizzo uint32_t nodelay, uint32_t ncoalesce) 8482f345d8eSLuigi Rizzo { 8492f345d8eSLuigi Rizzo struct oce_cq *cq = NULL; 8502f345d8eSLuigi Rizzo int rc = 0; 8512f345d8eSLuigi Rizzo 8522f345d8eSLuigi Rizzo cq = malloc(sizeof(struct oce_cq), M_DEVBUF, M_NOWAIT | M_ZERO); 8532f345d8eSLuigi Rizzo if (!cq) 8542f345d8eSLuigi Rizzo return NULL; 8552f345d8eSLuigi Rizzo 8562f345d8eSLuigi Rizzo cq->ring = oce_create_ring_buffer(sc, q_len, item_size); 8572f345d8eSLuigi Rizzo if (!cq->ring) 8582f345d8eSLuigi Rizzo goto error; 8592f345d8eSLuigi Rizzo 8602f345d8eSLuigi Rizzo cq->parent = sc; 8612f345d8eSLuigi Rizzo cq->eq = eq; 8622f345d8eSLuigi Rizzo cq->cq_cfg.q_len = q_len; 8632f345d8eSLuigi Rizzo cq->cq_cfg.item_size = item_size; 8642f345d8eSLuigi Rizzo cq->cq_cfg.nodelay = (uint8_t) nodelay; 8652f345d8eSLuigi Rizzo 8662f345d8eSLuigi Rizzo rc = oce_mbox_cq_create(cq, ncoalesce, is_eventable); 8672f345d8eSLuigi Rizzo if (rc) 8682f345d8eSLuigi Rizzo goto error; 8692f345d8eSLuigi Rizzo 8702f345d8eSLuigi Rizzo sc->cq[sc->ncqs++] = cq; 8712f345d8eSLuigi Rizzo 8722f345d8eSLuigi Rizzo return cq; 8732f345d8eSLuigi Rizzo 8742f345d8eSLuigi Rizzo error: 8752f345d8eSLuigi Rizzo device_printf(sc->dev, "CQ create failed\n"); 8762f345d8eSLuigi Rizzo oce_cq_del(sc, cq); 8772f345d8eSLuigi Rizzo return NULL; 8782f345d8eSLuigi Rizzo } 8792f345d8eSLuigi Rizzo 8802f345d8eSLuigi Rizzo /** 8812f345d8eSLuigi Rizzo * @brief Deletes the completion queue 8822f345d8eSLuigi Rizzo * @param sc software handle to the device 8832f345d8eSLuigi Rizzo * @param cq pointer to a completion queue 8842f345d8eSLuigi Rizzo */ 8852f345d8eSLuigi Rizzo static void 8862f345d8eSLuigi Rizzo oce_cq_del(POCE_SOFTC sc, struct oce_cq *cq) 8872f345d8eSLuigi Rizzo { 8882f345d8eSLuigi Rizzo struct oce_mbx mbx; 8892f345d8eSLuigi Rizzo struct mbx_destroy_common_cq *fwcmd; 8902f345d8eSLuigi Rizzo 8912f345d8eSLuigi Rizzo if (cq->ring != NULL) { 8922f345d8eSLuigi Rizzo bzero(&mbx, sizeof(struct oce_mbx)); 8932f345d8eSLuigi Rizzo /* now fill the command */ 8942f345d8eSLuigi Rizzo fwcmd = (struct mbx_destroy_common_cq *)&mbx.payload; 8952f345d8eSLuigi Rizzo fwcmd->params.req.id = cq->cq_id; 8962f345d8eSLuigi Rizzo (void)oce_destroy_q(sc, &mbx, 897c2625e6eSJosh Paetzel sizeof(struct mbx_destroy_common_cq), QTYPE_CQ, 0); 8982f345d8eSLuigi Rizzo /*NOW destroy the ring */ 8992f345d8eSLuigi Rizzo oce_destroy_ring_buffer(sc, cq->ring); 9002f345d8eSLuigi Rizzo cq->ring = NULL; 9012f345d8eSLuigi Rizzo } 9022f345d8eSLuigi Rizzo 9032f345d8eSLuigi Rizzo free(cq, M_DEVBUF); 9042f345d8eSLuigi Rizzo cq = NULL; 9052f345d8eSLuigi Rizzo } 9062f345d8eSLuigi Rizzo 9072f345d8eSLuigi Rizzo /** 9082f345d8eSLuigi Rizzo * @brief Start a receive queue 9092f345d8eSLuigi Rizzo * @param rq pointer to a receive queue 9102f345d8eSLuigi Rizzo */ 9112f345d8eSLuigi Rizzo int 9122f345d8eSLuigi Rizzo oce_start_rq(struct oce_rq *rq) 9132f345d8eSLuigi Rizzo { 914c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 9152f345d8eSLuigi Rizzo int rc; 9162f345d8eSLuigi Rizzo 917c2625e6eSJosh Paetzel if(sc->enable_hwlro) 918c2625e6eSJosh Paetzel rc = oce_alloc_rx_bufs(rq, 960); 919c2625e6eSJosh Paetzel else 920c2625e6eSJosh Paetzel rc = oce_alloc_rx_bufs(rq, rq->cfg.q_len - 1); 9212f345d8eSLuigi Rizzo 9222f345d8eSLuigi Rizzo if (rc == 0) 9232f345d8eSLuigi Rizzo oce_arm_cq(rq->parent, rq->cq->cq_id, 0, TRUE); 924c2625e6eSJosh Paetzel 9252f345d8eSLuigi Rizzo return rc; 9262f345d8eSLuigi Rizzo } 9272f345d8eSLuigi Rizzo 9282f345d8eSLuigi Rizzo /** 9292f345d8eSLuigi Rizzo * @brief Start a work queue 9302f345d8eSLuigi Rizzo * @param wq pointer to a work queue 9312f345d8eSLuigi Rizzo */ 9322f345d8eSLuigi Rizzo int 9332f345d8eSLuigi Rizzo oce_start_wq(struct oce_wq *wq) 9342f345d8eSLuigi Rizzo { 9352f345d8eSLuigi Rizzo oce_arm_cq(wq->parent, wq->cq->cq_id, 0, TRUE); 9362f345d8eSLuigi Rizzo return 0; 9372f345d8eSLuigi Rizzo } 9382f345d8eSLuigi Rizzo 9392f345d8eSLuigi Rizzo /** 9402f345d8eSLuigi Rizzo * @brief Start a mailbox queue 9412f345d8eSLuigi Rizzo * @param mq pointer to a mailbox queue 9422f345d8eSLuigi Rizzo */ 9432f345d8eSLuigi Rizzo int 9442f345d8eSLuigi Rizzo oce_start_mq(struct oce_mq *mq) 9452f345d8eSLuigi Rizzo { 9462f345d8eSLuigi Rizzo oce_arm_cq(mq->parent, mq->cq->cq_id, 0, TRUE); 9472f345d8eSLuigi Rizzo return 0; 9482f345d8eSLuigi Rizzo } 9492f345d8eSLuigi Rizzo 9502f345d8eSLuigi Rizzo /** 9512f345d8eSLuigi Rizzo * @brief Function to arm an EQ so that it can generate events 9522f345d8eSLuigi Rizzo * @param sc software handle to the device 9532f345d8eSLuigi Rizzo * @param qid id of the EQ returned by the fw at the time of creation 9542f345d8eSLuigi Rizzo * @param npopped number of EQEs to arm 9552f345d8eSLuigi Rizzo * @param rearm rearm bit enable/disable 9562f345d8eSLuigi Rizzo * @param clearint bit to clear the interrupt condition because of which 9572f345d8eSLuigi Rizzo * EQEs are generated 9582f345d8eSLuigi Rizzo */ 9592f345d8eSLuigi Rizzo void 9602f345d8eSLuigi Rizzo oce_arm_eq(POCE_SOFTC sc, 9612f345d8eSLuigi Rizzo int16_t qid, int npopped, uint32_t rearm, uint32_t clearint) 9622f345d8eSLuigi Rizzo { 9632f345d8eSLuigi Rizzo eq_db_t eq_db = { 0 }; 9642f345d8eSLuigi Rizzo 9652f345d8eSLuigi Rizzo eq_db.bits.rearm = rearm; 9662f345d8eSLuigi Rizzo eq_db.bits.event = 1; 9672f345d8eSLuigi Rizzo eq_db.bits.num_popped = npopped; 9682f345d8eSLuigi Rizzo eq_db.bits.clrint = clearint; 9692f345d8eSLuigi Rizzo eq_db.bits.qid = qid; 9702f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_EQ_DB, eq_db.dw0); 9712f345d8eSLuigi Rizzo 9722f345d8eSLuigi Rizzo } 9732f345d8eSLuigi Rizzo 9742f345d8eSLuigi Rizzo /** 9752f345d8eSLuigi Rizzo * @brief Function to arm a CQ with CQEs 9762f345d8eSLuigi Rizzo * @param sc software handle to the device 9772f345d8eSLuigi Rizzo * @param qid id of the CQ returned by the fw at the time of creation 9782f345d8eSLuigi Rizzo * @param npopped number of CQEs to arm 9792f345d8eSLuigi Rizzo * @param rearm rearm bit enable/disable 9802f345d8eSLuigi Rizzo */ 9812f345d8eSLuigi Rizzo void oce_arm_cq(POCE_SOFTC sc, int16_t qid, int npopped, uint32_t rearm) 9822f345d8eSLuigi Rizzo { 9832f345d8eSLuigi Rizzo cq_db_t cq_db = { 0 }; 9842f345d8eSLuigi Rizzo 9852f345d8eSLuigi Rizzo cq_db.bits.rearm = rearm; 9862f345d8eSLuigi Rizzo cq_db.bits.num_popped = npopped; 9872f345d8eSLuigi Rizzo cq_db.bits.event = 0; 9882f345d8eSLuigi Rizzo cq_db.bits.qid = qid; 9892f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_CQ_DB, cq_db.dw0); 9902f345d8eSLuigi Rizzo 9912f345d8eSLuigi Rizzo } 9922f345d8eSLuigi Rizzo 9932f345d8eSLuigi Rizzo /* 9942f345d8eSLuigi Rizzo * @brief function to cleanup the eqs used during stop 9952f345d8eSLuigi Rizzo * @param eq pointer to event queue structure 9962f345d8eSLuigi Rizzo * @returns the number of EQs processed 9972f345d8eSLuigi Rizzo */ 9982f345d8eSLuigi Rizzo void 9992f345d8eSLuigi Rizzo oce_drain_eq(struct oce_eq *eq) 10002f345d8eSLuigi Rizzo { 10012f345d8eSLuigi Rizzo 10022f345d8eSLuigi Rizzo struct oce_eqe *eqe; 10032f345d8eSLuigi Rizzo uint16_t num_eqe = 0; 10042f345d8eSLuigi Rizzo POCE_SOFTC sc = eq->parent; 10052f345d8eSLuigi Rizzo 10062f345d8eSLuigi Rizzo do { 10072f345d8eSLuigi Rizzo eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 10082f345d8eSLuigi Rizzo if (eqe->evnt == 0) 10092f345d8eSLuigi Rizzo break; 10102f345d8eSLuigi Rizzo eqe->evnt = 0; 10112f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 10122f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 10132f345d8eSLuigi Rizzo num_eqe++; 10142f345d8eSLuigi Rizzo RING_GET(eq->ring, 1); 10152f345d8eSLuigi Rizzo 10162f345d8eSLuigi Rizzo } while (TRUE); 10172f345d8eSLuigi Rizzo 10182f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, num_eqe, FALSE, TRUE); 10192f345d8eSLuigi Rizzo 10202f345d8eSLuigi Rizzo } 10212f345d8eSLuigi Rizzo 10222f345d8eSLuigi Rizzo void 10232f345d8eSLuigi Rizzo oce_drain_wq_cq(struct oce_wq *wq) 10242f345d8eSLuigi Rizzo { 10252f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 10262f345d8eSLuigi Rizzo struct oce_cq *cq = wq->cq; 10272f345d8eSLuigi Rizzo struct oce_nic_tx_cqe *cqe; 10282f345d8eSLuigi Rizzo int num_cqes = 0; 10292f345d8eSLuigi Rizzo 10302f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, 10312f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 10322f345d8eSLuigi Rizzo 10332f345d8eSLuigi Rizzo do { 10342f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 10352f345d8eSLuigi Rizzo if (cqe->u0.dw[3] == 0) 10362f345d8eSLuigi Rizzo break; 10372f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 10382f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, cq->ring->dma.map, 10392f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 10402f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 10412f345d8eSLuigi Rizzo num_cqes++; 10422f345d8eSLuigi Rizzo 10432f345d8eSLuigi Rizzo } while (TRUE); 10442f345d8eSLuigi Rizzo 10452f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 10462f345d8eSLuigi Rizzo 10472f345d8eSLuigi Rizzo } 10482f345d8eSLuigi Rizzo 10492f345d8eSLuigi Rizzo /* 10502f345d8eSLuigi Rizzo * @brief function to drain a MCQ and process its CQEs 10512f345d8eSLuigi Rizzo * @param dev software handle to the device 10522f345d8eSLuigi Rizzo * @param cq pointer to the cq to drain 10532f345d8eSLuigi Rizzo * @returns the number of CQEs processed 10542f345d8eSLuigi Rizzo */ 10552f345d8eSLuigi Rizzo void 10562f345d8eSLuigi Rizzo oce_drain_mq_cq(void *arg) 10572f345d8eSLuigi Rizzo { 10582f345d8eSLuigi Rizzo /* TODO: additional code. */ 10592f345d8eSLuigi Rizzo return; 10602f345d8eSLuigi Rizzo } 10612f345d8eSLuigi Rizzo 10622f345d8eSLuigi Rizzo /** 10632f345d8eSLuigi Rizzo * @brief function to process a Recieve queue 10642f345d8eSLuigi Rizzo * @param arg pointer to the RQ to charge 10652f345d8eSLuigi Rizzo * @return number of cqes processed 10662f345d8eSLuigi Rizzo */ 10672f345d8eSLuigi Rizzo void 10682f345d8eSLuigi Rizzo oce_drain_rq_cq(struct oce_rq *rq) 10692f345d8eSLuigi Rizzo { 10702f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe; 10712f345d8eSLuigi Rizzo uint16_t num_cqe = 0; 10722f345d8eSLuigi Rizzo struct oce_cq *cq; 10732f345d8eSLuigi Rizzo POCE_SOFTC sc; 10742f345d8eSLuigi Rizzo 10752f345d8eSLuigi Rizzo sc = rq->parent; 10762f345d8eSLuigi Rizzo cq = rq->cq; 10772f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 10782f345d8eSLuigi Rizzo /* dequeue till you reach an invalid cqe */ 10792f345d8eSLuigi Rizzo while (RQ_CQE_VALID(cqe)) { 10802f345d8eSLuigi Rizzo RQ_CQE_INVALIDATE(cqe); 10812f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 10822f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, 10832f345d8eSLuigi Rizzo struct oce_nic_rx_cqe); 10842f345d8eSLuigi Rizzo num_cqe++; 10852f345d8eSLuigi Rizzo } 10862f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqe, FALSE); 10872f345d8eSLuigi Rizzo 10882f345d8eSLuigi Rizzo return; 10892f345d8eSLuigi Rizzo } 10902f345d8eSLuigi Rizzo 10912f345d8eSLuigi Rizzo void 10922f345d8eSLuigi Rizzo oce_free_posted_rxbuf(struct oce_rq *rq) 10932f345d8eSLuigi Rizzo { 10942f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 10952f345d8eSLuigi Rizzo 10962f345d8eSLuigi Rizzo while (rq->pending) { 1097c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 10982f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 10992f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 11002f345d8eSLuigi Rizzo if (pd->mbuf != NULL) { 11012f345d8eSLuigi Rizzo m_freem(pd->mbuf); 11022f345d8eSLuigi Rizzo pd->mbuf = NULL; 11032f345d8eSLuigi Rizzo } 11042f345d8eSLuigi Rizzo 1105c2625e6eSJosh Paetzel RING_GET(rq->ring,1); 11062f345d8eSLuigi Rizzo rq->pending--; 11072f345d8eSLuigi Rizzo } 11082f345d8eSLuigi Rizzo 11092f345d8eSLuigi Rizzo } 11102f345d8eSLuigi Rizzo 11112f345d8eSLuigi Rizzo void 1112c2625e6eSJosh Paetzel oce_rx_cq_clean_hwlro(struct oce_rq *rq) 1113c2625e6eSJosh Paetzel { 1114c2625e6eSJosh Paetzel struct oce_cq *cq = rq->cq; 1115c2625e6eSJosh Paetzel POCE_SOFTC sc = rq->parent; 1116c2625e6eSJosh Paetzel struct nic_hwlro_singleton_cqe *cqe; 1117c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part2 *cqe2; 1118c2625e6eSJosh Paetzel int flush_wait = 0; 1119c2625e6eSJosh Paetzel int flush_compl = 0; 1120c2625e6eSJosh Paetzel int num_frags = 0; 1121c2625e6eSJosh Paetzel 1122c2625e6eSJosh Paetzel for (;;) { 1123c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1124c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 1125c2625e6eSJosh Paetzel if(cqe->valid) { 1126c2625e6eSJosh Paetzel if(cqe->cqe_type == 0) { /* singleton cqe */ 1127c2625e6eSJosh Paetzel /* we should not get singleton cqe after cqe1 on same rq */ 1128c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) { 1129c2625e6eSJosh Paetzel device_printf(sc->dev, "Got singleton cqe after cqe1 \n"); 1130c2625e6eSJosh Paetzel goto exit_rx_cq_clean_hwlro; 1131c2625e6eSJosh Paetzel } 1132c2625e6eSJosh Paetzel num_frags = cqe->pkt_size / rq->cfg.frag_size; 1133c2625e6eSJosh Paetzel if(cqe->pkt_size % rq->cfg.frag_size) 1134c2625e6eSJosh Paetzel num_frags++; 1135c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, num_frags); 1136c2625e6eSJosh Paetzel /* Check if CQE is flush completion */ 1137c2625e6eSJosh Paetzel if(!cqe->pkt_size) 1138c2625e6eSJosh Paetzel flush_compl = 1; 1139c2625e6eSJosh Paetzel cqe->valid = 0; 1140c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 1141c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x1) { /* first part */ 1142c2625e6eSJosh Paetzel /* we should not get cqe1 after cqe1 on same rq */ 1143c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) { 1144c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe1 after cqe1 \n"); 1145c2625e6eSJosh Paetzel goto exit_rx_cq_clean_hwlro; 1146c2625e6eSJosh Paetzel } 1147c2625e6eSJosh Paetzel rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe; 1148c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 1149c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x2) { /* second part */ 1150c2625e6eSJosh Paetzel cqe2 = (struct nic_hwlro_cqe_part2 *)cqe; 1151c2625e6eSJosh Paetzel /* We should not get cqe2 without cqe1 */ 1152c2625e6eSJosh Paetzel if(rq->cqe_firstpart == NULL) { 1153c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe2 without cqe1 \n"); 1154c2625e6eSJosh Paetzel goto exit_rx_cq_clean_hwlro; 1155c2625e6eSJosh Paetzel } 1156c2625e6eSJosh Paetzel num_frags = cqe2->coalesced_size / rq->cfg.frag_size; 1157c2625e6eSJosh Paetzel if(cqe2->coalesced_size % rq->cfg.frag_size) 1158c2625e6eSJosh Paetzel num_frags++; 1159c2625e6eSJosh Paetzel 1160c2625e6eSJosh Paetzel /* Flush completion will always come in singleton CQE */ 1161c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, num_frags); 1162c2625e6eSJosh Paetzel 1163c2625e6eSJosh Paetzel rq->cqe_firstpart->valid = 0; 1164c2625e6eSJosh Paetzel cqe2->valid = 0; 1165c2625e6eSJosh Paetzel rq->cqe_firstpart = NULL; 1166c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 1167c2625e6eSJosh Paetzel } 1168c2625e6eSJosh Paetzel oce_arm_cq(sc, cq->cq_id, 1, FALSE); 1169c2625e6eSJosh Paetzel if(flush_compl) 1170c2625e6eSJosh Paetzel break; 1171c2625e6eSJosh Paetzel }else { 1172c2625e6eSJosh Paetzel if (flush_wait++ > 100) { 1173c2625e6eSJosh Paetzel device_printf(sc->dev, "did not receive hwlro flush compl\n"); 1174c2625e6eSJosh Paetzel break; 1175c2625e6eSJosh Paetzel } 1176c2625e6eSJosh Paetzel oce_arm_cq(sc, cq->cq_id, 0, TRUE); 1177c2625e6eSJosh Paetzel DELAY(1000); 1178c2625e6eSJosh Paetzel } 1179c2625e6eSJosh Paetzel } 1180c2625e6eSJosh Paetzel 1181c2625e6eSJosh Paetzel /* After cleanup, leave the CQ in unarmed state */ 1182c2625e6eSJosh Paetzel oce_arm_cq(sc, cq->cq_id, 0, FALSE); 1183c2625e6eSJosh Paetzel 1184c2625e6eSJosh Paetzel exit_rx_cq_clean_hwlro: 1185c2625e6eSJosh Paetzel return; 1186c2625e6eSJosh Paetzel } 1187c2625e6eSJosh Paetzel 1188c2625e6eSJosh Paetzel void 1189c2625e6eSJosh Paetzel oce_rx_cq_clean(struct oce_rq *rq) 1190c2625e6eSJosh Paetzel { 1191c2625e6eSJosh Paetzel struct oce_nic_rx_cqe *cqe; 1192c2625e6eSJosh Paetzel struct oce_cq *cq; 1193c2625e6eSJosh Paetzel POCE_SOFTC sc; 1194c2625e6eSJosh Paetzel int flush_wait = 0; 1195c2625e6eSJosh Paetzel int flush_compl = 0; 1196c2625e6eSJosh Paetzel sc = rq->parent; 1197c2625e6eSJosh Paetzel cq = rq->cq; 1198c2625e6eSJosh Paetzel 1199c2625e6eSJosh Paetzel for (;;) { 1200c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag, 1201c2625e6eSJosh Paetzel cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1202c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1203c2625e6eSJosh Paetzel if(RQ_CQE_VALID(cqe)) { 1204c2625e6eSJosh Paetzel DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1205c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1206c2625e6eSJosh Paetzel /* Check if CQE is flush completion */ 1207c2625e6eSJosh Paetzel if((cqe->u0.s.num_fragments==0)&&(cqe->u0.s.pkt_size == 0)&&(cqe->u0.s.error == 0)) 1208c2625e6eSJosh Paetzel flush_compl = 1; 1209c2625e6eSJosh Paetzel 1210c2625e6eSJosh Paetzel RQ_CQE_INVALIDATE(cqe); 1211c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 1212c2625e6eSJosh Paetzel #if defined(INET6) || defined(INET) 1213c2625e6eSJosh Paetzel if (IF_LRO_ENABLED(sc)) 1214c2625e6eSJosh Paetzel oce_rx_flush_lro(rq); 1215c2625e6eSJosh Paetzel #endif 1216c2625e6eSJosh Paetzel oce_arm_cq(sc, cq->cq_id, 1, FALSE); 1217c2625e6eSJosh Paetzel if(flush_compl) 1218c2625e6eSJosh Paetzel break; 1219c2625e6eSJosh Paetzel }else { 1220c2625e6eSJosh Paetzel if (flush_wait++ > 100) { 1221c2625e6eSJosh Paetzel device_printf(sc->dev, "did not receive flush compl\n"); 1222c2625e6eSJosh Paetzel break; 1223c2625e6eSJosh Paetzel } 1224c2625e6eSJosh Paetzel oce_arm_cq(sc, cq->cq_id, 0, TRUE); 1225c2625e6eSJosh Paetzel DELAY(1000); 1226c2625e6eSJosh Paetzel } 1227c2625e6eSJosh Paetzel } 1228c2625e6eSJosh Paetzel 1229c2625e6eSJosh Paetzel /* After cleanup, leave the CQ in unarmed state */ 1230c2625e6eSJosh Paetzel oce_arm_cq(sc, cq->cq_id, 0, FALSE); 1231c2625e6eSJosh Paetzel } 1232c2625e6eSJosh Paetzel 1233c2625e6eSJosh Paetzel void 12342f345d8eSLuigi Rizzo oce_stop_rx(POCE_SOFTC sc) 12352f345d8eSLuigi Rizzo { 1236*e363f832SMichael Tuexen struct epoch_tracker et; 12372f345d8eSLuigi Rizzo struct oce_mbx mbx; 12382f345d8eSLuigi Rizzo struct mbx_delete_nic_rq *fwcmd; 1239c2625e6eSJosh Paetzel struct mbx_delete_nic_rq_v1 *fwcmd1; 12402f345d8eSLuigi Rizzo struct oce_rq *rq; 12412f345d8eSLuigi Rizzo int i = 0; 12422f345d8eSLuigi Rizzo 1243*e363f832SMichael Tuexen NET_EPOCH_ENTER(et); 1244c2625e6eSJosh Paetzel /* before deleting disable hwlro */ 1245c2625e6eSJosh Paetzel if(sc->enable_hwlro) 1246c2625e6eSJosh Paetzel oce_mbox_nic_set_iface_lro_config(sc, 0); 1247c2625e6eSJosh Paetzel 12482f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 12492f345d8eSLuigi Rizzo if (rq->qstate == QCREATED) { 12502f345d8eSLuigi Rizzo /* Delete rxq in firmware */ 1251c2625e6eSJosh Paetzel LOCK(&rq->rx_lock); 12522f345d8eSLuigi Rizzo 12532f345d8eSLuigi Rizzo bzero(&mbx, sizeof(mbx)); 1254c2625e6eSJosh Paetzel if(!rq->islro) { 12552f345d8eSLuigi Rizzo fwcmd = (struct mbx_delete_nic_rq *)&mbx.payload; 12562f345d8eSLuigi Rizzo fwcmd->params.req.rq_id = rq->rq_id; 1257c2625e6eSJosh Paetzel (void)oce_destroy_q(sc, &mbx, sizeof(struct mbx_delete_nic_rq), QTYPE_RQ, 0); 1258c2625e6eSJosh Paetzel }else { 1259c2625e6eSJosh Paetzel fwcmd1 = (struct mbx_delete_nic_rq_v1 *)&mbx.payload; 1260c2625e6eSJosh Paetzel fwcmd1->params.req.rq_id = rq->rq_id; 1261c2625e6eSJosh Paetzel fwcmd1->params.req.rq_flags = (NIC_RQ_FLAGS_RSS | NIC_RQ_FLAGS_LRO); 12622f345d8eSLuigi Rizzo 1263c2625e6eSJosh Paetzel (void)oce_destroy_q(sc,&mbx,sizeof(struct mbx_delete_nic_rq_v1),QTYPE_RQ,1); 1264c2625e6eSJosh Paetzel } 12652f345d8eSLuigi Rizzo rq->qstate = QDELETED; 12662f345d8eSLuigi Rizzo 1267c2625e6eSJosh Paetzel DELAY(1000); 1268c2625e6eSJosh Paetzel 1269c2625e6eSJosh Paetzel if(!rq->islro) 1270c2625e6eSJosh Paetzel oce_rx_cq_clean(rq); 1271c2625e6eSJosh Paetzel else 1272c2625e6eSJosh Paetzel oce_rx_cq_clean_hwlro(rq); 12732f345d8eSLuigi Rizzo 12742f345d8eSLuigi Rizzo /* Free posted RX buffers that are not used */ 12752f345d8eSLuigi Rizzo oce_free_posted_rxbuf(rq); 1276c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock); 12772f345d8eSLuigi Rizzo } 12782f345d8eSLuigi Rizzo } 1279*e363f832SMichael Tuexen NET_EPOCH_EXIT(et); 12802f345d8eSLuigi Rizzo } 12812f345d8eSLuigi Rizzo 12822f345d8eSLuigi Rizzo int 12832f345d8eSLuigi Rizzo oce_start_rx(POCE_SOFTC sc) 12842f345d8eSLuigi Rizzo { 12852f345d8eSLuigi Rizzo struct oce_rq *rq; 12862f345d8eSLuigi Rizzo int rc = 0, i; 12872f345d8eSLuigi Rizzo 12882f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 12892f345d8eSLuigi Rizzo if (rq->qstate == QCREATED) 12902f345d8eSLuigi Rizzo continue; 1291c2625e6eSJosh Paetzel if((i == 0) || (!sc->enable_hwlro)) { 12922f345d8eSLuigi Rizzo rc = oce_mbox_create_rq(rq); 12932f345d8eSLuigi Rizzo if (rc) 12942f345d8eSLuigi Rizzo goto error; 1295c2625e6eSJosh Paetzel rq->islro = 0; 1296c2625e6eSJosh Paetzel }else { 1297c2625e6eSJosh Paetzel rc = oce_mbox_create_rq_v2(rq); 1298c2625e6eSJosh Paetzel if (rc) 1299c2625e6eSJosh Paetzel goto error; 1300c2625e6eSJosh Paetzel rq->islro = 1; 1301c2625e6eSJosh Paetzel } 13022f345d8eSLuigi Rizzo /* reset queue pointers */ 13032f345d8eSLuigi Rizzo rq->qstate = QCREATED; 13042f345d8eSLuigi Rizzo rq->pending = 0; 13052f345d8eSLuigi Rizzo rq->ring->cidx = 0; 13062f345d8eSLuigi Rizzo rq->ring->pidx = 0; 1307c2625e6eSJosh Paetzel } 1308c2625e6eSJosh Paetzel 1309c2625e6eSJosh Paetzel if(sc->enable_hwlro) { 1310c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 1); 1311c2625e6eSJosh Paetzel if (rc) 1312c2625e6eSJosh Paetzel goto error; 13132f345d8eSLuigi Rizzo } 13142f345d8eSLuigi Rizzo 13152f345d8eSLuigi Rizzo DELAY(1); 13162f345d8eSLuigi Rizzo 13172f345d8eSLuigi Rizzo /* RSS config */ 1318291a1934SXin LI if (is_rss_enabled(sc)) { 13192f345d8eSLuigi Rizzo rc = oce_config_nic_rss(sc, (uint8_t) sc->if_id, RSS_ENABLE); 13202f345d8eSLuigi Rizzo if (rc) 13212f345d8eSLuigi Rizzo goto error; 13222f345d8eSLuigi Rizzo } 13232f345d8eSLuigi Rizzo 1324c2625e6eSJosh Paetzel DELAY(1); 13252f345d8eSLuigi Rizzo return rc; 13262f345d8eSLuigi Rizzo error: 13272f345d8eSLuigi Rizzo device_printf(sc->dev, "Start RX failed\n"); 13282f345d8eSLuigi Rizzo return rc; 13292f345d8eSLuigi Rizzo 13302f345d8eSLuigi Rizzo } 1331