octeontx2-af: Enable mkex profile
authorVamsi Attunuru <vamsi.attunuru@marvell.com>
Sun, 2 Dec 2018 12:47:49 +0000 (18:17 +0530)
committerDavid S. Miller <davem@davemloft.net>
Tue, 4 Dec 2018 00:23:08 +0000 (16:23 -0800)
The following set of NPC registers allow the driver to configure NPC
to generate different key value schemes to compare against packet
payload in MCAM search.

NPC_AF_INTF(0..1)_KEX_CFG
NPC_AF_KEX_LDATA(0..1)_FLAGS_CFG
NPC_AF_INTF(0..1)_LID(0..7)_LT(0..15)_LD(0..1)_CFG
NPC_AF_INTF(0..1)_LDATA(0..1)_FLAGS(0..15)_CFG

Currently, the AF driver populates these registers to
configure the default values to address the most common
use cases such as key generation for channel number + DMAC.

The secure firmware stores different configuration
value of these registers to enable different NPC use case
along with the name for the lookup.

Patch loads profile binary from secure firmware over
the exiting CGX mailbox interface and apply the profile.

AF driver shall fall back to the default configuration
in case of any errors.

The AF consumer driver can know the selected profile
on response to NPC_GET_KEX_CFG mailbox by introducing
mkex_pfl_name in the struct npc_get_kex_cfg_rsp.

Signed-off-by: Vamsi Attunuru <vamsi.attunuru@marvell.com>
Signed-off-by: Jerin Jacob <jerinj@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.h
drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/npc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu.c
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c

index 4c94571e03ebadfc8e31758b065a9f8ea4d77b72..742f0c1f60df785eabe83ff5ab18746526100e2a 100644 (file)
@@ -498,6 +498,60 @@ static inline bool cgx_event_is_linkevent(u64 event)
                return false;
 }
 
+static inline int cgx_fwi_get_mkex_prfl_sz(u64 *prfl_sz,
+                                          struct cgx *cgx)
+{
+       u64 req = 0;
+       u64 resp;
+       int err;
+
+       req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_SIZE, req);
+       err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
+       if (!err)
+               *prfl_sz = FIELD_GET(RESP_MKEX_PRFL_SIZE, resp);
+
+       return err;
+}
+
+static inline int cgx_fwi_get_mkex_prfl_addr(u64 *prfl_addr,
+                                            struct cgx *cgx)
+{
+       u64 req = 0;
+       u64 resp;
+       int err;
+
+       req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_MKEX_PRFL_ADDR, req);
+       err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
+       if (!err)
+               *prfl_addr = FIELD_GET(RESP_MKEX_PRFL_ADDR, resp);
+
+       return err;
+}
+
+int cgx_get_mkex_prfl_info(u64 *addr, u64 *size)
+{
+       struct cgx *cgx_dev;
+       int err;
+
+       if (!addr || !size)
+               return -EINVAL;
+
+       cgx_dev = list_first_entry(&cgx_list, struct cgx, cgx_list);
+       if (!cgx_dev)
+               return -ENXIO;
+
+       err = cgx_fwi_get_mkex_prfl_sz(size, cgx_dev);
+       if (err)
+               return -EIO;
+
+       err = cgx_fwi_get_mkex_prfl_addr(addr, cgx_dev);
+       if (err)
+               return -EIO;
+
+       return 0;
+}
+EXPORT_SYMBOL(cgx_get_mkex_prfl_info);
+
 static irqreturn_t cgx_fwi_event_handler(int irq, void *data)
 {
        struct lmac *lmac = data;
index 8c2be84933216927dea326442607a9b8385ed172..206dc5dc1df8ea3caf227a8cab3e4b0fb0d66de2 100644 (file)
@@ -111,4 +111,5 @@ int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable);
 int cgx_get_link_info(void *cgxd, int lmac_id,
                      struct cgx_link_user_info *linfo);
 int cgx_lmac_linkup_start(void *cgxd);
+int cgx_get_mkex_prfl_info(u64 *addr, u64 *size);
 #endif /* CGX_H */
