get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 43908,
    "url": "http://patches.dpdk.org/api/patches/43908/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/3b90cf007384ac7e38aec0f7ce5d10d2e9619818.1535292771.git.rahul.lakkireddy@chelsio.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<3b90cf007384ac7e38aec0f7ce5d10d2e9619818.1535292771.git.rahul.lakkireddy@chelsio.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/3b90cf007384ac7e38aec0f7ce5d10d2e9619818.1535292771.git.rahul.lakkireddy@chelsio.com",
    "date": "2018-08-27T12:52:29",
    "name": "[1/4] net/cxgbe: add API to program hardware layer 2 table",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "58f2ff494b58bd1fee7094646c873b3dd668116d",
    "submitter": {
        "id": 241,
        "url": "http://patches.dpdk.org/api/people/241/?format=api",
        "name": "Rahul Lakkireddy",
        "email": "rahul.lakkireddy@chelsio.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/3b90cf007384ac7e38aec0f7ce5d10d2e9619818.1535292771.git.rahul.lakkireddy@chelsio.com/mbox/",
    "series": [
        {
            "id": 1068,
            "url": "http://patches.dpdk.org/api/series/1068/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1068",
            "date": "2018-08-27T12:52:28",
            "name": "net/cxgbe: add destination MAC match and VLAN rewrite support for flow API",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/1068/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/43908/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/43908/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 [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 315415B30;\n\tMon, 27 Aug 2018 14:52:56 +0200 (CEST)",
            "from stargate.chelsio.com (stargate.chelsio.com [12.32.117.8])\n\tby dpdk.org (Postfix) with ESMTP id 748635B1E\n\tfor <dev@dpdk.org>; Mon, 27 Aug 2018 14:52:54 +0200 (CEST)",
            "from localhost (scalar.blr.asicdesigners.com [10.193.185.94])\n\tby stargate.chelsio.com (8.13.8/8.13.8) with ESMTP id w7RCqoYW027064; \n\tMon, 27 Aug 2018 05:52:51 -0700"
        ],
        "From": "Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>",
        "To": "dev@dpdk.org",
        "Cc": "shaguna@chelsio.com, indranil@chelsio.com, nirranjan@chelsio.com",
        "Date": "Mon, 27 Aug 2018 18:22:29 +0530",
        "Message-Id": "<3b90cf007384ac7e38aec0f7ce5d10d2e9619818.1535292771.git.rahul.lakkireddy@chelsio.com>",
        "X-Mailer": "git-send-email 2.5.3",
        "In-Reply-To": [
            "<cover.1535292771.git.rahul.lakkireddy@chelsio.com>",
            "<cover.1535292771.git.rahul.lakkireddy@chelsio.com>"
        ],
        "References": [
            "<cover.1535292771.git.rahul.lakkireddy@chelsio.com>",
            "<cover.1535292771.git.rahul.lakkireddy@chelsio.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH 1/4] net/cxgbe: add API to program hardware layer\n\t2 table",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/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: Shagun Agrawal <shaguna@chelsio.com>\n\nAdd API to program and manage hardware Layer 2 Table. L2T holds\ninformation necessary to rewrite specific fields in packet, such\nas destination MAC address and vlan id.\n\nSigned-off-by: Shagun Agrawal <shaguna@chelsio.com>\nSigned-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>\n---\n drivers/net/cxgbe/Makefile              |   1 +\n drivers/net/cxgbe/base/adapter.h        |   3 +\n drivers/net/cxgbe/base/t4_msg.h         |  34 +++++\n drivers/net/cxgbe/base/t4fw_interface.h |   2 +\n drivers/net/cxgbe/cxgbe_filter.h        |   1 +\n drivers/net/cxgbe/cxgbe_main.c          |  30 ++++-\n drivers/net/cxgbe/l2t.c                 | 227 ++++++++++++++++++++++++++++++++\n drivers/net/cxgbe/l2t.h                 |  57 ++++++++\n drivers/net/cxgbe/meson.build           |   1 +\n 9 files changed, 349 insertions(+), 7 deletions(-)\n create mode 100644 drivers/net/cxgbe/l2t.c\n create mode 100644 drivers/net/cxgbe/l2t.h",
    "diff": "diff --git a/drivers/net/cxgbe/Makefile b/drivers/net/cxgbe/Makefile\nindex 5d66c4b3a..d75b070f3 100644\n--- a/drivers/net/cxgbe/Makefile\n+++ b/drivers/net/cxgbe/Makefile\n@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe_filter.c\n SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += cxgbe_flow.c\n SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4_hw.c\n SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += clip_tbl.c\n+SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += l2t.c\n SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4vf_hw.c\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/drivers/net/cxgbe/base/adapter.h b/drivers/net/cxgbe/base/adapter.h\nindex e98dd2182..9f4a9653c 100644\n--- a/drivers/net/cxgbe/base/adapter.h\n+++ b/drivers/net/cxgbe/base/adapter.h\n@@ -324,7 +324,10 @@ struct adapter {\n \n \tunsigned int clipt_start; /* CLIP table start */\n \tunsigned int clipt_end;   /* CLIP table end */\n+\tunsigned int l2t_start;   /* Layer 2 table start */\n+\tunsigned int l2t_end;     /* Layer 2 table end */\n \tstruct clip_tbl *clipt;   /* CLIP table */\n+\tstruct l2t_data *l2t;     /* Layer 2 table */\n \n \tstruct tid_info tids;     /* Info used to access TID related tables */\n };\ndiff --git a/drivers/net/cxgbe/base/t4_msg.h b/drivers/net/cxgbe/base/t4_msg.h\nindex 5d433c91c..094a153f2 100644\n--- a/drivers/net/cxgbe/base/t4_msg.h\n+++ b/drivers/net/cxgbe/base/t4_msg.h\n@@ -11,7 +11,9 @@ enum {\n \tCPL_SET_TCB_FIELD     = 0x5,\n \tCPL_ABORT_REQ         = 0xA,\n \tCPL_ABORT_RPL         = 0xB,\n+\tCPL_L2T_WRITE_REQ     = 0x12,\n \tCPL_TID_RELEASE       = 0x1A,\n+\tCPL_L2T_WRITE_RPL     = 0x23,\n \tCPL_ACT_OPEN_RPL      = 0x25,\n \tCPL_ABORT_RPL_RSS     = 0x2D,\n \tCPL_SET_TCB_RPL       = 0x3A,\n@@ -66,6 +68,9 @@ union opcode_tid {\n #define M_TID_TID    0x3fff\n #define G_TID_TID(x) (((x) >> S_TID_TID) & M_TID_TID)\n \n+#define S_TID_QID    14\n+#define V_TID_QID(x) ((x) << S_TID_QID)\n+\n struct rss_header {\n \t__u8 opcode;\n #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n@@ -421,6 +426,35 @@ struct cpl_rx_pkt {\n \t__be16 err_vec;\n };\n \n+struct cpl_l2t_write_req {\n+\tWR_HDR;\n+\tunion opcode_tid ot;\n+\t__be16 params;\n+\t__be16 l2t_idx;\n+\t__be16 vlan;\n+\t__u8   dst_mac[6];\n+};\n+\n+/* cpl_l2t_write_req.params fields */\n+#define S_L2T_W_PORT    8\n+#define V_L2T_W_PORT(x) ((x) << S_L2T_W_PORT)\n+\n+#define S_L2T_W_LPBK    10\n+#define V_L2T_W_LPBK(x) ((x) << S_L2T_W_LPBK)\n+\n+#define S_L2T_W_ARPMISS         11\n+#define V_L2T_W_ARPMISS(x)      ((x) << S_L2T_W_ARPMISS)\n+\n+#define S_L2T_W_NOREPLY    15\n+#define V_L2T_W_NOREPLY(x) ((x) << S_L2T_W_NOREPLY)\n+\n+struct cpl_l2t_write_rpl {\n+\tRSS_HDR\n+\tunion opcode_tid ot;\n+\t__u8 status;\n+\t__u8 rsvd[3];\n+};\n+\n /* rx_pkt.l2info fields */\n #define S_RXF_UDP    22\n #define V_RXF_UDP(x) ((x) << S_RXF_UDP)\ndiff --git a/drivers/net/cxgbe/base/t4fw_interface.h b/drivers/net/cxgbe/base/t4fw_interface.h\nindex e80b58a32..1c08637bb 100644\n--- a/drivers/net/cxgbe/base/t4fw_interface.h\n+++ b/drivers/net/cxgbe/base/t4fw_interface.h\n@@ -665,6 +665,8 @@ enum fw_params_param_pfvf {\n \tFW_PARAMS_PARAM_PFVF_CLIP_END = 0x04,\n \tFW_PARAMS_PARAM_PFVF_FILTER_START = 0x05,\n \tFW_PARAMS_PARAM_PFVF_FILTER_END = 0x06,\n+\tFW_PARAMS_PARAM_PFVF_L2T_START = 0x13,\n+\tFW_PARAMS_PARAM_PFVF_L2T_END = 0x14,\n \tFW_PARAMS_PARAM_PFVF_CPLFW4MSG_ENCAP = 0x31,\n \tFW_PARAMS_PARAM_PFVF_PORT_CAPS32 = 0x3A\n };\ndiff --git a/drivers/net/cxgbe/cxgbe_filter.h b/drivers/net/cxgbe/cxgbe_filter.h\nindex af8fa7529..be12e231a 100644\n--- a/drivers/net/cxgbe/cxgbe_filter.h\n+++ b/drivers/net/cxgbe/cxgbe_filter.h\n@@ -145,6 +145,7 @@ struct filter_entry {\n \tu32 pending:1;              /* filter action is pending FW reply */\n \tstruct filter_ctx *ctx;     /* caller's completion hook */\n \tstruct clip_entry *clipt;   /* CLIP Table entry for IPv6 */\n+\tstruct l2t_entry *l2t;      /* Layer Two Table entry for dmac */\n \tstruct rte_eth_dev *dev;    /* Port's rte eth device */\n \tvoid *private;              /* For use by apps using filter_entry */\n \ndiff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c\nindex c3938e8db..be2bc4213 100644\n--- a/drivers/net/cxgbe/cxgbe_main.c\n+++ b/drivers/net/cxgbe/cxgbe_main.c\n@@ -38,6 +38,7 @@\n #include \"t4_msg.h\"\n #include \"cxgbe.h\"\n #include \"clip_tbl.h\"\n+#include \"l2t.h\"\n \n /**\n  * Allocate a chunk of memory. The allocated memory is cleared.\n@@ -99,6 +100,10 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,\n \t\tconst struct cpl_act_open_rpl *p = (const void *)rsp;\n \n \t\thash_filter_rpl(q->adapter, p);\n+\t} else if (opcode == CPL_L2T_WRITE_RPL) {\n+\t\tconst struct cpl_l2t_write_rpl *p = (const void *)rsp;\n+\n+\t\tdo_l2t_write_rpl(q->adapter, p);\n \t} else {\n \t\tdev_err(adapter, \"unexpected CPL %#x on FW event queue\\n\",\n \t\t\topcode);\n@@ -1135,13 +1140,17 @@ static int adap_init0(struct adapter *adap)\n \t V_FW_PARAMS_PARAM_Y(0) | \\\n \t V_FW_PARAMS_PARAM_Z(0))\n \n-\tparams[0] = FW_PARAM_PFVF(FILTER_START);\n-\tparams[1] = FW_PARAM_PFVF(FILTER_END);\n-\tret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);\n+\tparams[0] = FW_PARAM_PFVF(L2T_START);\n+\tparams[1] = FW_PARAM_PFVF(L2T_END);\n+\tparams[2] = FW_PARAM_PFVF(FILTER_START);\n+\tparams[3] = FW_PARAM_PFVF(FILTER_END);\n+\tret = t4_query_params(adap, adap->mbox, adap->pf, 0, 4, params, val);\n \tif (ret < 0)\n \t\tgoto bye;\n-\tadap->tids.ftid_base = val[0];\n-\tadap->tids.nftids = val[1] - val[0] + 1;\n+\tadap->l2t_start = val[0];\n+\tadap->l2t_end = val[1];\n+\tadap->tids.ftid_base = val[2];\n+\tadap->tids.nftids = val[3] - val[2] + 1;\n \n \tparams[0] = FW_PARAM_PFVF(CLIP_START);\n \tparams[1] = FW_PARAM_PFVF(CLIP_END);\n@@ -1679,10 +1688,11 @@ void cxgbe_close(struct adapter *adapter)\n \tint i;\n \n \tif (adapter->flags & FULL_INIT_DONE) {\n-\t\tif (is_pf4(adapter))\n-\t\t\tt4_intr_disable(adapter);\n \t\ttid_free(&adapter->tids);\n \t\tt4_cleanup_clip_tbl(adapter);\n+\t\tt4_cleanup_l2t(adapter);\n+\t\tif (is_pf4(adapter))\n+\t\t\tt4_intr_disable(adapter);\n \t\tt4_sge_tx_monitor_stop(adapter);\n \t\tt4_free_sge_resources(adapter);\n \t\tfor_each_port(adapter, i) {\n@@ -1855,6 +1865,12 @@ int cxgbe_probe(struct adapter *adapter)\n \t\tdev_warn(adapter, \"could not allocate CLIP. Continuing\\n\");\n \t}\n \n+\tadapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end);\n+\tif (!adapter->l2t) {\n+\t\t/* We tolerate a lack of L2T, giving up some functionality */\n+\t\tdev_warn(adapter, \"could not allocate L2T. Continuing\\n\");\n+\t}\n+\n \tif (tid_init(&adapter->tids) < 0) {\n \t\t/* Disable filtering support */\n \t\tdev_warn(adapter, \"could not allocate TID table, \"\ndiff --git a/drivers/net/cxgbe/l2t.c b/drivers/net/cxgbe/l2t.c\nnew file mode 100644\nindex 000000000..814188fea\n--- /dev/null\n+++ b/drivers/net/cxgbe/l2t.c\n@@ -0,0 +1,227 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Chelsio Communications.\n+ * All rights reserved.\n+ */\n+#include \"common.h\"\n+#include \"l2t.h\"\n+\n+/**\n+ * cxgbe_l2t_release - Release associated L2T entry\n+ * @e: L2T entry to release\n+ *\n+ * Releases ref count and frees up an L2T entry from L2T table\n+ */\n+void cxgbe_l2t_release(struct l2t_entry *e)\n+{\n+\tif (rte_atomic32_read(&e->refcnt) != 0)\n+\t\trte_atomic32_dec(&e->refcnt);\n+}\n+\n+/**\n+ * Process a CPL_L2T_WRITE_RPL. Note that the TID in the reply is really\n+ * the L2T index it refers to.\n+ */\n+void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl)\n+{\n+\tstruct l2t_data *d = adap->l2t;\n+\tunsigned int tid = GET_TID(rpl);\n+\tunsigned int l2t_idx = tid % L2T_SIZE;\n+\n+\tif (unlikely(rpl->status != CPL_ERR_NONE)) {\n+\t\tdev_err(adap,\n+\t\t\t\"Unexpected L2T_WRITE_RPL status %u for entry %u\\n\",\n+\t\t\trpl->status, l2t_idx);\n+\t\treturn;\n+\t}\n+\n+\tif (tid & F_SYNC_WR) {\n+\t\tstruct l2t_entry *e = &d->l2tab[l2t_idx - d->l2t_start];\n+\n+\t\tt4_os_lock(&e->lock);\n+\t\tif (e->state != L2T_STATE_SWITCHING)\n+\t\t\te->state = L2T_STATE_VALID;\n+\t\tt4_os_unlock(&e->lock);\n+\t}\n+}\n+\n+/**\n+ * Write an L2T entry.  Must be called with the entry locked.\n+ * The write may be synchronous or asynchronous.\n+ */\n+static int write_l2e(struct rte_eth_dev *dev, struct l2t_entry *e, int sync,\n+\t\t     bool loopback, bool arpmiss)\n+{\n+\tstruct adapter *adap = ethdev2adap(dev);\n+\tstruct l2t_data *d = adap->l2t;\n+\tstruct rte_mbuf *mbuf;\n+\tstruct cpl_l2t_write_req *req;\n+\tstruct sge_ctrl_txq *ctrlq;\n+\tunsigned int l2t_idx = e->idx + d->l2t_start;\n+\tunsigned int port_id = ethdev2pinfo(dev)->port_id;\n+\n+\tctrlq = &adap->sge.ctrlq[port_id];\n+\tmbuf = rte_pktmbuf_alloc(ctrlq->mb_pool);\n+\tif (!mbuf)\n+\t\treturn -ENOMEM;\n+\n+\tmbuf->data_len = sizeof(*req);\n+\tmbuf->pkt_len = mbuf->data_len;\n+\n+\treq = rte_pktmbuf_mtod(mbuf, struct cpl_l2t_write_req *);\n+\tINIT_TP_WR(req, 0);\n+\n+\tOPCODE_TID(req) =\n+\t\tcpu_to_be32(MK_OPCODE_TID(CPL_L2T_WRITE_REQ,\n+\t\t\t\t\t  l2t_idx | V_SYNC_WR(sync) |\n+\t\t\t\t\t  V_TID_QID(adap->sge.fw_evtq.abs_id)));\n+\treq->params = cpu_to_be16(V_L2T_W_PORT(e->lport) |\n+\t\t\t\t  V_L2T_W_LPBK(loopback) |\n+\t\t\t\t  V_L2T_W_ARPMISS(arpmiss) |\n+\t\t\t\t  V_L2T_W_NOREPLY(!sync));\n+\treq->l2t_idx = cpu_to_be16(l2t_idx);\n+\treq->vlan = cpu_to_be16(e->vlan);\n+\trte_memcpy(req->dst_mac, e->dmac, ETHER_ADDR_LEN);\n+\n+\tif (loopback)\n+\t\tmemset(req->dst_mac, 0, ETHER_ADDR_LEN);\n+\n+\tt4_mgmt_tx(ctrlq, mbuf);\n+\n+\tif (sync && e->state != L2T_STATE_SWITCHING)\n+\t\te->state = L2T_STATE_SYNC_WRITE;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * find_or_alloc_l2e - Find/Allocate a free L2T entry\n+ * @d: L2T table\n+ * @vlan: VLAN id to compare/add\n+ * @port: port id to compare/add\n+ * @dmac: Destination MAC address to compare/add\n+ * Returns pointer to the L2T entry found/created\n+ *\n+ * Finds/Allocates an L2T entry to be used by switching rule of a filter.\n+ */\n+static struct l2t_entry *find_or_alloc_l2e(struct l2t_data *d, u16 vlan,\n+\t\t\t\t\t   u8 port, u8 *dmac)\n+{\n+\tstruct l2t_entry *end, *e;\n+\tstruct l2t_entry *first_free = NULL;\n+\n+\tfor (e = &d->l2tab[0], end = &d->l2tab[d->l2t_size]; e != end; ++e) {\n+\t\tif (rte_atomic32_read(&e->refcnt) == 0) {\n+\t\t\tif (!first_free)\n+\t\t\t\tfirst_free = e;\n+\t\t} else {\n+\t\t\tif (e->state == L2T_STATE_SWITCHING) {\n+\t\t\t\tif ((!memcmp(e->dmac, dmac, ETHER_ADDR_LEN)) &&\n+\t\t\t\t    e->vlan == vlan && e->lport == port)\n+\t\t\t\t\tgoto exists;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (first_free) {\n+\t\te = first_free;\n+\t\tgoto found;\n+\t}\n+\n+\treturn NULL;\n+\n+found:\n+\te->state = L2T_STATE_UNUSED;\n+\n+exists:\n+\treturn e;\n+}\n+\n+static struct l2t_entry *t4_l2t_alloc_switching(struct rte_eth_dev *dev,\n+\t\t\t\t\t\tu16 vlan, u8 port,\n+\t\t\t\t\t\tu8 *eth_addr)\n+{\n+\tstruct adapter *adap = ethdev2adap(dev);\n+\tstruct l2t_data *d = adap->l2t;\n+\tstruct l2t_entry *e;\n+\tint ret = 0;\n+\n+\tt4_os_write_lock(&d->lock);\n+\te = find_or_alloc_l2e(d, vlan, port, eth_addr);\n+\tif (e) {\n+\t\tt4_os_lock(&e->lock);\n+\t\tif (!rte_atomic32_read(&e->refcnt)) {\n+\t\t\te->state = L2T_STATE_SWITCHING;\n+\t\t\te->vlan = vlan;\n+\t\t\te->lport = port;\n+\t\t\trte_memcpy(e->dmac, eth_addr, ETHER_ADDR_LEN);\n+\t\t\trte_atomic32_set(&e->refcnt, 1);\n+\t\t\tret = write_l2e(dev, e, 0, !L2T_LPBK, !L2T_ARPMISS);\n+\t\t\tif (ret < 0)\n+\t\t\t\tdev_debug(adap, \"Failed to write L2T entry: %d\",\n+\t\t\t\t\t  ret);\n+\t\t} else {\n+\t\t\trte_atomic32_inc(&e->refcnt);\n+\t\t}\n+\t\tt4_os_unlock(&e->lock);\n+\t}\n+\tt4_os_write_unlock(&d->lock);\n+\n+\treturn ret ? NULL : e;\n+}\n+\n+/**\n+ * cxgbe_l2t_alloc_switching - Allocate a L2T entry for switching rule\n+ * @dev: rte_eth_dev pointer\n+ * @vlan: VLAN Id\n+ * @port: Associated port\n+ * @dmac: Destination MAC address to add to L2T\n+ * Returns pointer to the allocated l2t entry\n+ *\n+ * Allocates a L2T entry for use by switching rule of a filter\n+ */\n+struct l2t_entry *cxgbe_l2t_alloc_switching(struct rte_eth_dev *dev, u16 vlan,\n+\t\t\t\t\t    u8 port, u8 *dmac)\n+{\n+\treturn t4_l2t_alloc_switching(dev, vlan, port, dmac);\n+}\n+\n+/**\n+ * Initialize L2 Table\n+ */\n+struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end)\n+{\n+\tunsigned int l2t_size;\n+\tunsigned int i;\n+\tstruct l2t_data *d;\n+\n+\tif (l2t_start >= l2t_end || l2t_end >= L2T_SIZE)\n+\t\treturn NULL;\n+\tl2t_size = l2t_end - l2t_start + 1;\n+\n+\td = t4_os_alloc(sizeof(*d) + l2t_size * sizeof(struct l2t_entry));\n+\tif (!d)\n+\t\treturn NULL;\n+\n+\td->l2t_start = l2t_start;\n+\td->l2t_size = l2t_size;\n+\n+\tt4_os_rwlock_init(&d->lock);\n+\n+\tfor (i = 0; i < d->l2t_size; ++i) {\n+\t\td->l2tab[i].idx = i;\n+\t\td->l2tab[i].state = L2T_STATE_UNUSED;\n+\t\tt4_os_lock_init(&d->l2tab[i].lock);\n+\t\trte_atomic32_set(&d->l2tab[i].refcnt, 0);\n+\t}\n+\n+\treturn d;\n+}\n+\n+/**\n+ * Cleanup L2 Table\n+ */\n+void t4_cleanup_l2t(struct adapter *adap)\n+{\n+\tif (adap->l2t)\n+\t\tt4_os_free(adap->l2t);\n+}\ndiff --git a/drivers/net/cxgbe/l2t.h b/drivers/net/cxgbe/l2t.h\nnew file mode 100644\nindex 000000000..22a34e388\n--- /dev/null\n+++ b/drivers/net/cxgbe/l2t.h\n@@ -0,0 +1,57 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Chelsio Communications.\n+ * All rights reserved.\n+ */\n+#ifndef _CXGBE_L2T_H_\n+#define _CXGBE_L2T_H_\n+\n+#include \"t4_msg.h\"\n+\n+enum {\n+\tL2T_SIZE = 4096       /* # of L2T entries */\n+};\n+\n+enum {\n+\tL2T_STATE_VALID,      /* entry is up to date */\n+\tL2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */\n+\n+\t/* when state is one of the below the entry is not hashed */\n+\tL2T_STATE_SWITCHING,  /* entry is being used by a switching filter */\n+\tL2T_STATE_UNUSED      /* entry not in use */\n+};\n+\n+/*\n+ * State for the corresponding entry of the HW L2 table.\n+ */\n+struct l2t_entry {\n+\tu16 state;                  /* entry state */\n+\tu16 idx;                    /* entry index within in-memory table */\n+\tu16 vlan;                   /* VLAN TCI (id: bits 0-11, prio: 13-15 */\n+\tu8  lport;                  /* destination port */\n+\tu8  dmac[ETHER_ADDR_LEN];   /* destination MAC address */\n+\trte_spinlock_t lock;        /* entry lock */\n+\trte_atomic32_t refcnt;      /* entry reference count */\n+};\n+\n+struct l2t_data {\n+\tunsigned int l2t_start;     /* start index of our piece of the L2T */\n+\tunsigned int l2t_size;      /* number of entries in l2tab */\n+\trte_rwlock_t lock;          /* table rw lock */\n+\tstruct l2t_entry l2tab[0];  /* MUST BE LAST */\n+};\n+\n+#define L2T_LPBK\ttrue\n+#define L2T_ARPMISS\ttrue\n+\n+/* identifies sync vs async L2T_WRITE_REQs */\n+#define S_SYNC_WR    12\n+#define V_SYNC_WR(x) ((x) << S_SYNC_WR)\n+#define F_SYNC_WR    V_SYNC_WR(1)\n+\n+struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end);\n+void t4_cleanup_l2t(struct adapter *adap);\n+struct l2t_entry *cxgbe_l2t_alloc_switching(struct rte_eth_dev *dev, u16 vlan,\n+\t\t\t\t\t    u8 port, u8 *dmac);\n+void cxgbe_l2t_release(struct l2t_entry *e);\n+void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl);\n+#endif /* _CXGBE_L2T_H_ */\ndiff --git a/drivers/net/cxgbe/meson.build b/drivers/net/cxgbe/meson.build\nindex 7c69a34b1..f6a442cb8 100644\n--- a/drivers/net/cxgbe/meson.build\n+++ b/drivers/net/cxgbe/meson.build\n@@ -9,6 +9,7 @@ sources = files('cxgbe_ethdev.c',\n \t'cxgbe_filter.c',\n \t'cxgbe_flow.c',\n \t'clip_tbl.c',\n+\t'l2t.c',\n \t'base/t4_hw.c',\n \t'base/t4vf_hw.c')\n includes += include_directories('base')\n",
    "prefixes": [
        "1/4"
    ]
}