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