index 2d9fe51c66166efb22a612d0f09d8c9a3c25e23a..fb3ba4968a9bdeb61674ca73ca4d3a9d042a2df5 100644 (file)
@@ -78,6 +78,8 @@ enum cgx_cmd_id {
        CGX_CMD_LINK_STATE_CHANGE,
        CGX_CMD_MODE_CHANGE,            /* hot plug support */
        CGX_CMD_INTF_SHUTDOWN,
+       CGX_CMD_GET_MKEX_PRFL_SIZE,
+       CGX_CMD_GET_MKEX_PRFL_ADDR
 };
 
 /* async event ids */
@@ -137,6 +139,16 @@ enum cgx_cmd_own {
  */
 #define RESP_MAC_ADDR          GENMASK_ULL(56, 9)
 
+/* Response to cmd ID as CGX_CMD_GET_MKEX_PRFL_SIZE with cmd status as
+ * CGX_STAT_SUCCESS
+ */
+#define RESP_MKEX_PRFL_SIZE            GENMASK_ULL(63, 9)
+
+/* Response to cmd ID as CGX_CMD_GET_MKEX_PRFL_ADDR with cmd status as
+ * CGX_STAT_SUCCESS
+ */
+#define RESP_MKEX_PRFL_ADDR            GENMASK_ULL(63, 9)
+
 /* Response to cmd ID - CGX_CMD_LINK_BRING_UP/DOWN, event ID CGX_EVT_LINK_CHANGE
  * status can be either CGX_STAT_FAIL or CGX_STAT_SUCCESS
  *
index f8c332b1acec01c5a841a02fab6a8ea03348733f..76a4575d18ff28779a7d998b5b7d35566fede9ea 100644 (file)
@@ -788,6 +788,8 @@ struct npc_get_kex_cfg_rsp {
        u64 intf_lid_lt_ld[NPC_MAX_INTF][NPC_MAX_LID][NPC_MAX_LT][NPC_MAX_LD];
        /* NPC_AF_INTF(0..1)_LDATA(0..1)_FLAGS(0..15)_CFG */
        u64 intf_ld_flags[NPC_MAX_INTF][NPC_MAX_LD][NPC_MAX_LFL];
+#define MKEX_NAME_LEN 128
+       u8 mkex_pfl_name[MKEX_NAME_LEN];
 };
 
 #endif /* MBOX_H */
index a7a20afb3ba0c6077688d727a8ae7b7edf8ca168..8d6d90fdfb739c2f4398d96d4da2693135a19066 100644 (file)
@@ -265,4 +265,22 @@ struct nix_rx_action {
 #define VTAG0_LID_MASK         GENMASK_ULL(10, 8)
 #define VTAG0_RELPTR_MASK      GENMASK_ULL(7, 0)
 
+struct npc_mcam_kex {
+       /* MKEX Profle Header */
+       u64 mkex_sign; /* "mcam-kex-profile" (8 bytes/ASCII characters) */
+       u8 name[MKEX_NAME_LEN];   /* MKEX Profile name */
+       u64 cpu_model;   /* Format as profiled by CPU hardware */
+       u64 kpu_version; /* KPU firmware/profile version */
+       u64 reserved; /* Reserved for extension */
+
+       /* MKEX Profle Data */
+       u64 keyx_cfg[NPC_MAX_INTF]; /* NPC_AF_INTF(0..1)_KEX_CFG */
+       /* NPC_AF_KEX_LDATA(0..1)_FLAGS_CFG */
+       u64 kex_ld_flags[NPC_MAX_LD];
+       /* NPC_AF_INTF(0..1)_LID(0..7)_LT(0..15)_LD(0..1)_CFG */
+       u64 intf_lid_lt_ld[NPC_MAX_INTF][NPC_MAX_LID][NPC_MAX_LT][NPC_MAX_LD];
+       /* NPC_AF_INTF(0..1)_LDATA(0..1)_FLAGS(0..15)_CFG */
+       u64 intf_ld_flags[NPC_MAX_INTF][NPC_MAX_LD][NPC_MAX_LFL];
+} __packed;
+
 #endif /* NPC_H */
index 4d061d9719561017ac05afaa2dd397fdd93282b6..e581091c09c4e328ffca2a4d10b99af391d62c42 100644 (file)
@@ -52,6 +52,10 @@ MODULE_LICENSE("GPL v2");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DEVICE_TABLE(pci, rvu_id_table);
 
+static char *mkex_profile; /* MKEX profile name */
+module_param(mkex_profile, charp, 0000);
+MODULE_PARM_DESC(mkex_profile, "MKEX profile name string");
+
 /* Poll a RVU block's register 'offset', for a 'zero'
  * or 'nonzero' at bits specified by 'mask'
  */
@@ -2359,6 +2363,14 @@ static void rvu_disable_sriov(struct rvu *rvu)
        pci_disable_sriov(rvu->pdev);
 }
 
