get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/8530/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 8530,
    "url": "https://patches.dpdk.org/api/patches/8530/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1446467130-300-3-git-send-email-alejandro.lucero@netronome.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1446467130-300-3-git-send-email-alejandro.lucero@netronome.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1446467130-300-3-git-send-email-alejandro.lucero@netronome.com",
    "date": "2015-11-02T12:25:22",
    "name": "[dpdk-dev,v5,2/9] nfp: rx/tx functionality",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "f3152c734788b12d54d11b4e7e867ffdc79ed648",
    "submitter": {
        "id": 270,
        "url": "https://patches.dpdk.org/api/people/270/?format=api",
        "name": "Alejandro Lucero",
        "email": "alejandro.lucero@netronome.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1446467130-300-3-git-send-email-alejandro.lucero@netronome.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/8530/comments/",
    "check": "pending",
    "checks": "https://patches.dpdk.org/api/patches/8530/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 28B078F9D;\n\tMon,  2 Nov 2015 13:25:37 +0100 (CET)",
            "from ubuntu (host217-39-174-19.in-addr.btopenworld.com\n\t[217.39.174.19]) by dpdk.org (Postfix) with SMTP id D31EC8E88\n\tfor <dev@dpdk.org>; Mon,  2 Nov 2015 13:25:30 +0100 (CET)",
            "by ubuntu (Postfix, from userid 5466)\n\tid 2F742E92E4; Mon,  2 Nov 2015 12:25:30 +0000 (GMT)"
        ],
        "From": "\"Alejandro.Lucero\" <alejandro.lucero@netronome.com>",
        "To": "dev@dpdk.org",
        "Date": "Mon,  2 Nov 2015 12:25:22 +0000",
        "Message-Id": "<1446467130-300-3-git-send-email-alejandro.lucero@netronome.com>",
        "X-Mailer": "git-send-email 1.7.9.5",
        "In-Reply-To": "<1446467130-300-1-git-send-email-alejandro.lucero@netronome.com>",
        "References": "<1446467130-300-1-git-send-email-alejandro.lucero@netronome.com>",
        "Subject": "[dpdk-dev] [PATCH v5 2/9] nfp: rx/tx functionality",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: \"Alejandro.Lucero\" <alejandro.lucero@netronome.com>\n\nSigned-off-by: Alejandro.Lucero <alejandro.lucero@netronome.com>\nSigned-off-by: Rolf.Neugebauer <rolf.neugebauer@netronome.com>\n---\n drivers/net/nfp/nfp_net.c |  921 +++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 921 insertions(+)",
    "diff": "diff --git a/drivers/net/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c\nindex a33ed37..8339c2d 100644\n--- a/drivers/net/nfp/nfp_net.c\n+++ b/drivers/net/nfp/nfp_net.c\n@@ -212,6 +212,100 @@ nn_cfg_writeq(struct nfp_net_hw *hw, int off, uint64_t val)\n \tnn_writeq(rte_cpu_to_le_64(val), hw->ctrl_bar + off);\n }\n \n+/* Creating memzone for hardware rings. */\n+static const struct rte_memzone *\n+ring_dma_zone_reserve(struct rte_eth_dev *dev, const char *ring_name,\n+\t\t      uint16_t queue_id, uint32_t ring_size, int socket_id)\n+{\n+\tchar z_name[RTE_MEMZONE_NAMESIZE];\n+\tconst struct rte_memzone *mz;\n+\n+\tsnprintf(z_name, sizeof(z_name), \"%s_%s_%d_%d\",\n+\t\t dev->driver->pci_drv.name,\n+\t\t ring_name, dev->data->port_id, queue_id);\n+\n+\tmz = rte_memzone_lookup(z_name);\n+\tif (mz)\n+\t\treturn mz;\n+\n+\treturn rte_memzone_reserve_aligned(z_name, ring_size, socket_id, 0,\n+\t\t\t\t\t   NFP_MEMZONE_ALIGN);\n+}\n+\n+static void\n+nfp_net_rx_queue_release_mbufs(struct nfp_net_rxq *rxq)\n+{\n+\tunsigned i;\n+\n+\tif (rxq->rxbufs == NULL)\n+\t\treturn;\n+\n+\tfor (i = 0; i < rxq->rx_count; i++) {\n+\t\tif (rxq->rxbufs[i].mbuf) {\n+\t\t\trte_pktmbuf_free_seg(rxq->rxbufs[i].mbuf);\n+\t\t\trxq->rxbufs[i].mbuf = NULL;\n+\t\t}\n+\t}\n+}\n+\n+static void\n+nfp_net_rx_queue_release(void *rx_queue)\n+{\n+\tstruct nfp_net_rxq *rxq = rx_queue;\n+\n+\tif (rxq) {\n+\t\tnfp_net_rx_queue_release_mbufs(rxq);\n+\t\trte_free(rxq->rxbufs);\n+\t\trte_free(rxq);\n+\t}\n+}\n+\n+static void\n+nfp_net_reset_rx_queue(struct nfp_net_rxq *rxq)\n+{\n+\tnfp_net_rx_queue_release_mbufs(rxq);\n+\trxq->wr_p = 0;\n+\trxq->rd_p = 0;\n+\trxq->nb_rx_hold = 0;\n+}\n+\n+static void\n+nfp_net_tx_queue_release_mbufs(struct nfp_net_txq *txq)\n+{\n+\tunsigned i;\n+\n+\tif (txq->txbufs == NULL)\n+\t\treturn;\n+\n+\tfor (i = 0; i < txq->tx_count; i++) {\n+\t\tif (txq->txbufs[i].mbuf) {\n+\t\t\trte_pktmbuf_free_seg(txq->txbufs[i].mbuf);\n+\t\t\ttxq->txbufs[i].mbuf = NULL;\n+\t\t}\n+\t}\n+}\n+\n+static void\n+nfp_net_tx_queue_release(void *tx_queue)\n+{\n+\tstruct nfp_net_txq *txq = tx_queue;\n+\n+\tif (txq) {\n+\t\tnfp_net_tx_queue_release_mbufs(txq);\n+\t\trte_free(txq->txbufs);\n+\t\trte_free(txq);\n+\t}\n+}\n+\n+static void\n+nfp_net_reset_tx_queue(struct nfp_net_txq *txq)\n+{\n+\tnfp_net_tx_queue_release_mbufs(txq);\n+\ttxq->wr_p = 0;\n+\ttxq->rd_p = 0;\n+\ttxq->tail = 0;\n+}\n+\n static int\n __nfp_net_reconfig(struct nfp_net_hw *hw, uint32_t update)\n {\n@@ -449,6 +543,18 @@ nfp_net_disable_queues(struct rte_eth_dev *dev)\n \thw->ctrl = new_ctrl;\n }\n \n+static int\n+nfp_net_rx_freelist_setup(struct rte_eth_dev *dev)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < dev->data->nb_rx_queues; i++) {\n+\t\tif (nfp_net_rx_fill_freelist(dev->data->rx_queues[i]) < 0)\n+\t\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n static void\n nfp_net_params_setup(struct nfp_net_hw *hw)\n {\n@@ -582,6 +688,821 @@ nfp_net_close(struct rte_eth_dev *dev)\n \t */\n }\n \n+static uint32_t\n+nfp_net_rx_queue_count(struct rte_eth_dev *dev, uint16_t queue_idx)\n+{\n+\tstruct nfp_net_rxq *rxq;\n+\tstruct nfp_net_rx_desc *rxds;\n+\tuint32_t idx;\n+\tuint32_t count;\n+\n+\trxq = (struct nfp_net_rxq *)dev->data->rx_queues[queue_idx];\n+\n+\tif (rxq == NULL) {\n+\t\tPMD_INIT_LOG(ERR, \"Bad queue: %u\\n\", queue_idx);\n+\t\treturn 0;\n+\t}\n+\n+\tidx = rxq->rd_p % rxq->rx_count;\n+\trxds = &rxq->rxds[idx];\n+\n+\tcount = 0;\n+\n+\t/*\n+\t * Other PMDs are just checking the DD bit in intervals of 4\n+\t * descriptors and counting all four if the first has the DD\n+\t * bit on. Of course, this is not accurate but can be good for\n+\t * perfomance. But ideally that should be done in descriptors\n+\t * chunks belonging to the same cache line\n+\t */\n+\n+\twhile (count < rxq->rx_count) {\n+\t\trxds = &rxq->rxds[idx];\n+\t\tif ((rxds->rxd.meta_len_dd & PCIE_DESC_RX_DD) == 0)\n+\t\t\tbreak;\n+\n+\t\tcount++;\n+\t\tidx++;\n+\n+\t\t/* Wrapping? */\n+\t\tif ((idx) == rxq->rx_count)\n+\t\t\tidx = 0;\n+\t}\n+\n+\treturn count;\n+}\n+\n+static int\n+nfp_net_rx_queue_setup(struct rte_eth_dev *dev,\n+\t\t       uint16_t queue_idx, uint16_t nb_desc,\n+\t\t       unsigned int socket_id,\n+\t\t       const struct rte_eth_rxconf *rx_conf,\n+\t\t       struct rte_mempool *mp)\n+{\n+\tconst struct rte_memzone *tz;\n+\tstruct nfp_net_rxq *rxq;\n+\tstruct nfp_net_hw *hw;\n+\n+\thw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\t/* Validating number of descriptors */\n+\tif (((nb_desc * sizeof(struct nfp_net_rx_desc)) % 128) != 0 ||\n+\t    (nb_desc > NFP_NET_MAX_RX_DESC) ||\n+\t    (nb_desc < NFP_NET_MIN_RX_DESC)) {\n+\t\tRTE_LOG(ERR, PMD, \"Wrong nb_desc value\\n\");\n+\t\treturn (-EINVAL);\n+\t}\n+\n+\t/*\n+\t * Free memory prior to re-allocation if needed. This is the case after\n+\t * calling nfp_net_stop\n+\t */\n+\tif (dev->data->rx_queues[queue_idx]) {\n+\t\tnfp_net_rx_queue_release(dev->data->rx_queues[queue_idx]);\n+\t\tdev->data->rx_queues[queue_idx] = NULL;\n+\t}\n+\n+\t/* Allocating rx queue data structure */\n+\trxq = rte_zmalloc_socket(\"ethdev RX queue\", sizeof(struct nfp_net_rxq),\n+\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (rxq == NULL)\n+\t\treturn (-ENOMEM);\n+\n+\t/* Hw queues mapping based on firmware confifguration */\n+\trxq->qidx = queue_idx;\n+\trxq->fl_qcidx = queue_idx * hw->stride_rx;\n+\trxq->rx_qcidx = rxq->fl_qcidx + (hw->stride_rx - 1);\n+\trxq->qcp_fl = hw->rx_bar + NFP_QCP_QUEUE_OFF(rxq->fl_qcidx);\n+\trxq->qcp_rx = hw->rx_bar + NFP_QCP_QUEUE_OFF(rxq->rx_qcidx);\n+\n+\t/*\n+\t * Tracking mbuf size for detecting a potential mbuf overflow due to\n+\t * NFP_NET_RX_OFFSET\n+\t */\n+\trxq->mem_pool = mp;\n+\trxq->mbuf_size = rxq->mem_pool->elt_size;\n+\trxq->mbuf_size -= (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM);\n+\thw->flbufsz = rxq->mbuf_size;\n+\n+\trxq->rx_count = nb_desc;\n+\trxq->port_id = dev->data->port_id;\n+\trxq->rx_free_thresh = rx_conf->rx_free_thresh;\n+\trxq->drop_en = rx_conf->rx_drop_en;\n+\n+\t/*\n+\t * Allocate RX ring hardware descriptors. A memzone large enough to\n+\t * handle the maximum ring size is allocated in order to allow for\n+\t * resizing in later calls to the queue setup function.\n+\t */\n+\ttz = ring_dma_zone_reserve(dev, \"rx_ring\", queue_idx,\n+\t\t\t\t   sizeof(struct nfp_net_rx_desc) *\n+\t\t\t\t   NFP_NET_MAX_RX_DESC, socket_id);\n+\n+\tif (tz == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"Error allocatig rx dma\\n\");\n+\t\tnfp_net_rx_queue_release(rxq);\n+\t\treturn (-ENOMEM);\n+\t}\n+\n+\t/* Saving physical and virtual addresses for the RX ring */\n+\trxq->dma = (uint64_t)tz->phys_addr;\n+\trxq->rxds = (struct nfp_net_rx_desc *)tz->addr;\n+\n+\t/* mbuf pointers array for referencing mbufs linked to RX descriptors */\n+\trxq->rxbufs = rte_zmalloc_socket(\"rxq->rxbufs\",\n+\t\t\t\t\t sizeof(*rxq->rxbufs) * nb_desc,\n+\t\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (rxq->rxbufs == NULL) {\n+\t\tnfp_net_rx_queue_release(rxq);\n+\t\treturn (-ENOMEM);\n+\t}\n+\n+\tPMD_RX_LOG(DEBUG, \"rxbufs=%p hw_ring=%p dma_addr=0x%\" PRIx64 \"\\n\",\n+\t\t   rxq->rxbufs, rxq->rxds, (unsigned long int)rxq->dma);\n+\n+\tnfp_net_reset_rx_queue(rxq);\n+\n+\tdev->data->rx_queues[queue_idx] = rxq;\n+\trxq->hw = hw;\n+\n+\t/*\n+\t * Telling the HW about the physical address of the RX ring and number\n+\t * of descriptors in log2 format\n+\t */\n+\tnn_cfg_writeq(hw, NFP_NET_CFG_RXR_ADDR(queue_idx), rxq->dma);\n+\tnn_cfg_writeb(hw, NFP_NET_CFG_RXR_SZ(queue_idx), log2(nb_desc));\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_net_rx_fill_freelist(struct nfp_net_rxq *rxq)\n+{\n+\tstruct nfp_net_rx_buff *rxe = rxq->rxbufs;\n+\tuint64_t dma_addr;\n+\tunsigned i;\n+\n+\tPMD_RX_LOG(DEBUG, \"nfp_net_rx_fill_freelist for %u descriptors\\n\",\n+\t\t   rxq->rx_count);\n+\n+\tfor (i = 0; i < rxq->rx_count; i++) {\n+\t\tstruct nfp_net_rx_desc *rxd;\n+\t\tstruct rte_mbuf *mbuf = rte_pktmbuf_alloc(rxq->mem_pool);\n+\n+\t\tif (mbuf == NULL) {\n+\t\t\tRTE_LOG(ERR, PMD, \"RX mbuf alloc failed queue_id=%u\\n\",\n+\t\t\t\t(unsigned)rxq->qidx);\n+\t\t\treturn (-ENOMEM);\n+\t\t}\n+\n+\t\tdma_addr = rte_cpu_to_le_64(RTE_MBUF_DMA_ADDR_DEFAULT(mbuf));\n+\n+\t\trxd = &rxq->rxds[i];\n+\t\trxd->fld.dd = 0;\n+\t\trxd->fld.dma_addr_hi = (dma_addr >> 32) & 0xff;\n+\t\trxd->fld.dma_addr_lo = dma_addr & 0xffffffff;\n+\t\trxe[i].mbuf = mbuf;\n+\t\tPMD_RX_LOG(DEBUG, \"[%d]: %\" PRIx64 \"\\n\", i, dma_addr);\n+\n+\t\trxq->wr_p++;\n+\t}\n+\n+\t/* Make sure all writes are flushed before telling the hardware */\n+\trte_wmb();\n+\n+\t/* Not advertising the whole ring as the firmware gets confused if so */\n+\tPMD_RX_LOG(DEBUG, \"Increment FL write pointer in %u\\n\",\n+\t\t   rxq->rx_count - 1);\n+\n+\tnfp_qcp_ptr_add(rxq->qcp_fl, NFP_QCP_WRITE_PTR, rxq->rx_count - 1);\n+\n+\treturn 0;\n+}\n+\n+static int\n+nfp_net_tx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx,\n+\t\t       uint16_t nb_desc, unsigned int socket_id,\n+\t\t       const struct rte_eth_txconf *tx_conf)\n+{\n+\tconst struct rte_memzone *tz;\n+\tstruct nfp_net_txq *txq;\n+\tuint16_t tx_free_thresh;\n+\tstruct nfp_net_hw *hw;\n+\n+\thw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);\n+\n+\tPMD_INIT_FUNC_TRACE();\n+\n+\t/* Validating number of descriptors */\n+\tif (((nb_desc * sizeof(struct nfp_net_tx_desc)) % 128) != 0 ||\n+\t    (nb_desc > NFP_NET_MAX_TX_DESC) ||\n+\t    (nb_desc < NFP_NET_MIN_TX_DESC)) {\n+\t\tRTE_LOG(ERR, PMD, \"Wrong nb_desc value\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\ttx_free_thresh = (uint16_t)((tx_conf->tx_free_thresh) ?\n+\t\t\t\t    tx_conf->tx_free_thresh :\n+\t\t\t\t    DEFAULT_TX_FREE_THRESH);\n+\n+\tif (tx_free_thresh > (nb_desc)) {\n+\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\"tx_free_thresh must be less than the number of TX \"\n+\t\t\t\"descriptors. (tx_free_thresh=%u port=%d \"\n+\t\t\t\"queue=%d)\\n\", (unsigned int)tx_free_thresh,\n+\t\t\t(int)dev->data->port_id, (int)queue_idx);\n+\t\treturn -(EINVAL);\n+\t}\n+\n+\t/*\n+\t * Free memory prior to re-allocation if needed. This is the case after\n+\t * calling nfp_net_stop\n+\t */\n+\tif (dev->data->tx_queues[queue_idx]) {\n+\t\tPMD_TX_LOG(DEBUG, \"Freeing memory prior to re-allocation %d\\n\",\n+\t\t\t   queue_idx);\n+\t\tnfp_net_tx_queue_release(dev->data->tx_queues[queue_idx]);\n+\t\tdev->data->tx_queues[queue_idx] = NULL;\n+\t}\n+\n+\t/* Allocating tx queue data structure */\n+\ttxq = rte_zmalloc_socket(\"ethdev TX queue\", sizeof(struct nfp_net_txq),\n+\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (txq == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"Error allocating tx dma\\n\");\n+\t\treturn (-ENOMEM);\n+\t}\n+\n+\t/*\n+\t * Allocate TX ring hardware descriptors. A memzone large enough to\n+\t * handle the maximum ring size is allocated in order to allow for\n+\t * resizing in later calls to the queue setup function.\n+\t */\n+\ttz = ring_dma_zone_reserve(dev, \"tx_ring\", queue_idx,\n+\t\t\t\t   sizeof(struct nfp_net_tx_desc) *\n+\t\t\t\t   NFP_NET_MAX_TX_DESC, socket_id);\n+\tif (tz == NULL) {\n+\t\tRTE_LOG(ERR, PMD, \"Error allocating tx dma\\n\");\n+\t\tnfp_net_tx_queue_release(txq);\n+\t\treturn (-ENOMEM);\n+\t}\n+\n+\ttxq->tx_count = nb_desc;\n+\ttxq->tx_free_thresh = tx_free_thresh;\n+\ttxq->tx_pthresh = tx_conf->tx_thresh.pthresh;\n+\ttxq->tx_hthresh = tx_conf->tx_thresh.hthresh;\n+\ttxq->tx_wthresh = tx_conf->tx_thresh.wthresh;\n+\n+\t/* queue mapping based on firmware configuration */\n+\ttxq->qidx = queue_idx;\n+\ttxq->tx_qcidx = queue_idx * hw->stride_tx;\n+\ttxq->qcp_q = hw->tx_bar + NFP_QCP_QUEUE_OFF(txq->tx_qcidx);\n+\n+\ttxq->port_id = dev->data->port_id;\n+\ttxq->txq_flags = tx_conf->txq_flags;\n+\n+\t/* Saving physical and virtual addresses for the TX ring */\n+\ttxq->dma = (uint64_t)tz->phys_addr;\n+\ttxq->txds = (struct nfp_net_tx_desc *)tz->addr;\n+\n+\t/* mbuf pointers array for referencing mbufs linked to TX descriptors */\n+\ttxq->txbufs = rte_zmalloc_socket(\"txq->txbufs\",\n+\t\t\t\t\t sizeof(*txq->txbufs) * nb_desc,\n+\t\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (txq->txbufs == NULL) {\n+\t\tnfp_net_tx_queue_release(txq);\n+\t\treturn (-ENOMEM);\n+\t}\n+\tPMD_TX_LOG(DEBUG, \"txbufs=%p hw_ring=%p dma_addr=0x%\" PRIx64 \"\\n\",\n+\t\t   txq->txbufs, txq->txds, (unsigned long int)txq->dma);\n+\n+\tnfp_net_reset_tx_queue(txq);\n+\n+\tdev->data->tx_queues[queue_idx] = txq;\n+\ttxq->hw = hw;\n+\n+\t/*\n+\t * Telling the HW about the physical address of the TX ring and number\n+\t * of descriptors in log2 format\n+\t */\n+\tnn_cfg_writeq(hw, NFP_NET_CFG_TXR_ADDR(queue_idx), txq->dma);\n+\tnn_cfg_writeb(hw, NFP_NET_CFG_TXR_SZ(queue_idx), log2(nb_desc));\n+\n+\treturn 0;\n+}\n+\n+/* nfp_net_tx_cksum - Set TX CSUM offload flags in TX descriptor */\n+static inline void\n+nfp_net_tx_cksum(struct nfp_net_txq *txq, struct nfp_net_tx_desc *txd,\n+\t\t struct rte_mbuf *mb)\n+{\n+\tuint16_t ol_flags;\n+\tstruct nfp_net_hw *hw = txq->hw;\n+\n+\tif (!(hw->cap & NFP_NET_CFG_CTRL_TXCSUM))\n+\t\treturn;\n+\n+\tol_flags = mb->ol_flags;\n+\n+\t/* IPv6 does not need checksum */\n+\tif (ol_flags & PKT_TX_IP_CKSUM)\n+\t\ttxd->flags |= PCIE_DESC_TX_IP4_CSUM;\n+\n+\tswitch (ol_flags & PKT_TX_L4_MASK) {\n+\tcase PKT_TX_UDP_CKSUM:\n+\t\ttxd->flags |= PCIE_DESC_TX_UDP_CSUM;\n+\t\tbreak;\n+\tcase PKT_TX_TCP_CKSUM:\n+\t\ttxd->flags |= PCIE_DESC_TX_TCP_CSUM;\n+\t\tbreak;\n+\t}\n+\n+\ttxd->flags |= PCIE_DESC_TX_CSUM;\n+}\n+\n+/* nfp_net_rx_cksum - set mbuf checksum flags based on RX descriptor flags */\n+static inline void\n+nfp_net_rx_cksum(struct nfp_net_rxq *rxq, struct nfp_net_rx_desc *rxd,\n+\t\t struct rte_mbuf *mb)\n+{\n+\tstruct nfp_net_hw *hw = rxq->hw;\n+\n+\tif (!(hw->ctrl & NFP_NET_CFG_CTRL_RXCSUM))\n+\t\treturn;\n+\n+\t/* If IPv4 and IP checksum error, fail */\n+\tif ((rxd->rxd.flags & PCIE_DESC_RX_IP4_CSUM) &&\n+\t    !(rxd->rxd.flags & PCIE_DESC_RX_IP4_CSUM_OK))\n+\t\tmb->ol_flags |= PKT_RX_IP_CKSUM_BAD;\n+\n+\t/* If neither UDP nor TCP return */\n+\tif (!(rxd->rxd.flags & PCIE_DESC_RX_TCP_CSUM) &&\n+\t    !(rxd->rxd.flags & PCIE_DESC_RX_UDP_CSUM))\n+\t\treturn;\n+\n+\tif ((rxd->rxd.flags & PCIE_DESC_RX_TCP_CSUM) &&\n+\t    !(rxd->rxd.flags & PCIE_DESC_RX_TCP_CSUM_OK))\n+\t\tmb->ol_flags |= PKT_RX_L4_CKSUM_BAD;\n+\n+\tif ((rxd->rxd.flags & PCIE_DESC_RX_UDP_CSUM) &&\n+\t    !(rxd->rxd.flags & PCIE_DESC_RX_UDP_CSUM_OK))\n+\t\tmb->ol_flags |= PKT_RX_L4_CKSUM_BAD;\n+}\n+\n+#define NFP_HASH_OFFSET      ((uint8_t *)mbuf->buf_addr + mbuf->data_off - 4)\n+#define NFP_HASH_TYPE_OFFSET ((uint8_t *)mbuf->buf_addr + mbuf->data_off - 8)\n+\n+/*\n+ * nfp_net_set_hash - Set mbuf hash data\n+ *\n+ * The RSS hash and hash-type are pre-pended to the packet data.\n+ * Extract and decode it and set the mbuf fields.\n+ */\n+static inline void\n+nfp_net_set_hash(struct nfp_net_rxq *rxq, struct nfp_net_rx_desc *rxd,\n+\t\t struct rte_mbuf *mbuf)\n+{\n+\tuint32_t hash;\n+\tuint32_t hash_type;\n+\tstruct nfp_net_hw *hw = rxq->hw;\n+\n+\tif (!(hw->ctrl & NFP_NET_CFG_CTRL_RSS))\n+\t\treturn;\n+\n+\tif (!(rxd->rxd.flags & PCIE_DESC_RX_RSS))\n+\t\treturn;\n+\n+\thash = rte_be_to_cpu_32(*(uint32_t *)NFP_HASH_OFFSET);\n+\thash_type = rte_be_to_cpu_32(*(uint32_t *)NFP_HASH_TYPE_OFFSET);\n+\n+\t/*\n+\t * hash type is sharing the same word with input port info\n+\t * 31-8: input port\n+\t * 7:0: hash type\n+\t */\n+\thash_type &= 0xff;\n+\tmbuf->hash.rss = hash;\n+\tmbuf->ol_flags |= PKT_RX_RSS_HASH;\n+\n+\tswitch (hash_type) {\n+\tcase NFP_NET_RSS_IPV4:\n+\t\tmbuf->packet_type |= RTE_PTYPE_INNER_L3_IPV4;\n+\t\tbreak;\n+\tcase NFP_NET_RSS_IPV6:\n+\t\tmbuf->packet_type |= RTE_PTYPE_INNER_L3_IPV6;\n+\t\tbreak;\n+\tcase NFP_NET_RSS_IPV6_EX:\n+\t\tmbuf->packet_type |= RTE_PTYPE_INNER_L3_IPV6_EXT;\n+\t\tbreak;\n+\tdefault:\n+\t\tmbuf->packet_type |= RTE_PTYPE_INNER_L4_MASK;\n+\t}\n+}\n+\n+/* nfp_net_check_port - Set mbuf in_port field */\n+static void\n+nfp_net_check_port(struct nfp_net_rx_desc *rxd, struct rte_mbuf *mbuf)\n+{\n+\tuint32_t port;\n+\n+\tif (!(rxd->rxd.flags & PCIE_DESC_RX_INGRESS_PORT)) {\n+\t\tmbuf->port = 0;\n+\t\treturn;\n+\t}\n+\n+\tport = rte_be_to_cpu_32(*(uint32_t *)((uint8_t *)mbuf->buf_addr +\n+\t\t\t\t\t      mbuf->data_off - 8));\n+\n+\t/*\n+\t * hash type is sharing the same word with input port info\n+\t * 31-8: input port\n+\t * 7:0: hash type\n+\t */\n+\tport = (uint8_t)(port >> 8);\n+\tmbuf->port = port;\n+}\n+\n+static inline void\n+nfp_net_mbuf_alloc_failed(struct nfp_net_rxq *rxq)\n+{\n+\trte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++;\n+}\n+\n+#define NFP_DESC_META_LEN(d) (d->rxd.meta_len_dd & PCIE_DESC_RX_META_LEN_MASK)\n+\n+/*\n+ * RX path design:\n+ *\n+ * There are some decissions to take:\n+ * 1) How to check DD RX descriptors bit\n+ * 2) How and when to allocate new mbufs\n+ *\n+ * Current implementation checks just one single DD bit each loop. As each\n+ * descriptor is 8 bytes, it is likely a good idea to check descriptors in\n+ * a single cache line instead. Tests with this change have not shown any\n+ * performance improvement but it requires further investigation. For example,\n+ * depending on which descriptor is next, the number of descriptors could be\n+ * less than 8 for just checking those in the same cache line. This implies\n+ * extra work which could be counterproductive by itself. Indeed, last firmware\n+ * changes are just doing this: writing several descriptors with the DD bit\n+ * for saving PCIe bandwidth and DMA operations from the NFP.\n+ *\n+ * Mbuf allocation is done when a new packet is received. Then the descriptor\n+ * is automatically linked with the new mbuf and the old one is given to the\n+ * user. The main drawback with this design is mbuf allocation is heavier than\n+ * using bulk allocations allowed by DPDK with rte_mempool_get_bulk. From the\n+ * cache point of view it does not seem allocating the mbuf early on as we are\n+ * doing now have any benefit at all. Again, tests with this change have not\n+ * shown any improvement. Also, rte_mempool_get_bulk returns all or nothing\n+ * so looking at the implications of this type of allocation should be studied\n+ * deeply\n+ */\n+\n+static uint16_t\n+nfp_net_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)\n+{\n+\tstruct nfp_net_rxq *rxq;\n+\tstruct nfp_net_rx_desc *rxds;\n+\tstruct nfp_net_rx_buff *rxb;\n+\tstruct nfp_net_hw *hw;\n+\tstruct rte_mbuf *mb;\n+\tstruct rte_mbuf *new_mb;\n+\tint idx;\n+\tuint16_t nb_hold;\n+\tuint64_t dma_addr;\n+\tint avail;\n+\n+\trxq = rx_queue;\n+\tif (unlikely(rxq == NULL)) {\n+\t\t/*\n+\t\t * DPDK just checks the queue is lower than max queues\n+\t\t * enabled. But the queue needs to be configured\n+\t\t */\n+\t\tRTE_LOG(ERR, PMD, \"RX Bad queue\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\thw = rxq->hw;\n+\tavail = 0;\n+\tnb_hold = 0;\n+\n+\twhile (avail < nb_pkts) {\n+\t\tidx = rxq->rd_p % rxq->rx_count;\n+\n+\t\trxb = &rxq->rxbufs[idx];\n+\t\tif (unlikely(rxb == NULL)) {\n+\t\t\tRTE_LOG(ERR, PMD, \"rxb does not exist!\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/*\n+\t\t * Memory barrier to ensure that we won't do other\n+\t\t * reads before the DD bit.\n+\t\t */\n+\t\trte_rmb();\n+\n+\t\trxds = &rxq->rxds[idx];\n+\t\tif ((rxds->rxd.meta_len_dd & PCIE_DESC_RX_DD) == 0)\n+\t\t\tbreak;\n+\n+\t\t/*\n+\t\t * We got a packet. Let's alloc a new mbuff for refilling the\n+\t\t * free descriptor ring as soon as possible\n+\t\t */\n+\t\tnew_mb = rte_pktmbuf_alloc(rxq->mem_pool);\n+\t\tif (unlikely(new_mb == NULL)) {\n+\t\t\tRTE_LOG(DEBUG, PMD, \"RX mbuf alloc failed port_id=%u \"\n+\t\t\t\t\"queue_id=%u\\n\", (unsigned)rxq->port_id,\n+\t\t\t\t(unsigned)rxq->qidx);\n+\t\t\tnfp_net_mbuf_alloc_failed(rxq);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tnb_hold++;\n+\n+\t\t/*\n+\t\t * Grab the mbuff and refill the descriptor with the\n+\t\t * previously allocated mbuff\n+\t\t */\n+\t\tmb = rxb->mbuf;\n+\t\trxb->mbuf = new_mb;\n+\n+\t\tPMD_RX_LOG(DEBUG, \"Packet len: %u, mbuf_size: %u\\n\",\n+\t\t\t   rxds->rxd.data_len, rxq->mbuf_size);\n+\n+\t\t/* Size of this segment */\n+\t\tmb->data_len = rxds->rxd.data_len - NFP_DESC_META_LEN(rxds);\n+\t\t/* Size of the whole packet. We just support 1 segment */\n+\t\tmb->pkt_len = rxds->rxd.data_len - NFP_DESC_META_LEN(rxds);\n+\n+\t\tif (unlikely((mb->data_len + NFP_NET_RX_OFFSET) >\n+\t\t\t     rxq->mbuf_size)) {\n+\t\t\t/*\n+\t\t\t * This should not happen and the user has the\n+\t\t\t * responsibility of avoiding it. But we have\n+\t\t\t * to give some info about the error\n+\t\t\t */\n+\t\t\tRTE_LOG(ERR, PMD,\n+\t\t\t\t\"mbuf overflow likely due to NFP_NET_RX_OFFSET\\n\"\n+\t\t\t\t\"\\t\\tYour mbuf size should have extra space for\"\n+\t\t\t\t\" NFP_NET_RX_OFFSET=%u bytes.\\n\"\n+\t\t\t\t\"\\t\\tCurrently you just have %u bytes available\"\n+\t\t\t\t\" but the received packet is %u bytes long\",\n+\t\t\t\tNFP_NET_RX_OFFSET,\n+\t\t\t\trxq->mbuf_size - NFP_NET_RX_OFFSET,\n+\t\t\t\tmb->data_len);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\t/* Filling the received mbuff with packet info */\n+\t\tmb->data_off = RTE_PKTMBUF_HEADROOM + NFP_NET_RX_OFFSET;\n+\n+\t\t/* No scatter mode supported */\n+\t\tmb->nb_segs = 1;\n+\t\tmb->next = NULL;\n+\n+\t\t/* Checking the RSS flag */\n+\t\tnfp_net_set_hash(rxq, rxds, mb);\n+\n+\t\t/* Checking the checksum flag */\n+\t\tnfp_net_rx_cksum(rxq, rxds, mb);\n+\n+\t\t/* Checking the port flag */\n+\t\tnfp_net_check_port(rxds, mb);\n+\n+\t\tif ((rxds->rxd.flags & PCIE_DESC_RX_VLAN) &&\n+\t\t    (hw->ctrl & NFP_NET_CFG_CTRL_RXVLAN)) {\n+\t\t\tmb->vlan_tci = rte_cpu_to_le_32(rxds->rxd.vlan);\n+\t\t\tmb->ol_flags |= PKT_RX_VLAN_PKT;\n+\t\t}\n+\n+\t\t/* Adding the mbuff to the mbuff array passed by the app */\n+\t\trx_pkts[avail++] = mb;\n+\n+\t\t/* Now resetting and updating the descriptor */\n+\t\trxds->vals[0] = 0;\n+\t\trxds->vals[1] = 0;\n+\t\tdma_addr = rte_cpu_to_le_64(RTE_MBUF_DMA_ADDR_DEFAULT(new_mb));\n+\t\trxds->fld.dd = 0;\n+\t\trxds->fld.dma_addr_hi = (dma_addr >> 32) & 0xff;\n+\t\trxds->fld.dma_addr_lo = dma_addr & 0xffffffff;\n+\n+\t\trxq->rd_p++;\n+\t}\n+\n+\tif (nb_hold == 0)\n+\t\treturn nb_hold;\n+\n+\tPMD_RX_LOG(DEBUG, \"RX  port_id=%u queue_id=%u, %d packets received\\n\",\n+\t\t   (unsigned)rxq->port_id, (unsigned)rxq->qidx, nb_hold);\n+\n+\tnb_hold += rxq->nb_rx_hold;\n+\n+\t/*\n+\t * FL descriptors needs to be written before incrementing the\n+\t * FL queue WR pointer\n+\t */\n+\trte_wmb();\n+\tif (nb_hold > rxq->rx_free_thresh) {\n+\t\tPMD_RX_LOG(DEBUG, \"port=%u queue=%u nb_hold=%u avail=%u\\n\",\n+\t\t\t   (unsigned)rxq->port_id, (unsigned)rxq->qidx,\n+\t\t\t   (unsigned)nb_hold, (unsigned)avail);\n+\t\tnfp_qcp_ptr_add(rxq->qcp_fl, NFP_QCP_WRITE_PTR, nb_hold);\n+\t\tnb_hold = 0;\n+\t}\n+\trxq->nb_rx_hold = nb_hold;\n+\n+\treturn avail;\n+}\n+\n+/*\n+ * nfp_net_tx_free_bufs - Check for descriptors with a complete\n+ * status\n+ * @txq: TX queue to work with\n+ * Returns number of descriptors freed\n+ */\n+int\n+nfp_net_tx_free_bufs(struct nfp_net_txq *txq)\n+{\n+\tuint32_t qcp_rd_p;\n+\tint todo;\n+\n+\tPMD_TX_LOG(DEBUG, \"queue %u. Check for descriptor with a complete\"\n+\t\t   \" status\\n\", txq->qidx);\n+\n+\t/* Work out how many packets have been sent */\n+\tqcp_rd_p = nfp_qcp_read(txq->qcp_q, NFP_QCP_READ_PTR);\n+\n+\tif (qcp_rd_p == txq->qcp_rd_p) {\n+\t\tPMD_TX_LOG(DEBUG, \"queue %u: It seems harrier is not sending \"\n+\t\t\t   \"packets (%u, %u)\\n\", txq->qidx,\n+\t\t\t   qcp_rd_p, txq->qcp_rd_p);\n+\t\treturn 0;\n+\t}\n+\n+\tif (qcp_rd_p > txq->qcp_rd_p)\n+\t\ttodo = qcp_rd_p - txq->qcp_rd_p;\n+\telse\n+\t\ttodo = qcp_rd_p + txq->tx_count - txq->qcp_rd_p;\n+\n+\tPMD_TX_LOG(DEBUG, \"qcp_rd_p %u, txq->qcp_rd_p: %u, qcp->rd_p: %u\\n\",\n+\t\t   qcp_rd_p, txq->qcp_rd_p, txq->rd_p);\n+\n+\tif (todo == 0)\n+\t\treturn todo;\n+\n+\ttxq->qcp_rd_p += todo;\n+\ttxq->qcp_rd_p %= txq->tx_count;\n+\ttxq->rd_p += todo;\n+\n+\treturn todo;\n+}\n+\n+/* Leaving always free descriptors for avoiding wrapping confusion */\n+#define NFP_FREE_TX_DESC(t) (t->tx_count - (t->wr_p - t->rd_p) - 8)\n+\n+/*\n+ * nfp_net_txq_full - Check if the TX queue free descriptors\n+ * is below tx_free_threshold\n+ *\n+ * @txq: TX queue to check\n+ *\n+ * This function uses the host copy* of read/write pointers\n+ */\n+static inline\n+int nfp_net_txq_full(struct nfp_net_txq *txq)\n+{\n+\treturn NFP_FREE_TX_DESC(txq) < txq->tx_free_thresh;\n+}\n+\n+static uint16_t\n+nfp_net_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n+{\n+\tstruct nfp_net_txq *txq;\n+\tstruct nfp_net_hw *hw;\n+\tstruct nfp_net_tx_desc *txds;\n+\tstruct rte_mbuf *pkt;\n+\tuint64_t dma_addr;\n+\tint pkt_size, dma_size;\n+\tuint16_t free_descs, issued_descs;\n+\tstruct rte_mbuf **lmbuf;\n+\tint i;\n+\n+\ttxq = tx_queue;\n+\thw = txq->hw;\n+\ttxds = &txq->txds[txq->tail];\n+\n+\tPMD_TX_LOG(DEBUG, \"working for queue %u at pos %d and %u packets\\n\",\n+\t\t   txq->qidx, wr_idx, nb_pkts);\n+\n+\tif ((NFP_FREE_TX_DESC(txq) < nb_pkts) || (nfp_net_txq_full(txq)))\n+\t\tnfp_net_tx_free_bufs(txq);\n+\n+\tfree_descs = (uint16_t)NFP_FREE_TX_DESC(txq);\n+\tif (unlikely(free_descs == 0))\n+\t\treturn 0;\n+\n+\tpkt = *tx_pkts;\n+\n+\ti = 0;\n+\tissued_descs = 0;\n+\tPMD_TX_LOG(DEBUG, \"queue: %u. Sending %u packets\\n\",\n+\t\t   txq->qidx, nb_pkts);\n+\t/* Sending packets */\n+\twhile ((i < nb_pkts) && free_descs) {\n+\t\t/* Grabbing the mbuf linked to the current descriptor */\n+\t\tlmbuf = &txq->txbufs[txq->tail].mbuf;\n+\t\t/* Warming the cache for releasing the mbuf later on */\n+\t\tRTE_MBUF_PREFETCH_TO_FREE(*lmbuf);\n+\n+\t\tpkt = *(tx_pkts + i);\n+\n+\t\tif (unlikely((pkt->nb_segs > 1) &&\n+\t\t\t     !(hw->cap & NFP_NET_CFG_CTRL_GATHER))) {\n+\t\t\tPMD_INIT_LOG(INFO, \"NFP_NET_CFG_CTRL_GATHER not set\\n\");\n+\t\t\trte_panic(\"Multisegment packet unsupported\\n\");\n+\t\t}\n+\n+\t\t/* Checking if we have enough descriptors */\n+\t\tif (unlikely(pkt->nb_segs > free_descs))\n+\t\t\tgoto xmit_end;\n+\n+\t\t/*\n+\t\t * Checksum and VLAN flags just in the first descriptor for a\n+\t\t * multisegment packet\n+\t\t */\n+\t\tnfp_net_tx_cksum(txq, txds, pkt);\n+\n+\t\tif ((pkt->ol_flags & PKT_TX_VLAN_PKT) &&\n+\t\t    (hw->cap & NFP_NET_CFG_CTRL_TXVLAN)) {\n+\t\t\ttxds->flags |= PCIE_DESC_TX_VLAN;\n+\t\t\ttxds->vlan = pkt->vlan_tci;\n+\t\t}\n+\n+\t\tif (pkt->ol_flags & PKT_TX_TCP_SEG)\n+\t\t\trte_panic(\"TSO is not supported\\n\");\n+\n+\t\t/*\n+\t\t * mbuf data_len is the data in one segment and pkt_len data\n+\t\t * in the whole packet. When the packet is just one segment,\n+\t\t * then data_len = pkt_len\n+\t\t */\n+\t\tpkt_size = pkt->pkt_len;\n+\n+\t\twhile (pkt_size) {\n+\t\t\t/* Releasing mbuf which was prefetched above */\n+\t\t\tif (*lmbuf)\n+\t\t\t\trte_pktmbuf_free_seg(*lmbuf);\n+\n+\t\t\tdma_size = pkt->data_len;\n+\t\t\tdma_addr = RTE_MBUF_DATA_DMA_ADDR(pkt);\n+\t\t\tPMD_TX_LOG(DEBUG, \"Working with mbuf at dma address:\"\n+\t\t\t\t   \"%\" PRIx64 \"\\n\", dma_addr);\n+\n+\t\t\t/* Filling descriptors fields */\n+\t\t\ttxds->dma_len = dma_size;\n+\t\t\ttxds->data_len = pkt->pkt_len;\n+\t\t\ttxds->dma_addr_hi = (dma_addr >> 32) & 0xff;\n+\t\t\ttxds->dma_addr_lo = (dma_addr & 0xffffffff);\n+\t\t\tASSERT(free_descs > 0);\n+\t\t\tfree_descs--;\n+\n+\t\t\t/*\n+\t\t\t * Linking mbuf with descriptor for being released\n+\t\t\t * next time descriptor is used\n+\t\t\t */\n+\t\t\t*lmbuf = pkt;\n+\n+\t\t\ttxq->wr_p++;\n+\t\t\ttxq->tail++;\n+\t\t\tif (unlikely(txq->tail == txq->tx_count)) /* wrapping?*/\n+\t\t\t\ttxq->tail = 0;\n+\n+\t\t\tpkt_size -= dma_size;\n+\t\t\tif (!pkt_size) {\n+\t\t\t\t/* End of packet */\n+\t\t\t\ttxds->offset_eop |= PCIE_DESC_TX_EOP;\n+\t\t\t} else {\n+\t\t\t\ttxds->offset_eop &= PCIE_DESC_TX_OFFSET_MASK;\n+\t\t\t\tpkt = pkt->next;\n+\t\t\t}\n+\t\t\t/* Referencing next free TX descriptor */\n+\t\t\ttxds = &txq->txds[txq->tail];\n+\t\t\tissued_descs++;\n+\t\t}\n+\t\ti++;\n+\t}\n+\n+xmit_end:\n+\t/* Increment write pointers. Force memory write before we let HW know */\n+\trte_wmb();\n+\tnfp_qcp_ptr_add(txq->qcp_q, NFP_QCP_WRITE_PTR, issued_descs);\n+\n+\treturn i;\n+}\n+\n /* Initialise and register driver with DPDK Application */\n static struct eth_dev_ops nfp_net_eth_dev_ops = {\n \t.dev_configure\t\t= nfp_net_configure,\n",
    "prefixes": [
        "dpdk-dev",
        "v5",
        "2/9"
    ]
}