get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 43910,
    "url": "http://patches.dpdk.org/api/patches/43910/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/8a8222dbcb81621f72b5b42c1d6dbc4757b1b4b1.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": "<8a8222dbcb81621f72b5b42c1d6dbc4757b1b4b1.1535292771.git.rahul.lakkireddy@chelsio.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/8a8222dbcb81621f72b5b42c1d6dbc4757b1b4b1.1535292771.git.rahul.lakkireddy@chelsio.com",
    "date": "2018-08-27T12:52:31",
    "name": "[3/4] net/cxgbe: add API to program hardware MPS table",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "2c9758bc31540319962a4771d0b22a3d35357dc5",
    "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/8a8222dbcb81621f72b5b42c1d6dbc4757b1b4b1.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/43910/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/43910/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 2E3905F19;\n\tMon, 27 Aug 2018 14:53:02 +0200 (CEST)",
            "from stargate.chelsio.com (stargate.chelsio.com [12.32.117.8])\n\tby dpdk.org (Postfix) with ESMTP id 5819D5B12\n\tfor <dev@dpdk.org>; Mon, 27 Aug 2018 14:53:00 +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 w7RCqukg027070; \n\tMon, 27 Aug 2018 05:52:57 -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:31 +0530",
        "Message-Id": "<8a8222dbcb81621f72b5b42c1d6dbc4757b1b4b1.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 3/4] net/cxgbe: add API to program hardware MPS\n\ttable",
        "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 Multi Port Switch table. MPS\nholds destination MAC addresses to be matched against incoming packets\nfor further rule processing. Packets not matching any entry in MPS table\nwill be dropped by default, unless the underlying port is in promiscuous\nmode.\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        |   1 +\n drivers/net/cxgbe/base/common.h         |   6 +\n drivers/net/cxgbe/base/t4_hw.c          | 106 ++++++++++++++\n drivers/net/cxgbe/base/t4_regs.h        |   8 ++\n drivers/net/cxgbe/base/t4fw_interface.h |  24 ++++\n drivers/net/cxgbe/cxgbe_main.c          |   7 +\n drivers/net/cxgbe/meson.build           |   1 +\n drivers/net/cxgbe/mps_tcam.c            | 243 ++++++++++++++++++++++++++++++++\n drivers/net/cxgbe/mps_tcam.h            |  52 +++++++\n 10 files changed, 449 insertions(+)\n create mode 100644 drivers/net/cxgbe/mps_tcam.c\n create mode 100644 drivers/net/cxgbe/mps_tcam.h",
    "diff": "diff --git a/drivers/net/cxgbe/Makefile b/drivers/net/cxgbe/Makefile\nindex d75b070f3..68466f13e 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) += mps_tcam.c\n SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += l2t.c\n SRCS-$(CONFIG_RTE_LIBRTE_CXGBE_PMD) += t4vf_hw.c\n \ndiff --git a/drivers/net/cxgbe/base/adapter.h b/drivers/net/cxgbe/base/adapter.h\nindex 9f4a9653c..47cfc5f5f 100644\n--- a/drivers/net/cxgbe/base/adapter.h\n+++ b/drivers/net/cxgbe/base/adapter.h\n@@ -328,6 +328,7 @@ struct adapter {\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+\tstruct mpstcam_table *mpstcam;\n \n \tstruct tid_info tids;     /* Info used to access TID related tables */\n };\ndiff --git a/drivers/net/cxgbe/base/common.h b/drivers/net/cxgbe/base/common.h\nindex 157201da2..9f5756850 100644\n--- a/drivers/net/cxgbe/base/common.h\n+++ b/drivers/net/cxgbe/base/common.h\n@@ -388,6 +388,12 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox,\n int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,\n \t\t  int mtu, int promisc, int all_multi, int bcast, int vlanex,\n \t\t  bool sleep_ok);\n+int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid,\n+\t\t\t const u8 *addr, const u8 *mask, unsigned int idx,\n+\t\t\t u8 lookup_type, u8 port_id, bool sleep_ok);\n+int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid,\n+\t\t\t  const u8 *addr, const u8 *mask, unsigned int idx,\n+\t\t\t  u8 lookup_type, u8 port_id, bool sleep_ok);\n int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,\n \t\t  int idx, const u8 *addr, bool persist, bool add_smt);\n int t4_enable_vi_params(struct adapter *adap, unsigned int mbox,\ndiff --git a/drivers/net/cxgbe/base/t4_hw.c b/drivers/net/cxgbe/base/t4_hw.c\nindex 31762c9c5..d60894115 100644\n--- a/drivers/net/cxgbe/base/t4_hw.c\n+++ b/drivers/net/cxgbe/base/t4_hw.c\n@@ -4161,6 +4161,112 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,\n \t\treturn t4vf_wr_mbox(adap, &c, sizeof(c), NULL);\n }\n \n+/**\n+ *\tt4_alloc_raw_mac_filt - Adds a raw mac entry in mps tcam\n+ *\t@adap: the adapter\n+ *\t@viid: the VI id\n+ *\t@mac: the MAC address\n+ *\t@mask: the mask\n+ *\t@idx: index at which to add this entry\n+ *\t@port_id: the port index\n+ *\t@lookup_type: MAC address for inner (1) or outer (0) header\n+ *\t@sleep_ok: call is allowed to sleep\n+ *\n+ *\tAdds the mac entry at the specified index using raw mac interface.\n+ *\n+ *\tReturns a negative error number or the allocated index for this mac.\n+ */\n+int t4_alloc_raw_mac_filt(struct adapter *adap, unsigned int viid,\n+\t\t\t  const u8 *addr, const u8 *mask, unsigned int idx,\n+\t\t\t  u8 lookup_type, u8 port_id, bool sleep_ok)\n+{\n+\tint ret = 0;\n+\tstruct fw_vi_mac_cmd c;\n+\tstruct fw_vi_mac_raw *p = &c.u.raw;\n+\tu32 val;\n+\n+\tmemset(&c, 0, sizeof(c));\n+\tc.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) |\n+\t\t\t\t   F_FW_CMD_REQUEST | F_FW_CMD_WRITE |\n+\t\t\t\t   V_FW_VI_MAC_CMD_VIID(viid));\n+\tval = V_FW_CMD_LEN16(1) |\n+\t      V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW);\n+\tc.freemacs_to_len16 = cpu_to_be32(val);\n+\n+\t/* Specify that this is an inner mac address */\n+\tp->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx));\n+\n+\t/* Lookup Type. Outer header: 0, Inner header: 1 */\n+\tp->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) |\n+\t\t\t\t   V_DATAPORTNUM(port_id));\n+\t/* Lookup mask and port mask */\n+\tp->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) |\n+\t\t\t\t    V_DATAPORTNUM(M_DATAPORTNUM));\n+\n+\t/* Copy the address and the mask */\n+\tmemcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN);\n+\tmemcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN);\n+\n+\tret = t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);\n+\tif (ret == 0) {\n+\t\tret = G_FW_VI_MAC_CMD_RAW_IDX(be32_to_cpu(p->raw_idx_pkd));\n+\t\tif (ret != (int)idx)\n+\t\t\tret = -ENOMEM;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+/**\n+ *\tt4_free_raw_mac_filt - Frees a raw mac entry in mps tcam\n+ *\t@adap: the adapter\n+ *\t@viid: the VI id\n+ *\t@addr: the MAC address\n+ *\t@mask: the mask\n+ *\t@idx: index of the entry in mps tcam\n+ *\t@lookup_type: MAC address for inner (1) or outer (0) header\n+ *\t@port_id: the port index\n+ *\t@sleep_ok: call is allowed to sleep\n+ *\n+ *\tRemoves the mac entry at the specified index using raw mac interface.\n+ *\n+ *\tReturns a negative error number on failure.\n+ */\n+int t4_free_raw_mac_filt(struct adapter *adap, unsigned int viid,\n+\t\t\t const u8 *addr, const u8 *mask, unsigned int idx,\n+\t\t\t u8 lookup_type, u8 port_id, bool sleep_ok)\n+{\n+\tstruct fw_vi_mac_cmd c;\n+\tstruct fw_vi_mac_raw *p = &c.u.raw;\n+\tu32 raw;\n+\n+\tmemset(&c, 0, sizeof(c));\n+\tc.op_to_viid = cpu_to_be32(V_FW_CMD_OP(FW_VI_MAC_CMD) |\n+\t\t\t\t   F_FW_CMD_REQUEST | F_FW_CMD_WRITE |\n+\t\t\t\t   V_FW_CMD_EXEC(0) |\n+\t\t\t\t   V_FW_VI_MAC_CMD_VIID(viid));\n+\traw = V_FW_VI_MAC_CMD_ENTRY_TYPE(FW_VI_MAC_TYPE_RAW);\n+\tc.freemacs_to_len16 = cpu_to_be32(V_FW_VI_MAC_CMD_FREEMACS(0) |\n+\t\t\t\t\t  raw |\n+\t\t\t\t\t  V_FW_CMD_LEN16(1));\n+\n+\tp->raw_idx_pkd = cpu_to_be32(V_FW_VI_MAC_CMD_RAW_IDX(idx) |\n+\t\t\t\t     FW_VI_MAC_ID_BASED_FREE);\n+\n+\t/* Lookup Type. Outer header: 0, Inner header: 1 */\n+\tp->data0_pkd = cpu_to_be32(V_DATALKPTYPE(lookup_type) |\n+\t\t\t\t   V_DATAPORTNUM(port_id));\n+\t/* Lookup mask and port mask */\n+\tp->data0m_pkd = cpu_to_be64(V_DATALKPTYPE(M_DATALKPTYPE) |\n+\t\t\t\t    V_DATAPORTNUM(M_DATAPORTNUM));\n+\n+\t/* Copy the address and the mask */\n+\tmemcpy((u8 *)&p->data1[0] + 2, addr, ETHER_ADDR_LEN);\n+\tmemcpy((u8 *)&p->data1m[0] + 2, mask, ETHER_ADDR_LEN);\n+\n+\treturn t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, sleep_ok);\n+}\n+\n /**\n  * t4_change_mac - modifies the exact-match filter for a MAC address\n  * @adap: the adapter\ndiff --git a/drivers/net/cxgbe/base/t4_regs.h b/drivers/net/cxgbe/base/t4_regs.h\nindex 6f872edc2..af8c741e2 100644\n--- a/drivers/net/cxgbe/base/t4_regs.h\n+++ b/drivers/net/cxgbe/base/t4_regs.h\n@@ -45,6 +45,14 @@\n #define MPS_T5_CLS_SRAM_H(idx) (A_MPS_T5_CLS_SRAM_H + (idx) * 8)\n #define NUM_MPS_T5_CLS_SRAM_H_INSTANCES 512\n \n+#define S_DATAPORTNUM    12\n+#define M_DATAPORTNUM    0xfU\n+#define V_DATAPORTNUM(x) ((x) << S_DATAPORTNUM)\n+\n+#define S_DATALKPTYPE    10\n+#define M_DATALKPTYPE    0x3U\n+#define V_DATALKPTYPE(x) ((x) << S_DATALKPTYPE)\n+\n /* registers for module SGE */\n #define SGE_BASE_ADDR 0x1000\n \ndiff --git a/drivers/net/cxgbe/base/t4fw_interface.h b/drivers/net/cxgbe/base/t4fw_interface.h\nindex 1c08637bb..e2d2ee897 100644\n--- a/drivers/net/cxgbe/base/t4fw_interface.h\n+++ b/drivers/net/cxgbe/base/t4fw_interface.h\n@@ -1282,12 +1282,17 @@ struct fw_vi_cmd {\n /* Special VI_MAC command index ids */\n #define FW_VI_MAC_ADD_MAC\t\t0x3FF\n #define FW_VI_MAC_ADD_PERSIST_MAC\t0x3FE\n+#define FW_VI_MAC_ID_BASED_FREE         0x3FC\n \n enum fw_vi_mac_smac {\n \tFW_VI_MAC_MPS_TCAM_ENTRY,\n \tFW_VI_MAC_SMT_AND_MPSTCAM\n };\n \n+enum fw_vi_mac_entry_types {\n+\tFW_VI_MAC_TYPE_RAW = 0x2,\n+};\n+\n struct fw_vi_mac_cmd {\n \t__be32 op_to_viid;\n \t__be32 freemacs_to_len16;\n@@ -1299,6 +1304,13 @@ struct fw_vi_mac_cmd {\n \t\tstruct fw_vi_mac_hash {\n \t\t\t__be64 hashvec;\n \t\t} hash;\n+\t\tstruct fw_vi_mac_raw {\n+\t\t\t__be32 raw_idx_pkd;\n+\t\t\t__be32 data0_pkd;\n+\t\t\t__be32 data1[2];\n+\t\t\t__be64 data0m_pkd;\n+\t\t\t__be32 data1m[2];\n+\t\t} raw;\n \t} u;\n };\n \n@@ -1308,6 +1320,12 @@ struct fw_vi_mac_cmd {\n #define G_FW_VI_MAC_CMD_VIID(x)\t\\\n \t(((x) >> S_FW_VI_MAC_CMD_VIID) & M_FW_VI_MAC_CMD_VIID)\n \n+#define S_FW_VI_MAC_CMD_FREEMACS\t31\n+#define V_FW_VI_MAC_CMD_FREEMACS(x)\t((x) << S_FW_VI_MAC_CMD_FREEMACS)\n+\n+#define S_FW_VI_MAC_CMD_ENTRY_TYPE      23\n+#define V_FW_VI_MAC_CMD_ENTRY_TYPE(x)   ((x) << S_FW_VI_MAC_CMD_ENTRY_TYPE)\n+\n #define S_FW_VI_MAC_CMD_VALID\t\t15\n #define M_FW_VI_MAC_CMD_VALID\t\t0x1\n #define V_FW_VI_MAC_CMD_VALID(x)\t((x) << S_FW_VI_MAC_CMD_VALID)\n@@ -1327,6 +1345,12 @@ struct fw_vi_mac_cmd {\n #define G_FW_VI_MAC_CMD_IDX(x)\t\\\n \t(((x) >> S_FW_VI_MAC_CMD_IDX) & M_FW_VI_MAC_CMD_IDX)\n \n+#define S_FW_VI_MAC_CMD_RAW_IDX         16\n+#define M_FW_VI_MAC_CMD_RAW_IDX         0xffff\n+#define V_FW_VI_MAC_CMD_RAW_IDX(x)      ((x) << S_FW_VI_MAC_CMD_RAW_IDX)\n+#define G_FW_VI_MAC_CMD_RAW_IDX(x)      \\\n+\t(((x) >> S_FW_VI_MAC_CMD_RAW_IDX) & M_FW_VI_MAC_CMD_RAW_IDX)\n+\n struct fw_vi_rxmode_cmd {\n \t__be32 op_to_viid;\n \t__be32 retval_len16;\ndiff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c\nindex be2bc4213..20d2de442 100644\n--- a/drivers/net/cxgbe/cxgbe_main.c\n+++ b/drivers/net/cxgbe/cxgbe_main.c\n@@ -39,6 +39,7 @@\n #include \"cxgbe.h\"\n #include \"clip_tbl.h\"\n #include \"l2t.h\"\n+#include \"mps_tcam.h\"\n \n /**\n  * Allocate a chunk of memory. The allocated memory is cleared.\n@@ -1689,6 +1690,7 @@ void cxgbe_close(struct adapter *adapter)\n \n \tif (adapter->flags & FULL_INIT_DONE) {\n \t\ttid_free(&adapter->tids);\n+\t\tt4_cleanup_mpstcam(adapter);\n \t\tt4_cleanup_clip_tbl(adapter);\n \t\tt4_cleanup_l2t(adapter);\n \t\tif (is_pf4(adapter))\n@@ -1877,6 +1879,11 @@ int cxgbe_probe(struct adapter *adapter)\n \t\t\t \"filter support disabled. Continuing\\n\");\n \t}\n \n+\tadapter->mpstcam = t4_init_mpstcam(adapter);\n+\tif (!adapter->mpstcam)\n+\t\tdev_warn(adapter, \"could not allocate mps tcam table.\"\n+\t\t\t \" Continuing\\n\");\n+\n \tif (is_hashfilter(adapter)) {\n \t\tif (t4_read_reg(adapter, A_LE_DB_CONFIG) & F_HASHEN) {\n \t\t\tu32 hash_base, hash_reg;\ndiff --git a/drivers/net/cxgbe/meson.build b/drivers/net/cxgbe/meson.build\nindex f6a442cb8..c51af26e9 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'mps_tcam.c',\n \t'l2t.c',\n \t'base/t4_hw.c',\n \t'base/t4vf_hw.c')\ndiff --git a/drivers/net/cxgbe/mps_tcam.c b/drivers/net/cxgbe/mps_tcam.c\nnew file mode 100644\nindex 000000000..02ec69a92\n--- /dev/null\n+++ b/drivers/net/cxgbe/mps_tcam.c\n@@ -0,0 +1,243 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Chelsio Communications.\n+ * All rights reserved.\n+ */\n+\n+#include \"mps_tcam.h\"\n+\n+static inline bool\n+match_entry(struct mps_tcam_entry *entry, const u8 *eth_addr, const u8 *mask)\n+{\n+\tif (!memcmp(eth_addr, entry->eth_addr, ETHER_ADDR_LEN) &&\n+\t    !memcmp(mask, entry->mask, ETHER_ADDR_LEN))\n+\t\treturn true;\n+\treturn false;\n+}\n+\n+static int cxgbe_update_free_idx(struct mpstcam_table *t)\n+{\n+\tstruct mps_tcam_entry *entry = t->entry;\n+\tu16 i, next = t->free_idx + 1;\n+\n+\tif (entry[t->free_idx].state == MPS_ENTRY_UNUSED)\n+\t\t/* You are already pointing to a free entry !! */\n+\t\treturn 0;\n+\n+\t/* loop, till we don't rollback to same index where we started */\n+\tfor (i = next; i != t->free_idx; i++) {\n+\t\tif (i == t->size)\n+\t\t\t/* rollback and search free entry from start */\n+\t\t\ti = 0;\n+\n+\t\tif (entry[i].state == MPS_ENTRY_UNUSED) {\n+\t\t\tt->free_idx = i;\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\treturn -1;\t/* table is full */\n+}\n+\n+static struct mps_tcam_entry *\n+cxgbe_mpstcam_lookup(struct mpstcam_table *t, const u8 *eth_addr,\n+\t\t     const u8 *mask)\n+{\n+\tstruct mps_tcam_entry *entry = t->entry;\n+\tint i;\n+\n+\tif (!entry)\n+\t\treturn NULL;\n+\n+\tfor (i = 0; i < t->size; i++) {\n+\t\tif (entry[i].state == MPS_ENTRY_UNUSED)\n+\t\t\tcontinue;\t/* entry is not being used */\n+\t\tif (match_entry(&entry[i], eth_addr, mask))\n+\t\t\treturn &entry[i];\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *eth_addr,\n+\t\t\tconst u8 *mask)\n+{\n+\tstruct adapter *adap = pi->adapter;\n+\tstruct mpstcam_table *mpstcam = adap->mpstcam;\n+\tstruct mps_tcam_entry *entry;\n+\tint ret;\n+\n+\tif (!adap->mpstcam) {\n+\t\tdev_err(adap, \"mpstcam table is not available\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\t/* If entry already present, return it. */\n+\tt4_os_write_lock(&mpstcam->lock);\n+\tentry = cxgbe_mpstcam_lookup(adap->mpstcam, eth_addr, mask);\n+\tif (entry) {\n+\t\trte_atomic32_add(&entry->refcnt, 1);\n+\t\tt4_os_write_unlock(&mpstcam->lock);\n+\t\treturn entry->idx;\n+\t}\n+\n+\tif (mpstcam->full) {\n+\t\tt4_os_write_unlock(&mpstcam->lock);\n+\t\tdev_err(adap, \"mps-tcam table is full\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tret = t4_alloc_raw_mac_filt(adap, pi->viid, eth_addr, mask,\n+\t\t\t\t    mpstcam->free_idx, 0, pi->port_id, false);\n+\tif (ret <= 0) {\n+\t\tt4_os_write_unlock(&mpstcam->lock);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Fill in the new values */\n+\tentry = &mpstcam->entry[ret];\n+\tmemcpy(entry->eth_addr, eth_addr, ETHER_ADDR_LEN);\n+\tmemcpy(entry->mask, mask, ETHER_ADDR_LEN);\n+\trte_atomic32_set(&entry->refcnt, 1);\n+\tentry->state = MPS_ENTRY_USED;\n+\n+\tif (cxgbe_update_free_idx(mpstcam))\n+\t\tmpstcam->full = true;\n+\n+\tt4_os_write_unlock(&mpstcam->lock);\n+\treturn ret;\n+}\n+\n+int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr)\n+{\n+\tstruct adapter *adap = pi->adapter;\n+\tstruct mpstcam_table *mpstcam = adap->mpstcam;\n+\tstruct mps_tcam_entry *entry;\n+\n+\tif (!mpstcam)\n+\t\treturn -EOPNOTSUPP;\n+\tt4_os_write_lock(&mpstcam->lock);\n+\tif (idx != -1 && idx >= mpstcam->size) {\n+\t\tt4_os_write_unlock(&mpstcam->lock);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (idx >= 0) {\n+\t\tentry = &mpstcam->entry[idx];\n+\t\t/* user wants to modify an existing entry.\n+\t\t * verify if entry exists\n+\t\t */\n+\t\tif (entry->state != MPS_ENTRY_USED) {\n+\t\t\tt4_os_write_unlock(&mpstcam->lock);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tidx = t4_change_mac(adap, adap->mbox, pi->viid, idx, addr, true, true);\n+\tif (idx < 0) {\n+\t\tt4_os_write_unlock(&mpstcam->lock);\n+\t\treturn idx;\n+\t}\n+\n+\t/* idx can now be different from what user provided */\n+\tentry = &mpstcam->entry[idx];\n+\tmemcpy(entry->eth_addr, addr, ETHER_ADDR_LEN);\n+\t/* NOTE: we have considered the case that idx returned by t4_change_mac\n+\t * will be different from the user provided value only if user\n+\t * provided value is -1\n+\t */\n+\tif (entry->state == MPS_ENTRY_UNUSED) {\n+\t\trte_atomic32_set(&entry->refcnt, 1);\n+\t\tentry->state = MPS_ENTRY_USED;\n+\t}\n+\n+\tif (cxgbe_update_free_idx(mpstcam))\n+\t\tmpstcam->full = true;\n+\n+\tt4_os_write_unlock(&mpstcam->lock);\n+\treturn idx;\n+}\n+\n+/**\n+ * hold appropriate locks while calling this.\n+ */\n+static inline void reset_mpstcam_entry(struct mps_tcam_entry *entry)\n+{\n+\tmemset(entry->eth_addr, 0, ETHER_ADDR_LEN);\n+\tmemset(entry->mask, 0, ETHER_ADDR_LEN);\n+\trte_atomic32_clear(&entry->refcnt);\n+\tentry->state = MPS_ENTRY_UNUSED;\n+}\n+\n+/**\n+ * ret < 0: fatal error\n+ * ret = 0: entry removed in h/w\n+ * ret > 0: updated refcount.\n+ */\n+int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx)\n+{\n+\tstruct adapter *adap = pi->adapter;\n+\tstruct mpstcam_table *t = adap->mpstcam;\n+\tstruct mps_tcam_entry *entry;\n+\tint ret;\n+\n+\tif (!t)\n+\t\treturn -EOPNOTSUPP;\n+\tt4_os_write_lock(&t->lock);\n+\tentry = &t->entry[idx];\n+\tif (entry->state == MPS_ENTRY_UNUSED) {\n+\t\tt4_os_write_unlock(&t->lock);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (rte_atomic32_read(&entry->refcnt) == 1)\n+\t\tret = t4_free_raw_mac_filt(adap, pi->viid, entry->eth_addr,\n+\t\t\t\t\t   entry->mask, idx, 1, pi->port_id,\n+\t\t\t\t\t   false);\n+\telse\n+\t\tret = rte_atomic32_sub_return(&entry->refcnt, 1);\n+\n+\tif (ret == 0) {\n+\t\treset_mpstcam_entry(entry);\n+\t\tt->full = false;\t/* We have atleast 1 free entry */\n+\t\tcxgbe_update_free_idx(t);\n+\t}\n+\n+\tt4_os_write_unlock(&t->lock);\n+\treturn ret;\n+}\n+\n+struct mpstcam_table *t4_init_mpstcam(struct adapter *adap)\n+{\n+\tstruct mpstcam_table *t;\n+\tint i;\n+\tu16 size = adap->params.arch.mps_tcam_size;\n+\n+\tt =  t4_os_alloc(sizeof(*t) + size * sizeof(struct mps_tcam_entry));\n+\tif (!t)\n+\t\treturn NULL;\n+\n+\tt4_os_rwlock_init(&t->lock);\n+\tt->full = false;\n+\tt->size = size;\n+\n+\tfor (i = 0; i < size; i++) {\n+\t\treset_mpstcam_entry(&t->entry[i]);\n+\t\tt->entry[i].mpstcam = t;\n+\t\tt->entry[i].idx = i;\n+\t}\n+\n+\t/* first entry is used by chip. this is overwritten only\n+\t * in t4_cleanup_mpstcam()\n+\t */\n+\tt->entry[0].state = MPS_ENTRY_USED;\n+\tt->free_idx = 1;\n+\n+\treturn t;\n+}\n+\n+void t4_cleanup_mpstcam(struct adapter *adap)\n+{\n+\tif (adap->mpstcam) {\n+\t\tt4_os_free(adap->mpstcam->entry);\n+\t\tt4_os_free(adap->mpstcam);\n+\t}\n+}\ndiff --git a/drivers/net/cxgbe/mps_tcam.h b/drivers/net/cxgbe/mps_tcam.h\nnew file mode 100644\nindex 000000000..c3d6fe0d7\n--- /dev/null\n+++ b/drivers/net/cxgbe/mps_tcam.h\n@@ -0,0 +1,52 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Chelsio Communications.\n+ * All rights reserved.\n+ */\n+\n+#ifndef _CXGBE_MPSTCAM_H_\n+#define _CXGBE_MPSTCAM_H_\n+\n+#include \"common.h\"\n+\n+enum {\n+\tMPS_ENTRY_UNUSED,\t/* Keep this first so memset 0 renders\n+\t\t\t\t * the correct state. Other states can\n+\t\t\t\t * be added in future like MPS_ENTRY_BUSY\n+\t\t\t\t * to reduce contention while mboxing\n+\t\t\t\t * the request to f/w or to denote attributes\n+\t\t\t\t * for a specific entry\n+\t\t\t\t */\n+\tMPS_ENTRY_USED,\n+};\n+\n+struct mps_tcam_entry {\n+\tu8 state;\n+\tu16 idx;\n+\n+\t/* add data here which uniquely defines an entry */\n+\tu8 eth_addr[ETHER_ADDR_LEN];\n+\tu8 mask[ETHER_ADDR_LEN];\n+\n+\tstruct mpstcam_table *mpstcam; /* backptr */\n+\trte_atomic32_t refcnt;\n+};\n+\n+struct mpstcam_table {\n+\tu16 size;\n+\trte_rwlock_t lock;\n+\tu16 free_idx;\t/* next free index */\n+\tbool full;\t/* since free index can be present\n+\t\t\t * anywhere in the table, size and\n+\t\t\t * free_idx cannot alone determine\n+\t\t\t * if the table is full\n+\t\t\t */\n+\tstruct mps_tcam_entry entry[0];\n+};\n+\n+struct mpstcam_table *t4_init_mpstcam(struct adapter *adap);\n+void t4_cleanup_mpstcam(struct adapter *adap);\n+int cxgbe_mpstcam_alloc(struct port_info *pi, const u8 *mac, const u8 *mask);\n+int cxgbe_mpstcam_remove(struct port_info *pi, u16 idx);\n+int cxgbe_mpstcam_modify(struct port_info *pi, int idx, const u8 *addr);\n+\n+#endif /* _CXGBE_MPSTCAM_H_ */\n",
    "prefixes": [
        "3/4"
    ]
}