+static void rvu_update_module_params(struct rvu *rvu)
+{
+       const char *default_pfl_name = "default";
+
+       strscpy(rvu->mkex_pfl_name,
+               mkex_profile ? mkex_profile : default_pfl_name, MKEX_NAME_LEN);
+}
+
 static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct device *dev = &pdev->dev;
@@ -2412,6 +2424,9 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_release_regions;
        }
 
+       /* Store module params in rvu structure */
+       rvu_update_module_params(rvu);
+
        /* Check which blocks the HW supports */
        rvu_check_block_implemented(rvu);
 
index 3abdb98fb3481dd034023132edf6c8573de7d635..c9d60b0554c0ff5f0e5a9c0087a9b487679ee1b9 100644 (file)
@@ -261,6 +261,8 @@ struct rvu {
        struct                  workqueue_struct *cgx_evh_wq;
        spinlock_t              cgx_evq_lock; /* cgx event queue lock */
        struct list_head        cgx_evq_head; /* cgx event queue head */
+
+       char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */
 };
 
 static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val)
index bf81031f0fdd0cf4c13657816ffd9bd6fe8f6ae5..15f70273e29c75789ff36d8f6da085b2468cad51 100644 (file)
@@ -16,6 +16,7 @@
 #include "rvu_reg.h"
 #include "rvu.h"
 #include "npc.h"
+#include "cgx.h"
 #include "npc_profile.h"
 
 #define RSVD_MCAM_ENTRIES_PER_PF       2 /* Bcast & Promisc */
@@ -731,6 +732,111 @@ static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
        SET_KEX_LD(NIX_INTF_RX, NPC_LID_LD, NPC_LT_LD_TCP, 1, cfg);
 }
 
