get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 766317,
    "url": "http://patchwork.ozlabs.org/api/patches/766317/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20170524055535.14155-2-bjorn.topel@gmail.com/",
    "project": {
        "id": 46,
        "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api",
        "name": "Intel Wired Ethernet development",
        "link_name": "intel-wired-lan",
        "list_id": "intel-wired-lan.osuosl.org",
        "list_email": "intel-wired-lan@osuosl.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170524055535.14155-2-bjorn.topel@gmail.com>",
    "list_archive_url": null,
    "date": "2017-05-24T05:55:34",
    "name": "[v7,1/2] i40e: add XDP support for pass and drop actions",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "43395caf517e8665285179988a75863c7f6a05cf",
    "submitter": {
        "id": 70569,
        "url": "http://patchwork.ozlabs.org/api/people/70569/?format=api",
        "name": "Björn Töpel",
        "email": "bjorn.topel@gmail.com"
    },
    "delegate": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/users/68/?format=api",
        "username": "jtkirshe",
        "first_name": "Jeff",
        "last_name": "Kirsher",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20170524055535.14155-2-bjorn.topel@gmail.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/766317/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/766317/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@osuosl.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Received": [
            "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3wXhTR5YYdz9sP9\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 24 May 2017 15:55:55 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 47B99302E7;\n\tWed, 24 May 2017 05:55:54 +0000 (UTC)",
            "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id M3khIxtqDDES; Wed, 24 May 2017 05:55:49 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id 353F230325;\n\tWed, 24 May 2017 05:55:49 +0000 (UTC)",
            "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id 1EA3F1C05C2\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 24 May 2017 05:55:47 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 192CB86E81\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 24 May 2017 05:55:47 +0000 (UTC)",
            "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 4Ya6AFm6ag46 for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 24 May 2017 05:55:46 +0000 (UTC)",
            "from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id EEBC986EB1\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 24 May 2017 05:55:45 +0000 (UTC)",
            "from fmsmga006.fm.intel.com ([10.253.24.20])\n\tby orsmga104.jf.intel.com with ESMTP; 23 May 2017 22:55:45 -0700",
            "from btopel-mobl1.isw.intel.com (HELO localhost.localdomain)\n\t([10.103.211.137])\n\tby fmsmga006.fm.intel.com with ESMTP; 23 May 2017 22:55:43 -0700"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "from auto-whitelisted by SQLgrey-1.7.6",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.38,384,1491289200\"; d=\"scan'208\";a=\"106238921\"",
        "From": "=?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= <bjorn.topel@gmail.com>",
        "To": "jeffrey.t.kirsher@intel.com, intel-wired-lan@lists.osuosl.org,\n\talexander.duyck@gmail.com",
        "Date": "Wed, 24 May 2017 07:55:34 +0200",
        "Message-Id": "<20170524055535.14155-2-bjorn.topel@gmail.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "In-Reply-To": "<20170524055535.14155-1-bjorn.topel@gmail.com>",
        "References": "<20170524055535.14155-1-bjorn.topel@gmail.com>",
        "MIME-Version": "1.0",
        "Cc": "daniel@iogearbox.net,\n\t=?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= <bjorn.topel@intel.com>,\n\tmagnus.karlsson@intel.com",
        "Subject": "[Intel-wired-lan] [PATCH v7 1/2] i40e: add XDP support for pass and\n\tdrop actions",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.18-1",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>",
        "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>",
        "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "intel-wired-lan-bounces@osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"
    },
    "content": "From: Björn Töpel <bjorn.topel@intel.com>\n\nThis commit adds basic XDP support for i40e derived NICs. All XDP\nactions will end up in XDP_DROP.\n\nSigned-off-by: Björn Töpel <bjorn.topel@intel.com>\n---\n drivers/net/ethernet/intel/i40e/i40e.h      |   7 ++\n drivers/net/ethernet/intel/i40e/i40e_main.c |  87 +++++++++++++++++++\n drivers/net/ethernet/intel/i40e/i40e_txrx.c | 130 +++++++++++++++++++++-------\n drivers/net/ethernet/intel/i40e/i40e_txrx.h |   1 +\n 4 files changed, 194 insertions(+), 31 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\nindex 395ca94faf80..d3195b29d53c 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e.h\n@@ -645,6 +645,8 @@ struct i40e_vsi {\n \tu16 max_frame;\n \tu16 rx_buf_len;\n \n+\tstruct bpf_prog *xdp_prog;\n+\n \t/* List of q_vectors allocated to this VSI */\n \tstruct i40e_q_vector **q_vectors;\n \tint num_q_vectors;\n@@ -972,4 +974,9 @@ i40e_status i40e_get_npar_bw_setting(struct i40e_pf *pf);\n i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf);\n i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf);\n void i40e_print_link_message(struct i40e_vsi *vsi, bool isup);\n+\n+static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)\n+{\n+\treturn !!vsi->xdp_prog;\n+}\n #endif /* _I40E_H_ */\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\nindex 8d1d3b859af7..1ef2ba840f86 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n@@ -27,6 +27,7 @@\n #include <linux/etherdevice.h>\n #include <linux/of_net.h>\n #include <linux/pci.h>\n+#include <linux/bpf.h>\n \n /* Local includes */\n #include \"i40e.h\"\n@@ -2396,6 +2397,18 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)\n }\n \n /**\n+ * i40e_max_xdp_frame_size - returns the maximum allowed frame size for XDP\n+ * @vsi: the vsi\n+ **/\n+static int i40e_max_xdp_frame_size(struct i40e_vsi *vsi)\n+{\n+\tif (PAGE_SIZE >= 8192 || (vsi->back->flags & I40E_FLAG_LEGACY_RX))\n+\t\treturn I40E_RXBUFFER_2048;\n+\telse\n+\t\treturn I40E_RXBUFFER_3072;\n+}\n+\n+/**\n  * i40e_change_mtu - NDO callback to change the Maximum Transfer Unit\n  * @netdev: network interface device structure\n  * @new_mtu: new value for maximum frame size\n@@ -2408,6 +2421,13 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu)\n \tstruct i40e_vsi *vsi = np->vsi;\n \tstruct i40e_pf *pf = vsi->back;\n \n+\tif (i40e_enabled_xdp_vsi(vsi)) {\n+\t\tint frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;\n+\n+\t\tif (frame_size > i40e_max_xdp_frame_size(vsi))\n+\t\t\treturn -EINVAL;\n+\t}\n+\n \tnetdev_info(netdev, \"changing MTU from %d to %d\\n\",\n \t\t    netdev->mtu, new_mtu);\n \tnetdev->mtu = new_mtu;\n@@ -9310,6 +9330,72 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb,\n \treturn features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);\n }\n \n+/**\n+ * i40e_xdp_setup - add/remove an XDP program\n+ * @vsi: VSI to changed\n+ * @prog: XDP program\n+ **/\n+static int i40e_xdp_setup(struct i40e_vsi *vsi,\n+\t\t\t  struct bpf_prog *prog)\n+{\n+\tint frame_size = vsi->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;\n+\tstruct i40e_pf *pf = vsi->back;\n+\tstruct bpf_prog *old_prog;\n+\tbool need_reset;\n+\tint i;\n+\n+\t/* Don't allow frames that span over multiple buffers */\n+\tif (frame_size > vsi->rx_buf_len)\n+\t\treturn -EINVAL;\n+\n+\tif (!i40e_enabled_xdp_vsi(vsi) && !prog)\n+\t\treturn 0;\n+\n+\t/* When turning XDP on->off/off->on we reset and rebuild the rings. */\n+\tneed_reset = (i40e_enabled_xdp_vsi(vsi) != !!prog);\n+\n+\tif (need_reset)\n+\t\ti40e_prep_for_reset(pf, true);\n+\n+\told_prog = xchg(&vsi->xdp_prog, prog);\n+\n+\tif (need_reset)\n+\t\ti40e_reset_and_rebuild(pf, true, true);\n+\n+\tfor (i = 0; i < vsi->num_queue_pairs; i++)\n+\t\tWRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);\n+\n+\tif (old_prog)\n+\t\tbpf_prog_put(old_prog);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * i40e_xdp - implements ndo_xdp for i40e\n+ * @dev: netdevice\n+ * @xdp: XDP command\n+ **/\n+static int i40e_xdp(struct net_device *dev,\n+\t\t    struct netdev_xdp *xdp)\n+{\n+\tstruct i40e_netdev_priv *np = netdev_priv(dev);\n+\tstruct i40e_vsi *vsi = np->vsi;\n+\n+\tif (vsi->type != I40E_VSI_MAIN)\n+\t\treturn -EINVAL;\n+\n+\tswitch (xdp->command) {\n+\tcase XDP_SETUP_PROG:\n+\t\treturn i40e_xdp_setup(vsi, xdp->prog);\n+\tcase XDP_QUERY_PROG:\n+\t\txdp->prog_attached = i40e_enabled_xdp_vsi(vsi);\n+\t\treturn 0;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n static const struct net_device_ops i40e_netdev_ops = {\n \t.ndo_open\t\t= i40e_open,\n \t.ndo_stop\t\t= i40e_close,\n@@ -9342,6 +9428,7 @@ static const struct net_device_ops i40e_netdev_ops = {\n \t.ndo_features_check\t= i40e_features_check,\n \t.ndo_bridge_getlink\t= i40e_ndo_bridge_getlink,\n \t.ndo_bridge_setlink\t= i40e_ndo_bridge_setlink,\n+\t.ndo_xdp\t\t= i40e_xdp,\n };\n \n /**\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\nindex af554f3cda19..f744f843bc72 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n@@ -26,6 +26,7 @@\n \n #include <linux/prefetch.h>\n #include <net/busy_poll.h>\n+#include <linux/bpf_trace.h>\n #include \"i40e.h\"\n #include \"i40e_trace.h\"\n #include \"i40e_prototype.h\"\n@@ -1195,6 +1196,7 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)\n void i40e_free_rx_resources(struct i40e_ring *rx_ring)\n {\n \ti40e_clean_rx_ring(rx_ring);\n+\trx_ring->xdp_prog = NULL;\n \tkfree(rx_ring->rx_bi);\n \trx_ring->rx_bi = NULL;\n \n@@ -1241,6 +1243,8 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)\n \trx_ring->next_to_clean = 0;\n \trx_ring->next_to_use = 0;\n \n+\trx_ring->xdp_prog = rx_ring->vsi->xdp_prog;\n+\n \treturn 0;\n err:\n \tkfree(rx_ring->rx_bi);\n@@ -1593,6 +1597,7 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,\n  * i40e_cleanup_headers - Correct empty headers\n  * @rx_ring: rx descriptor ring packet is being transacted on\n  * @skb: pointer to current skb being fixed\n+ * @rx_desc: pointer to the EOP Rx descriptor\n  *\n  * Also address the case where we are pulling data in on pages only\n  * and as such no data is present in the skb header.\n@@ -1602,8 +1607,25 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,\n  *\n  * Returns true if an error was encountered and skb was freed.\n  **/\n-static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb)\n+static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb,\n+\t\t\t\t union i40e_rx_desc *rx_desc)\n+\n {\n+\t/* XDP packets use error pointer so abort at this point */\n+\tif (IS_ERR(skb))\n+\t\treturn true;\n+\n+\t/* ERR_MASK will only have valid bits if EOP set, and\n+\t * what we are doing here is actually checking\n+\t * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in\n+\t * the error field\n+\t */\n+\tif (unlikely(i40e_test_staterr(rx_desc,\n+\t\t\t\t       BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {\n+\t\tdev_kfree_skb_any(skb);\n+\t\treturn true;\n+\t}\n+\n \t/* if eth_skb_pad returns an error the skb was freed */\n \tif (eth_skb_pad(skb))\n \t\treturn true;\n@@ -1776,7 +1798,7 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,\n  * i40e_construct_skb - Allocate skb and populate it\n  * @rx_ring: rx descriptor ring to transact packets on\n  * @rx_buffer: rx buffer to pull data from\n- * @size: size of buffer to add to skb\n+ * @xdp: xdp_buff pointing to the data\n  *\n  * This function allocates an skb.  It then populates it with the page\n  * data from the current receive descriptor, taking care to set up the\n@@ -1784,9 +1806,9 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,\n  */\n static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,\n \t\t\t\t\t  struct i40e_rx_buffer *rx_buffer,\n-\t\t\t\t\t  unsigned int size)\n+\t\t\t\t\t  struct xdp_buff *xdp)\n {\n-\tvoid *va = page_address(rx_buffer->page) + rx_buffer->page_offset;\n+\tunsigned int size = xdp->data_end - xdp->data;\n #if (PAGE_SIZE < 8192)\n \tunsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;\n #else\n@@ -1796,9 +1818,9 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,\n \tstruct sk_buff *skb;\n \n \t/* prefetch first cache line of first page */\n-\tprefetch(va);\n+\tprefetch(xdp->data);\n #if L1_CACHE_BYTES < 128\n-\tprefetch(va + L1_CACHE_BYTES);\n+\tprefetch(xdp->data + L1_CACHE_BYTES);\n #endif\n \n \t/* allocate a skb to store the frags */\n@@ -1811,10 +1833,11 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,\n \t/* Determine available headroom for copy */\n \theadlen = size;\n \tif (headlen > I40E_RX_HDR_SIZE)\n-\t\theadlen = eth_get_headlen(va, I40E_RX_HDR_SIZE);\n+\t\theadlen = eth_get_headlen(xdp->data, I40E_RX_HDR_SIZE);\n \n \t/* align pull length to size of long to optimize memcpy performance */\n-\tmemcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long)));\n+\tmemcpy(__skb_put(skb, headlen), xdp->data,\n+\t       ALIGN(headlen, sizeof(long)));\n \n \t/* update all of the pointers */\n \tsize -= headlen;\n@@ -1841,16 +1864,16 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,\n  * i40e_build_skb - Build skb around an existing buffer\n  * @rx_ring: Rx descriptor ring to transact packets on\n  * @rx_buffer: Rx buffer to pull data from\n- * @size: size of buffer to add to skb\n+ * @xdp: xdp_buff pointing to the data\n  *\n  * This function builds an skb around an existing Rx buffer, taking care\n  * to set up the skb correctly and avoid any memcpy overhead.\n  */\n static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,\n \t\t\t\t      struct i40e_rx_buffer *rx_buffer,\n-\t\t\t\t      unsigned int size)\n+\t\t\t\t      struct xdp_buff *xdp)\n {\n-\tvoid *va = page_address(rx_buffer->page) + rx_buffer->page_offset;\n+\tunsigned int size = xdp->data_end - xdp->data;\n #if (PAGE_SIZE < 8192)\n \tunsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;\n #else\n@@ -1860,12 +1883,12 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,\n \tstruct sk_buff *skb;\n \n \t/* prefetch first cache line of first page */\n-\tprefetch(va);\n+\tprefetch(xdp->data);\n #if L1_CACHE_BYTES < 128\n-\tprefetch(va + L1_CACHE_BYTES);\n+\tprefetch(xdp->data + L1_CACHE_BYTES);\n #endif\n \t/* build an skb around the page buffer */\n-\tskb = build_skb(va - I40E_SKB_PAD, truesize);\n+\tskb = build_skb(xdp->data_hard_start, truesize);\n \tif (unlikely(!skb))\n \t\treturn NULL;\n \n@@ -1944,6 +1967,46 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,\n \treturn true;\n }\n \n+#define I40E_XDP_PASS 0\n+#define I40E_XDP_CONSUMED 1\n+\n+/**\n+ * i40e_run_xdp - run an XDP program\n+ * @rx_ring: Rx ring being processed\n+ * @xdp: XDP buffer containing the frame\n+ **/\n+static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring,\n+\t\t\t\t    struct xdp_buff *xdp)\n+{\n+\tint result = I40E_XDP_PASS;\n+\tstruct bpf_prog *xdp_prog;\n+\tu32 act;\n+\n+\trcu_read_lock();\n+\txdp_prog = READ_ONCE(rx_ring->xdp_prog);\n+\n+\tif (!xdp_prog)\n+\t\tgoto xdp_out;\n+\n+\tact = bpf_prog_run_xdp(xdp_prog, xdp);\n+\tswitch (act) {\n+\tcase XDP_PASS:\n+\t\tbreak;\n+\tdefault:\n+\t\tbpf_warn_invalid_xdp_action(act);\n+\tcase XDP_TX:\n+\tcase XDP_ABORTED:\n+\t\ttrace_xdp_exception(rx_ring->netdev, xdp_prog, act);\n+\t\t/* fallthrough -- handle aborts by dropping packet */\n+\tcase XDP_DROP:\n+\t\tresult = I40E_XDP_CONSUMED;\n+\t\tbreak;\n+\t}\n+xdp_out:\n+\trcu_read_unlock();\n+\treturn ERR_PTR(-result);\n+}\n+\n /**\n  * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf\n  * @rx_ring: rx descriptor ring to transact packets on\n@@ -1966,6 +2029,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)\n \twhile (likely(total_rx_packets < budget)) {\n \t\tstruct i40e_rx_buffer *rx_buffer;\n \t\tunion i40e_rx_desc *rx_desc;\n+\t\tstruct xdp_buff xdp;\n \t\tunsigned int size;\n \t\tu16 vlan_tag;\n \t\tu8 rx_ptype;\n@@ -2006,12 +2070,27 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)\n \t\trx_buffer = i40e_get_rx_buffer(rx_ring, size);\n \n \t\t/* retrieve a buffer from the ring */\n-\t\tif (skb)\n+\t\tif (!skb) {\n+\t\t\txdp.data = page_address(rx_buffer->page) +\n+\t\t\t\t   rx_buffer->page_offset;\n+\t\t\txdp.data_hard_start = xdp.data -\n+\t\t\t\t\t      i40e_rx_offset(rx_ring);\n+\t\t\txdp.data_end = xdp.data + size;\n+\n+\t\t\tskb = i40e_run_xdp(rx_ring, &xdp);\n+\t\t}\n+\n+\t\tif (IS_ERR(skb)) {\n+\t\t\ttotal_rx_bytes += size;\n+\t\t\ttotal_rx_packets++;\n+\t\t\trx_buffer->pagecnt_bias++;\n+\t\t} else if (skb) {\n \t\t\ti40e_add_rx_frag(rx_ring, rx_buffer, skb, size);\n-\t\telse if (ring_uses_build_skb(rx_ring))\n-\t\t\tskb = i40e_build_skb(rx_ring, rx_buffer, size);\n-\t\telse\n-\t\t\tskb = i40e_construct_skb(rx_ring, rx_buffer, size);\n+\t\t} else if (ring_uses_build_skb(rx_ring)) {\n+\t\t\tskb = i40e_build_skb(rx_ring, rx_buffer, &xdp);\n+\t\t} else {\n+\t\t\tskb = i40e_construct_skb(rx_ring, rx_buffer, &xdp);\n+\t\t}\n \n \t\t/* exit if we failed to retrieve a buffer */\n \t\tif (!skb) {\n@@ -2026,18 +2105,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)\n \t\tif (i40e_is_non_eop(rx_ring, rx_desc, skb))\n \t\t\tcontinue;\n \n-\t\t/* ERR_MASK will only have valid bits if EOP set, and\n-\t\t * what we are doing here is actually checking\n-\t\t * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in\n-\t\t * the error field\n-\t\t */\n-\t\tif (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {\n-\t\t\tdev_kfree_skb_any(skb);\n-\t\t\tskb = NULL;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (i40e_cleanup_headers(rx_ring, skb)) {\n+\t\tif (i40e_cleanup_headers(rx_ring, skb, rx_desc)) {\n \t\t\tskb = NULL;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h\nindex f5de51124cae..31f0b162996f 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h\n@@ -360,6 +360,7 @@ struct i40e_ring {\n \tvoid *desc;\t\t\t/* Descriptor ring memory */\n \tstruct device *dev;\t\t/* Used for DMA mapping */\n \tstruct net_device *netdev;\t/* netdev ring maps to */\n+\tstruct bpf_prog *xdp_prog;\n \tunion {\n \t\tstruct i40e_tx_buffer *tx_bi;\n \t\tstruct i40e_rx_buffer *rx_bi;\n",
    "prefixes": [
        "v7",
        "1/2"
    ]
}