+static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
+                                    struct npc_mcam_kex *mkex)
+{
+       int lid, lt, ld, fl;
+
+       rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX),
+                   mkex->keyx_cfg[NIX_INTF_RX]);
+       rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX),
+                   mkex->keyx_cfg[NIX_INTF_TX]);
+
+       for (ld = 0; ld < NPC_MAX_LD; ld++)
+               rvu_write64(rvu, blkaddr, NPC_AF_KEX_LDATAX_FLAGS_CFG(ld),
+                           mkex->kex_ld_flags[ld]);
+
+       for (lid = 0; lid < NPC_MAX_LID; lid++) {
+               for (lt = 0; lt < NPC_MAX_LT; lt++) {
+                       for (ld = 0; ld < NPC_MAX_LD; ld++) {
+                               SET_KEX_LD(NIX_INTF_RX, lid, lt, ld,
+                                          mkex->intf_lid_lt_ld[NIX_INTF_RX]
+                                          [lid][lt][ld]);
+
+                               SET_KEX_LD(NIX_INTF_TX, lid, lt, ld,
+                                          mkex->intf_lid_lt_ld[NIX_INTF_TX]
+                                          [lid][lt][ld]);
+                       }
+               }
+       }
+
+       for (ld = 0; ld < NPC_MAX_LD; ld++) {
+               for (fl = 0; fl < NPC_MAX_LFL; fl++) {
+                       SET_KEX_LDFLAGS(NIX_INTF_RX, ld, fl,
+                                       mkex->intf_ld_flags[NIX_INTF_RX]
+                                       [ld][fl]);
+
+                       SET_KEX_LDFLAGS(NIX_INTF_TX, ld, fl,
+                                       mkex->intf_ld_flags[NIX_INTF_TX]
+                                       [ld][fl]);
+               }
+       }
+}
+
+/* strtoull of "mkexprof" with base:36 */
+#define MKEX_SIGN      0x19bbfdbd15f
+#define MKEX_END_SIGN  0xdeadbeef
+
+static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr)
+{
+       const char *mkex_profile = rvu->mkex_pfl_name;
+       struct device *dev = &rvu->pdev->dev;
+       void __iomem *mkex_prfl_addr = NULL;
+       struct npc_mcam_kex *mcam_kex;
+       u64 prfl_addr;
+       u64 prfl_sz;
+
+       /* If user not selected mkex profile */
+       if (!strncmp(mkex_profile, "default", MKEX_NAME_LEN))
+               goto load_default;
+
+       if (cgx_get_mkex_prfl_info(&prfl_addr, &prfl_sz))
+               goto load_default;
+
+       if (!prfl_addr || !prfl_sz)
+               goto load_default;
+
+       mkex_prfl_addr = ioremap_wc(prfl_addr, prfl_sz);
+       if (!mkex_prfl_addr)
+               goto load_default;
+
+       mcam_kex = (struct npc_mcam_kex *)mkex_prfl_addr;
+
+       while (((s64)prfl_sz > 0) && (mcam_kex->mkex_sign != MKEX_END_SIGN)) {
+               /* Compare with mkex mod_param name string */
+               if (mcam_kex->mkex_sign == MKEX_SIGN &&
+                   !strncmp(mcam_kex->name, mkex_profile, MKEX_NAME_LEN)) {
+                       /* Due to an errata (35786) in A0 pass silicon,
+                        * parse nibble enable configuration has to be
+                        * identical for both Rx and Tx interfaces.
+                        */
+                       if (is_rvu_9xxx_A0(rvu) &&
+                           mcam_kex->keyx_cfg[NIX_INTF_RX] !=
+                           mcam_kex->keyx_cfg[NIX_INTF_TX])
+                               goto load_default;
+
+                       /* Program selected mkex profile */
+                       npc_program_mkex_profile(rvu, blkaddr, mcam_kex);
+
+                       goto unmap;
+               }
+
+               mcam_kex++;
+               prfl_sz -= sizeof(struct npc_mcam_kex);
+       }
+       dev_warn(dev, "Failed to load requested profile: %s\n",
+                rvu->mkex_pfl_name);
+
+load_default:
+       dev_info(rvu->dev, "Using default mkex profile\n");
+       /* Config packet data and flags extraction into PARSE result */
+       npc_config_ldata_extract(rvu, blkaddr);
+
+unmap:
+       if (mkex_prfl_addr)
+               iounmap(mkex_prfl_addr);
+}
+
 static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
                                 struct npc_kpu_profile_action *kpuaction,
                                 int kpu, int entry, bool pkind)
@@ -1068,8 +1174,8 @@ int rvu_npc_init(struct rvu *rvu)
        if (err)
                return err;
 
-       /* Config packet data and flags extraction into PARSE result */
-       npc_config_ldata_extract(rvu, blkaddr);
+       /* Configure MKEX profile */
+       npc_load_mkex_profile(rvu, blkaddr);
 
        /* Set TX miss action to UCAST_DEFAULT i.e
         * transmit the packet on NIX LF SQ's default channel.
@@ -2077,6 +2183,7 @@ int rvu_mbox_handler_npc_get_kex_cfg(struct rvu *rvu, struct msg_req *req,
                                        GET_KEX_LDFLAGS(NIX_INTF_TX, ld, fl);
                }
        }
+       memcpy(rsp->mkex_pfl_name, rvu->mkex_pfl_name, MKEX_NAME_LEN);
        return 0;
 }