netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support
@ 2019-11-20 17:47 sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 01/16] octeontx2-af: Interface backpressure configuration support sunil.kovvuri
                   ` (15 more replies)
  0 siblings, 16 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Sunil Goutham

From: Sunil Goutham <sgoutham@marvell.com>

SO HW block provides packet (or work) queueing, scheduling and
synchronization. Also supports priorities and ordering. TIM or the
timer HW block enables software to schedule SSO work for a future time.

This patch series adds support for SSO and TIM HW blocks, enables them
to be configured and used by RVU PF/VF devices or drivers.

Also added support for
- Backpressure configuration.
- Pause frames or flow control enabling/disabling.
- Added a shared data structure between firmware and RVU admin function
  (AF) which will be used to get static information like interface MAC
  addresses, link modes, speeds, autoneg support etc.
- FEC (Forward error correction) config support for CGX.
- Retrieve FEC stats, PHY EEPROM etc from firmware
- Retrieving CGX LMAC info and to toggle it.
- Added debug prints for each of error interrupts raised by NIX,
  NPA and SSO blocks. These will help in identifying configuration
  and underlying HW functionality issues.

Changes from v2:
   * Added documentation to give a high level overview of HW and
     different drivers which will be upstreamed and how they interact.
   * Fixed white space issues.
      - Sugested by Jakub Kicinski

Changes from v1:
   * Made changes to TIM HW block support patch to use
      generic API to get HW ticks.
   * Removed inline keyword
     - Suggested by David Miller.
   * Fixed sparse warnings
     - Reported by Kbuild test robot.

Andrew Pinski (1):
  octeontx2-af: Add TIM unit support.

Christina Jacob (1):
  octeontx2-af: Support to get CGX link info like current speed, fec etc

Geetha sowjanya (2):
  octeontx2-af: Interface backpressure configuration support
  octeontx2-af: Ingress and egress pause frame configuration

Jerin Jacob (2):
  octeontx2-af: add debug msgs for NPA block errors
  octeontx2-af: add debug msgs for NIX block errors

Kiran Kumar K (1):
  octeontx2-af: NPC Tx parsed data key extraction profile

Linu Cherian (1):
  octeontx2-af: Add support for importing firmware data

Pavan Nikhilesh (3):
  octeontx2-af: Config support for per HWGRP thresholds
  octeontx2-af: add debug msgs for SSO block errors
  octeontx2-af: add debugfs support for sso

Radha Mohan Chintakuntla (1):
  octeontx2-af: Add SSO unit support to the AF driver

Subbaraya Sundeep (1):
  octeontx2-af: verify ingress channel in MCAM entry

Sunil Goutham (3):
  octeontx2-af: Cleanup CGX config permission checks
  octeontx2-af: Set discovery ID for RVUM block
  Documentation: net: octeontx2: Add RVU HW and drivers overview.

 Documentation/networking/device_drivers/index.rst  |    1 +
 .../device_drivers/marvell/octeontx2.rst           |  162 +
 .../marvell/resource_virtualization_unit.svg       | 3297 ++++++++++++++++++++
 MAINTAINERS                                        |    1 +
 drivers/net/ethernet/marvell/octeontx2/af/Makefile |    3 +-
 drivers/net/ethernet/marvell/octeontx2/af/cgx.c    |  434 ++-
 drivers/net/ethernet/marvell/octeontx2/af/cgx.h    |   26 +-
 .../net/ethernet/marvell/octeontx2/af/cgx_fw_if.h  |   78 +-
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  322 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |  197 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   72 +
 .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c    |  178 +-
 .../ethernet/marvell/octeontx2/af/rvu_debugfs.c    |  699 +++++
 .../net/ethernet/marvell/octeontx2/af/rvu_nix.c    |  388 ++-
 .../net/ethernet/marvell/octeontx2/af/rvu_npa.c    |  243 +-
 .../net/ethernet/marvell/octeontx2/af/rvu_npc.c    |  282 +-
 .../net/ethernet/marvell/octeontx2/af/rvu_reg.h    |  192 +-
 .../net/ethernet/marvell/octeontx2/af/rvu_sso.c    | 1146 +++++++
 .../net/ethernet/marvell/octeontx2/af/rvu_struct.h |   44 +
 .../net/ethernet/marvell/octeontx2/af/rvu_tim.c    |  322 ++
 20 files changed, 7950 insertions(+), 137 deletions(-)
 create mode 100644 Documentation/networking/device_drivers/marvell/octeontx2.rst
 create mode 100644 Documentation/networking/device_drivers/marvell/resource_virtualization_unit.svg
 create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
 create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_tim.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v3 01/16] octeontx2-af: Interface backpressure configuration support
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 02/16] octeontx2-af: Add support for importing firmware data sunil.kovvuri
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Geetha sowjanya, Sunil Goutham

From: Geetha sowjanya <gakula@marvell.com>

Enables backpressure and assigns BPID for CGX and LBK channels.
96xx support upto 512 BPIDs, these BPIDs are statically divided
across CGX/LBK/SDP interfaces as follows.
BPIDs   0 - 191 are mapped to LMAC channels.
BPIDs 192 - 255 are mapped to LBK channels.
BPIDs 256 - 511 are mapped to SDP channels.

BPIDs across CGX LMAC channels are divided as follows.
CGX(0)_LMAC(0)_CHAN(0 - 15) mapped to BPIDs(0 - 15)
CGX(0)_LMAC(1)_CHAN(0 - 15) mapped to BPIDs(16 - 31)
.......
CGX(1)_LMAC(0)_CHAN(0 - 15) mapped to BPIDs(64 - 79)
....

Signed-off-by: Geetha sowjanya <gakula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  26 +++-
 .../net/ethernet/marvell/octeontx2/af/rvu_nix.c    | 152 ++++++++++++++++++++-
 .../net/ethernet/marvell/octeontx2/af/rvu_npa.c    |  13 +-
 3 files changed, 184 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index a589748..68ec248 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -125,7 +125,7 @@ static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox,
 M(READY,		0x001, ready, msg_req, ready_msg_rsp)		\
 M(ATTACH_RESOURCES,	0x002, attach_resources, rsrc_attach, msg_rsp)	\
 M(DETACH_RESOURCES,	0x003, detach_resources, rsrc_detach, msg_rsp)	\
-M(MSIX_OFFSET,		0x004, msix_offset, msg_req, msix_offset_rsp)	\
+M(MSIX_OFFSET,		0x005, msix_offset, msg_req, msix_offset_rsp)	\
 M(VF_FLR,		0x006, vf_flr, msg_req, msg_rsp)		\
 M(GET_HW_CAP,		0x008, get_hw_cap, msg_req, get_hw_cap_rsp)	\
 /* CGX mbox IDs (range 0x200 - 0x3FF) */				\
@@ -210,7 +210,10 @@ M(NIX_SET_RX_CFG,	0x8010, nix_set_rx_cfg, nix_rx_cfg, msg_rsp)	\
 M(NIX_LSO_FORMAT_CFG,	0x8011, nix_lso_format_cfg,			\
 				 nix_lso_format_cfg,			\
 				 nix_lso_format_cfg_rsp)		\
-M(NIX_RXVLAN_ALLOC,	0x8012, nix_rxvlan_alloc, msg_req, msg_rsp)
+M(NIX_RXVLAN_ALLOC,	0x8012, nix_rxvlan_alloc, msg_req, msg_rsp)	\
+M(NIX_BP_ENABLE,	0x8016, nix_bp_enable, nix_bp_cfg_req,	\
+				nix_bp_cfg_rsp)	\
+M(NIX_BP_DISABLE,	0x8017, nix_bp_disable, nix_bp_cfg_req, msg_rsp) \
 
 /* Messages initiated by AF (range 0xC00 - 0xDFF) */
 #define MBOX_UP_CGX_MESSAGES						\
@@ -670,6 +673,25 @@ struct nix_lso_format_cfg_rsp {
 	u8 lso_format_idx;
 };
 
+struct nix_bp_cfg_req {
+	struct mbox_msghdr hdr;
+	u16	chan_base; /* Starting channel number */
+	u8	chan_cnt; /* Number of channels */
+	u8	bpid_per_chan;
+	/* bpid_per_chan = 0  assigns single bp id for range of channels */
+	/* bpid_per_chan = 1 assigns separate bp id for each channel */
+};
+
+/* PF can be mapped to either CGX or LBK interface,
+ * so maximum 64 channels are possible.
+ */
+#define NIX_MAX_BPID_CHAN	64
+struct nix_bp_cfg_rsp {
+	struct mbox_msghdr hdr;
+	u16	chan_bpid[NIX_MAX_BPID_CHAN]; /* Channel and bpid mapping */
+	u8	chan_cnt; /* Number of channel for which bpids are assigned */
+};
+
 /* NPC mbox message structs */
 
 #define NPC_MCAM_ENTRY_INVALID	0xFFFF
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 8a59f7d..cb1d653 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -18,6 +18,8 @@
 #include "cgx.h"
 
 static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add);
+static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
+			    int type, int chan_id);
 
 enum mc_tbl_sz {
 	MC_TBL_SZ_256,
@@ -253,6 +255,142 @@ static void nix_interface_deinit(struct rvu *rvu, u16 pcifunc, u8 nixlf)
 	rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
 }
 
+int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu,
+				    struct nix_bp_cfg_req *req,
+				    struct msg_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	struct rvu_pfvf *pfvf;
+	int blkaddr, pf, type;
+	u16 chan_base, chan;
+	u64 cfg;
+
+	pf = rvu_get_pf(pcifunc);
+	type = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX;
+	if (!is_pf_cgxmapped(rvu, pf) && type != NIX_INTF_TYPE_LBK)
+		return 0;
+
+	pfvf = rvu_get_pfvf(rvu, pcifunc);
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+
+	chan_base = pfvf->rx_chan_base + req->chan_base;
+	for (chan = chan_base; chan < (chan_base + req->chan_cnt); chan++) {
+		cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(chan));
+		rvu_write64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(chan),
+			    cfg & ~BIT_ULL(16));
+	}
+	return 0;
+}
+
+static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
+			    int type, int chan_id)
+{
+	int bpid, blkaddr, lmac_chan_cnt;
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 cgx_bpid_cnt, lbk_bpid_cnt;
+	struct rvu_pfvf *pfvf;
+	u8 cgx_id, lmac_id;
+	u64 cfg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, req->hdr.pcifunc);
+	cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
+	lmac_chan_cnt = cfg & 0xFF;
+
+	cgx_bpid_cnt = hw->cgx_links * lmac_chan_cnt;
+	lbk_bpid_cnt = hw->lbk_links * ((cfg >> 16) & 0xFF);
+
+	pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
+
+	/* Backpressure IDs range division
+	 * CGX  channles are mapped to (0 - 191) BPIDs
+	 * LBK	channles are mapped to (192 - 255) BPIDs
+	 * SDP  channles are mapped to (256 - 511) BPIDs
+	 *
+	 * Lmac channles and bpids mapped as follows
+	 * cgx(0)_lmac(0)_chan(0 - 15) = bpid(0 - 15)
+	 * cgx(0)_lmac(1)_chan(0 - 15) = bpid(16 - 31) ....
+	 * cgx(1)_lmac(0)_chan(0 - 15) = bpid(64 - 79) ....
+	 */
+	switch (type) {
+	case NIX_INTF_TYPE_CGX:
+		if ((req->chan_base + req->chan_cnt) > 15)
+			return -EINVAL;
+		rvu_get_cgx_lmac_id(pfvf->cgx_lmac, &cgx_id, &lmac_id);
+		/* Assign bpid based on cgx, lmac and chan id */
+		bpid = (cgx_id * hw->lmac_per_cgx * lmac_chan_cnt) +
+			(lmac_id * lmac_chan_cnt) + req->chan_base;
+
+		if (req->bpid_per_chan)
+			bpid += chan_id;
+		if (bpid > cgx_bpid_cnt)
+			return -EINVAL;
+		break;
+
+	case NIX_INTF_TYPE_LBK:
+		if ((req->chan_base + req->chan_cnt) > 63)
+			return -EINVAL;
+		bpid = cgx_bpid_cnt + req->chan_base;
+		if (req->bpid_per_chan)
+			bpid += chan_id;
+		if (bpid > (cgx_bpid_cnt + lbk_bpid_cnt))
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return bpid;
+}
+
+int rvu_mbox_handler_nix_bp_enable(struct rvu *rvu,
+				   struct nix_bp_cfg_req *req,
+				   struct nix_bp_cfg_rsp *rsp)
+{
+	int blkaddr, pf, type, chan_id = 0;
+	u16 pcifunc = req->hdr.pcifunc;
+	struct rvu_pfvf *pfvf;
+	u16 chan_base, chan;
+	s16 bpid, bpid_base;
+	u64 cfg;
+
+	pf = rvu_get_pf(pcifunc);
+	type = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX;
+
+	/* Enable backpressure only for CGX mapped PFs and LBK interface */
+	if (!is_pf_cgxmapped(rvu, pf) && type != NIX_INTF_TYPE_LBK)
+		return 0;
+
+	pfvf = rvu_get_pfvf(rvu, pcifunc);
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+
+	bpid_base = rvu_nix_get_bpid(rvu, req, type, chan_id);
+	chan_base = pfvf->rx_chan_base + req->chan_base;
+	bpid = bpid_base;
+
+	for (chan = chan_base; chan < (chan_base + req->chan_cnt); chan++) {
+		if (bpid < 0) {
+			dev_warn(rvu->dev, "Fail to enable backpessure\n");
+			return -EINVAL;
+		}
+
+		cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(chan));
+		rvu_write64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(chan),
+			    cfg | (bpid & 0xFF) | BIT_ULL(16));
+		chan_id++;
+		bpid = rvu_nix_get_bpid(rvu, req, type, chan_id);
+	}
+
+	for (chan = 0; chan < req->chan_cnt; chan++) {
+		/* Map channel and bpid assign to it */
+		rsp->chan_bpid[chan] = ((req->chan_base + chan) & 0x7F) << 10 |
+					(bpid_base & 0x3FF);
+		if (req->bpid_per_chan)
+			bpid_base++;
+	}
+	rsp->chan_cnt = req->chan_cnt;
+
+	return 0;
+}
+
 static void nix_setup_lso_tso_l3(struct rvu *rvu, int blkaddr,
 				 u64 format, bool v4, u64 *fidx)
 {
@@ -545,6 +683,11 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req,
 	 */
 	inst.res_addr = (u64)aq->res->iova;
 
+	/* Hardware uses same aq->res->base for updating result of
+	 * previous instruction hence wait here till it is done.
+	 */
+	spin_lock(&aq->lock);
+
 	/* Clean result + context memory */
 	memset(aq->res->base, 0, aq->res->entry_sz);
 	/* Context needs to be written at RES_ADDR + 128 */
@@ -589,11 +732,10 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req,
 		break;
 	default:
 		rc = NIX_AF_ERR_AQ_ENQUEUE;
+		spin_unlock(&aq->lock);
 		return rc;
 	}
 
-	spin_lock(&aq->lock);
-
 	/* Submit the instruction to AQ */
 	rc = nix_aq_enqueue_wait(rvu, block, &inst);
 	if (rc) {
@@ -698,6 +840,8 @@ static int nix_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
 	if (req->ctype == NIX_AQ_CTYPE_CQ) {
 		aq_req.cq.ena = 0;
 		aq_req.cq_mask.ena = 1;
+		aq_req.cq.bp_ena = 0;
+		aq_req.cq_mask.bp_ena = 1;
 		q_cnt = pfvf->cq_ctx->qsize;
 		bmap = pfvf->cq_bmap;
 	}
@@ -3060,6 +3204,10 @@ int rvu_nix_init(struct rvu *rvu)
 
 		/* Initialize CGX/LBK/SDP link credits, min/max pkt lengths */
 		nix_link_config(rvu, blkaddr);
+
+		/* Enable Channel backpressure */
+		rvu_write64(rvu, blkaddr, NIX_AF_RX_CFG, BIT_ULL(0));
+
 	}
 	return 0;
 }
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
index 6e7c7f4..67471cb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
@@ -94,6 +94,11 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
 	 */
 	inst.res_addr = (u64)aq->res->iova;
 
+	/* Hardware uses same aq->res->base for updating result of
+	 * previous instruction hence wait here till it is done.
+	 */
+	spin_lock(&aq->lock);
+
 	/* Clean result + context memory */
 	memset(aq->res->base, 0, aq->res->entry_sz);
 	/* Context needs to be written at RES_ADDR + 128 */
@@ -138,10 +143,10 @@ int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
 		break;
 	}
 
-	if (rc)
+	if (rc) {
+		spin_unlock(&aq->lock);
 		return rc;
-
-	spin_lock(&aq->lock);
+	}
 
 	/* Submit the instruction to AQ */
 	rc = npa_aq_enqueue_wait(rvu, block, &inst);
@@ -218,6 +223,8 @@ static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req)
 	} else if (req->ctype == NPA_AQ_CTYPE_AURA) {
 		aq_req.aura.ena = 0;
 		aq_req.aura_mask.ena = 1;
+		aq_req.aura.bp_ena = 0;
+		aq_req.aura_mask.bp_ena = 1;
 		cnt = pfvf->aura_ctx->qsize;
 		bmap = pfvf->aura_bmap;
 	}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 02/16] octeontx2-af: Add support for importing firmware data
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 01/16] octeontx2-af: Interface backpressure configuration support sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 03/16] octeontx2-af: Cleanup CGX config permission checks sunil.kovvuri
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev
  Cc: davem, jakub.kicinski, Linu Cherian, Rakesh Babu, Vamsi Attunuru,
	Sunil Goutham

From: Linu Cherian <lcherian@marvell.com>

Firmware data is essentially a block of one time configuration data
exported from firmware to kernel through shared memory. Base address
of this memory is obtained through CGX firmware interface commands.

With this in place, MAC address of CGX mapped functions are inited
from firmware data if available else they are inited with
random MAC address.

Also
- Added a new mbox for PF/VF to retrieve it's MAC address.
- Now RVU MSIX vector address is also retrieved from this fwdata struct
  instead of from CSR. Otherwise when kexec/kdump crash kernel loads
  CSR will have a IOVA setup by primary kernel which impacts
  RVU PF/VF's interrupts.

Signed-off-by: Linu Cherian <lcherian@marvell.com>
Signed-off-by: Rakesh Babu <rsaladi2@marvell.com>
Signed-off-by: Vamsi Attunuru <vamsi.attunuru@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/cgx.c    |  18 ++++
 drivers/net/ethernet/marvell/octeontx2/af/cgx.h    |   1 +
 .../net/ethernet/marvell/octeontx2/af/cgx_fw_if.h  |   8 +-
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |   9 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    | 112 +++++++++++++++++++--
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |  30 ++++++
 .../net/ethernet/marvell/octeontx2/af/rvu_nix.c    |  23 ++++-
 7 files changed, 192 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index 5ca7886..aa2ce5e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -697,6 +697,24 @@ int cgx_lmac_evh_unregister(void *cgxd, int lmac_id)
 }
 EXPORT_SYMBOL(cgx_lmac_evh_unregister);
 
+int cgx_get_fwdata_base(u64 *base)
+{
+	u64 req = 0, resp;
+	struct cgx *cgx;
+	int err;
+
+	cgx = list_first_entry_or_null(&cgx_list, struct cgx, cgx_list);
+	if (!cgx)
+		return -ENXIO;
+
+	req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_FWD_BASE, req);
+	err = cgx_fwi_cmd_generic(req, &resp, cgx, 0);
+	if (!err)
+		*base = FIELD_GET(RESP_FWD_BASE, resp);
+
+	return err;
+}
+
 static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable)
 {
 	u64 req = 0;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index 9343bf3..ad47cb8 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -124,5 +124,6 @@ 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_fwdata_base(u64 *base);
 int cgx_get_mkex_prfl_info(u64 *addr, u64 *size);
 #endif /* CGX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
index 473d975..c3702fa 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
@@ -79,7 +79,8 @@ enum cgx_cmd_id {
 	CGX_CMD_MODE_CHANGE,		/* hot plug support */
 	CGX_CMD_INTF_SHUTDOWN,
 	CGX_CMD_GET_MKEX_PRFL_SIZE,
-	CGX_CMD_GET_MKEX_PRFL_ADDR
+	CGX_CMD_GET_MKEX_PRFL_ADDR,
+	CGX_CMD_GET_FWD_BASE,		/* get base address of shared FW data */
 };
 
 /* async event ids */
@@ -149,6 +150,11 @@ enum cgx_cmd_own {
  */
 #define RESP_MKEX_PRFL_ADDR		GENMASK_ULL(63, 9)
 
+/* Response to cmd ID as CGX_CMD_GET_FWD_BASE with cmd status as
+ * CGX_STAT_SUCCESS
+ */
+#define RESP_FWD_BASE		GENMASK_ULL(56, 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
  *
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 68ec248..c68266a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -214,6 +214,7 @@ M(NIX_RXVLAN_ALLOC,	0x8012, nix_rxvlan_alloc, msg_req, msg_rsp)	\
 M(NIX_BP_ENABLE,	0x8016, nix_bp_enable, nix_bp_cfg_req,	\
 				nix_bp_cfg_rsp)	\
 M(NIX_BP_DISABLE,	0x8017, nix_bp_disable, nix_bp_cfg_req, msg_rsp) \
+M(NIX_GET_MAC_ADDR, 0x8018, nix_get_mac_addr, msg_req, nix_get_mac_addr_rsp)
 
 /* Messages initiated by AF (range 0xC00 - 0xDFF) */
 #define MBOX_UP_CGX_MESSAGES						\
@@ -253,7 +254,8 @@ enum rvu_af_status {
 
 struct ready_msg_rsp {
 	struct mbox_msghdr hdr;
-	u16    sclk_feq;	/* SCLK frequency */
+	u16    sclk_freq;	/* SCLK frequency (in MHz) */
+	u16    rclk_freq;	/* RCLK frequency (in MHz) */
 };
 
 /* Structure for requesting resource provisioning.
@@ -621,6 +623,11 @@ struct nix_set_mac_addr {
 	u8 mac_addr[ETH_ALEN]; /* MAC address to be set for this pcifunc */
 };
 
+struct nix_get_mac_addr_rsp {
+	struct mbox_msghdr hdr;
+	u8 mac_addr[ETH_ALEN];
+};
+
 struct nix_mark_format_cfg {
 	struct mbox_msghdr hdr;
 	u8 offset;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index 5c190c3..d221540 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -603,7 +603,12 @@ static int rvu_setup_msix_resources(struct rvu *rvu)
 	 */
 	cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_CONST);
 	max_msix = cfg & 0xFFFFF;
-	phy_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE);
+	if (rvu->fwdata && rvu->fwdata->msixtr_base)
+		phy_addr = rvu->fwdata->msixtr_base;
+	else
+		phy_addr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE);
+	/* Register save */
+	rvu->msixtr_base_phy = phy_addr;
 	iova = dma_map_resource(rvu->dev, phy_addr,
 				max_msix * PCI_MSIX_ENTRY_SIZE,
 				DMA_BIDIRECTIONAL, 0);
@@ -617,6 +622,13 @@ static int rvu_setup_msix_resources(struct rvu *rvu)
 	return 0;
 }
 
+static void rvu_reset_msix(struct rvu *rvu)
+{
+	/* Restore msixtr base register */
+	rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_MSIXTR_BASE,
+		    rvu->msixtr_base_phy);
+}
+
 static void rvu_free_hw_resources(struct rvu *rvu)
 {
 	struct rvu_hwinfo *hw = rvu->hw;
@@ -655,9 +667,81 @@ static void rvu_free_hw_resources(struct rvu *rvu)
 			   max_msix * PCI_MSIX_ENTRY_SIZE,
 			   DMA_BIDIRECTIONAL, 0);
 
+	rvu_reset_msix(rvu);
 	mutex_destroy(&rvu->rsrc_lock);
 }
 
+static void rvu_setup_pfvf_macaddress(struct rvu *rvu)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	int pf, vf, numvfs, hwvf;
+	struct rvu_pfvf *pfvf;
+	u64 *mac;
+
+	for (pf = 0; pf < hw->total_pfs; pf++) {
+		if (!is_pf_cgxmapped(rvu, pf))
+			continue;
+		/* Assign MAC address to PF */
+		pfvf = &rvu->pf[pf];
+		if (rvu->fwdata && pf < PF_MACNUM_MAX) {
+			mac = &rvu->fwdata->pf_macs[pf];
+			if (*mac)
+				u64_to_ether_addr(*mac, pfvf->mac_addr);
+			else
+				eth_random_addr(pfvf->mac_addr);
+		} else {
+			eth_random_addr(pfvf->mac_addr);
+		}
+
+		/* Assign MAC address to VFs */
+		rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf);
+		for (vf = 0; vf < numvfs; vf++, hwvf++) {
+			pfvf =  &rvu->hwvf[hwvf];
+			if (rvu->fwdata && hwvf < VF_MACNUM_MAX) {
+				mac = &rvu->fwdata->vf_macs[hwvf];
+				if (*mac)
+					u64_to_ether_addr(*mac, pfvf->mac_addr);
+				else
+					eth_random_addr(pfvf->mac_addr);
+			} else {
+				eth_random_addr(pfvf->mac_addr);
+			}
+		}
+	}
+}
+
+static int rvu_fwdata_init(struct rvu *rvu)
+{
+	u64 fwdbase;
+	int err;
+
+	/* Get firmware data base address */
+	err = cgx_get_fwdata_base(&fwdbase);
+	if (err)
+		goto fail;
+	rvu->fwdata = (struct rvu_fwdata *)
+				ioremap_wc(fwdbase, sizeof(struct rvu_fwdata));
+	if (!rvu->fwdata)
+		goto fail;
+	if (!is_rvu_fwdata_valid(rvu)) {
+		dev_err(rvu->dev,
+			"Mismatch in 'fwdata' struct btw kernel and firmware\n");
+		iounmap((void __iomem *)rvu->fwdata);
+		rvu->fwdata = NULL;
+		return -EINVAL;
+	}
+	return 0;
+fail:
+	dev_info(rvu->dev, "Unable to fetch 'fwdata' from firmware\n");
+	return -EIO;
+}
+
+static void rvu_fwdata_exit(struct rvu *rvu)
+{
+	if (rvu->fwdata)
+		iounmap((void __iomem *)rvu->fwdata);
+}
+
 static int rvu_setup_hw_resources(struct rvu *rvu)
 {
 	struct rvu_hwinfo *hw = rvu->hw;
@@ -813,6 +897,8 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
 
 	mutex_init(&rvu->rsrc_lock);
 
+	rvu_fwdata_init(rvu);
+
 	err = rvu_setup_msix_resources(rvu);
 	if (err)
 		return err;
@@ -825,8 +911,10 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
 		/* Allocate memory for block LF/slot to pcifunc mapping info */
 		block->fn_map = devm_kcalloc(rvu->dev, block->lf.max,
 					     sizeof(u16), GFP_KERNEL);
-		if (!block->fn_map)
-			return -ENOMEM;
+		if (!block->fn_map) {
+			err = -ENOMEM;
+			goto msix_err;
+		}
 
 		/* Scan all blocks to check if low level firmware has
 		 * already provisioned any of the resources to a PF/VF.
@@ -836,11 +924,14 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
 
 	err = rvu_npc_init(rvu);
 	if (err)
-		goto exit;
+		goto fwdata_err;
 
 	err = rvu_cgx_init(rvu);
 	if (err)
-		goto exit;
+		goto fwdata_err;
+
+	/* Assign MACs for CGX mapped functions */
+	rvu_setup_pfvf_macaddress(rvu);
 
 	err = rvu_npa_init(rvu);
 	if (err)
@@ -854,7 +945,10 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
 
 cgx_err:
 	rvu_cgx_exit(rvu);
-exit:
+fwdata_err:
+	rvu_fwdata_exit(rvu);
+msix_err:
+	rvu_reset_msix(rvu);
 	return err;
 }
 
@@ -901,6 +995,10 @@ int rvu_aq_alloc(struct rvu *rvu, struct admin_queue **ad_queue,
 int rvu_mbox_handler_ready(struct rvu *rvu, struct msg_req *req,
 			   struct ready_msg_rsp *rsp)
 {
+	if (rvu->fwdata) {
+		rsp->rclk_freq = rvu->fwdata->rclk;
+		rsp->sclk_freq = rvu->fwdata->sclk;
+	}
 	return 0;
 }
 
@@ -2506,6 +2604,7 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	rvu_mbox_destroy(&rvu->afpf_wq_info);
 err_hwsetup:
 	rvu_cgx_exit(rvu);
+	rvu_fwdata_exit(rvu);
 	rvu_reset_all_blocks(rvu);
 	rvu_free_hw_resources(rvu);
 err_release_regions:
@@ -2527,6 +2626,7 @@ static void rvu_remove(struct pci_dev *pdev)
 	rvu_unregister_interrupts(rvu);
 	rvu_flr_wq_destroy(rvu);
 	rvu_cgx_exit(rvu);
+	rvu_fwdata_exit(rvu);
 	rvu_mbox_destroy(&rvu->afpf_wq_info);
 	rvu_disable_sriov(rvu);
 	rvu_reset_all_blocks(rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 51c206f..3691809 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -269,6 +269,26 @@ struct mbox_wq_info {
 	struct workqueue_struct *mbox_wq;
 };
 
+struct rvu_fwdata {
+#define RVU_FWDATA_HEADER_MAGIC	0xCFDA	/* Custom Firmware Data */
+#define RVU_FWDATA_VERSION	0x0001
+	u32 header_magic;
+	u32 version;		/* version id */
+
+	/* MAC address */
+#define PF_MACNUM_MAX	32
+#define VF_MACNUM_MAX	256
+	u64 pf_macs[PF_MACNUM_MAX];
+	u64 vf_macs[VF_MACNUM_MAX];
+	u64 sclk;
+	u64 rclk;
+	u64 mcam_addr;
+	u64 mcam_sz;
+	u64 msixtr_base;
+#define FWDATA_RESERVED_MEM 1023
+	u64 reserved[FWDATA_RESERVED_MEM];
+};
+
 struct rvu {
 	void __iomem		*afreg_base;
 	void __iomem		*pfreg_base;
@@ -294,6 +314,7 @@ struct rvu {
 	char			*irq_name;
 	bool			*irq_allocated;
 	dma_addr_t		msix_base_iova;
+	u64			msixtr_base_phy; /* Register reset value */
 
 	/* CGX */
 #define PF_CGXMAP_BASE		1 /* PF 0 is reserved for RVU PF */
@@ -313,6 +334,9 @@ struct rvu {
 
 	char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */
 
+	/* Firmware data */
+	struct rvu_fwdata	*fwdata;
+
 #ifdef CONFIG_DEBUG_FS
 	struct rvu_debugfs	rvu_dbg;
 #endif
@@ -363,6 +387,12 @@ static inline int is_afvf(u16 pcifunc)
 	return !(pcifunc & ~RVU_PFVF_FUNC_MASK);
 }
 
+static inline bool is_rvu_fwdata_valid(struct rvu *rvu)
+{
+	return (rvu->fwdata->header_magic == RVU_FWDATA_HEADER_MAGIC) &&
+		(rvu->fwdata->version == RVU_FWDATA_VERSION);
+}
+
 int rvu_alloc_bitmap(struct rsrc_bmap *rsrc);
 int rvu_alloc_rsrc(struct rsrc_bmap *rsrc);
 void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index cb1d653..83bd42e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -2666,6 +2666,7 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu,
 				      struct nix_set_mac_addr *req,
 				      struct msg_rsp *rsp)
 {
+	bool from_vf = !!(req->hdr.pcifunc & RVU_PFVF_FUNC_MASK);
 	struct rvu_hwinfo *hw = rvu->hw;
 	u16 pcifunc = req->hdr.pcifunc;
 	struct rvu_pfvf *pfvf;
@@ -2680,7 +2681,10 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu,
 	if (nixlf < 0)
 		return NIX_AF_ERR_AF_LF_INVALID;
 
-	ether_addr_copy(pfvf->mac_addr, req->mac_addr);
+	/* Skip updating mac addr if request is from vf */
+	if (!from_vf)
+		ether_addr_copy(pfvf->mac_addr, req->mac_addr);
+
 
 	rvu_npc_install_ucast_entry(rvu, pcifunc, nixlf,
 				    pfvf->rx_chan_base, req->mac_addr);
@@ -2690,6 +2694,23 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu,
 	return 0;
 }
 
+int rvu_mbox_handler_nix_get_mac_addr(struct rvu *rvu,
+				      struct msg_req *req,
+				      struct nix_get_mac_addr_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	struct rvu_pfvf *pfvf;
+
+	if (!is_nixlf_attached(rvu, pcifunc))
+		return NIX_AF_ERR_AF_LF_INVALID;
+
+	pfvf = rvu_get_pfvf(rvu, pcifunc);
+
+	ether_addr_copy(rsp->mac_addr, pfvf->mac_addr);
+
+	return 0;
+}
+
 int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req,
 				     struct msg_rsp *rsp)
 {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 03/16] octeontx2-af: Cleanup CGX config permission checks
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 01/16] octeontx2-af: Interface backpressure configuration support sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 02/16] octeontx2-af: Add support for importing firmware data sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 04/16] octeontx2-af: Ingress and egress pause frame configuration sunil.kovvuri
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Sunil Goutham

From: Sunil Goutham <sgoutham@marvell.com>

Most of the CGX register config is restricted to mapped RVU PFs,
this patch cleans up these permission checks spread across
the rvu_cgx.c file by moving the checks to a common fn().

Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c    | 55 ++++++++++------------
 1 file changed, 24 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index 0bbb2eb..e3c87c2 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -350,6 +350,18 @@ int rvu_cgx_exit(struct rvu *rvu)
 	return 0;
 }
 
+/* Most of the CGX configuration is restricted to the mapped PF only,
+ * VF's of mapped PF and other PFs are not allowed. This fn() checks
+ * whether a PFFUNC is permitted to do the config or not.
+ */
+static bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc)
+{
+	if ((pcifunc & RVU_PFVF_FUNC_MASK) ||
+	    !is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc)))
+		return false;
+	return true;
+}
+
 void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable)
 {
 	u8 cgx_id, lmac_id;
@@ -373,11 +385,8 @@ int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
 	int pf = rvu_get_pf(pcifunc);
 	u8 cgx_id, lmac_id;
 
-	/* This msg is expected only from PFs that are mapped to CGX LMACs,
-	 * if received from other PF/VF simply ACK, nothing to do.
-	 */
-	if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
-		return -ENODEV;
+	if (!is_cgx_config_permitted(rvu, pcifunc))
+		return -EPERM;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
@@ -409,8 +418,7 @@ int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req,
 	u8 cgx_idx, lmac;
 	void *cgxd;
 
-	if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
-	    !is_pf_cgxmapped(rvu, pf))
+	if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
 		return -ENODEV;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
@@ -477,12 +485,8 @@ int rvu_mbox_handler_cgx_promisc_enable(struct rvu *rvu, struct msg_req *req,
 	int pf = rvu_get_pf(pcifunc);
 	u8 cgx_id, lmac_id;
 
-	/* This msg is expected only from PFs that are mapped to CGX LMACs,
-	 * if received from other PF/VF simply ACK, nothing to do.
-	 */
-	if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
-	    !is_pf_cgxmapped(rvu, pf))
-		return -ENODEV;
+	if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+		return -EPERM;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
@@ -493,16 +497,11 @@ int rvu_mbox_handler_cgx_promisc_enable(struct rvu *rvu, struct msg_req *req,
 int rvu_mbox_handler_cgx_promisc_disable(struct rvu *rvu, struct msg_req *req,
 					 struct msg_rsp *rsp)
 {
-	u16 pcifunc = req->hdr.pcifunc;
-	int pf = rvu_get_pf(pcifunc);
+	int pf = rvu_get_pf(req->hdr.pcifunc);
 	u8 cgx_id, lmac_id;
 
-	/* This msg is expected only from PFs that are mapped to CGX LMACs,
-	 * if received from other PF/VF simply ACK, nothing to do.
-	 */
-	if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
-	    !is_pf_cgxmapped(rvu, pf))
-		return -ENODEV;
+	if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+		return -EPERM;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
@@ -515,11 +514,8 @@ static int rvu_cgx_config_linkevents(struct rvu *rvu, u16 pcifunc, bool en)
 	int pf = rvu_get_pf(pcifunc);
 	u8 cgx_id, lmac_id;
 
-	/* This msg is expected only from PFs that are mapped to CGX LMACs,
-	 * if received from other PF/VF simply ACK, nothing to do.
-	 */
-	if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
-		return -ENODEV;
+	if (!is_cgx_config_permitted(rvu, pcifunc))
+		return -EPERM;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
@@ -571,11 +567,8 @@ static int rvu_cgx_config_intlbk(struct rvu *rvu, u16 pcifunc, bool en)
 	int pf = rvu_get_pf(pcifunc);
 	u8 cgx_id, lmac_id;
 
-	/* This msg is expected only from PFs that are mapped to CGX LMACs,
-	 * if received from other PF/VF simply ACK, nothing to do.
-	 */
-	if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
-		return -ENODEV;
+	if (!is_cgx_config_permitted(rvu, pcifunc))
+		return -EPERM;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 04/16] octeontx2-af: Ingress and egress pause frame configuration
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (2 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 03/16] octeontx2-af: Cleanup CGX config permission checks sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 05/16] octeontx2-af: Set discovery ID for RVUM block sunil.kovvuri
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Geetha sowjanya, Sunil Goutham

From: Geetha sowjanya <gakula@marvell.com>

Pause frames can be generated when NIX/NPA asserts backpressure
due to insufficient resources. This patch enables generation
of pause frames by CGX. Also enabled processing of received
pause frames and asserting backpressure on NIX transmit path.

Also added mailbox config messages for PF/VF to enable/disable
flow control any time.

Signed-off-by: Geetha sowjanya <gakula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/cgx.c    | 106 +++++++++++++++++++++
 drivers/net/ethernet/marvell/octeontx2/af/cgx.h    |  14 +++
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  11 +++
 .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c    |  24 +++++
 .../net/ethernet/marvell/octeontx2/af/rvu_nix.c    |   5 +
 5 files changed, 160 insertions(+)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index aa2ce5e..6379010 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -381,6 +381,110 @@ int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable)
 }
 EXPORT_SYMBOL(cgx_lmac_tx_enable);
 
+int cgx_lmac_get_pause_frm(void *cgxd, int lmac_id,
+			   u8 *tx_pause, u8 *rx_pause)
+{
+	struct cgx *cgx = cgxd;
+	u64 cfg;
+
+	if (!cgx || lmac_id >= cgx->lmac_count)
+		return -ENODEV;
+
+	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
+	*rx_pause = !!(cfg & CGX_SMUX_RX_FRM_CTL_CTL_BCK);
+
+	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
+	*tx_pause = !!(cfg & CGX_SMUX_TX_CTL_L2P_BP_CONV);
+	return 0;
+}
+EXPORT_SYMBOL(cgx_lmac_get_pause_frm);
+
+int cgx_lmac_set_pause_frm(void *cgxd, int lmac_id,
+			   u8 tx_pause, u8 rx_pause)
+{
+	struct cgx *cgx = cgxd;
+	u64 cfg;
+
+	if (!cgx || lmac_id >= cgx->lmac_count)
+		return -ENODEV;
+
+	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
+	cfg &= ~CGX_SMUX_RX_FRM_CTL_CTL_BCK;
+	cfg |= rx_pause ? CGX_SMUX_RX_FRM_CTL_CTL_BCK : 0x0;
+	cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg);
+
+	cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
+	cfg &= ~CGX_SMUX_TX_CTL_L2P_BP_CONV;
+	cfg |= tx_pause ? CGX_SMUX_TX_CTL_L2P_BP_CONV : 0x0;
+	cgx_write(cgx, lmac_id, CGXX_SMUX_TX_CTL, cfg);
+
+	cfg = cgx_read(cgx, 0, CGXX_CMR_RX_OVR_BP);
+	if (tx_pause) {
+		cfg &= ~CGX_CMR_RX_OVR_BP_EN(lmac_id);
+	} else {
+		cfg |= CGX_CMR_RX_OVR_BP_EN(lmac_id);
+		cfg &= ~CGX_CMR_RX_OVR_BP_BP(lmac_id);
+	}
+	cgx_write(cgx, 0, CGXX_CMR_RX_OVR_BP, cfg);
+	return 0;
+}
+EXPORT_SYMBOL(cgx_lmac_set_pause_frm);
+
+static void cgx_lmac_pause_frm_config(struct cgx *cgx, int lmac_id, bool enable)
+{
+	u64 cfg;
+
+	if (!cgx || lmac_id >= cgx->lmac_count)
+		return;
+	if (enable) {
+		/* Enable receive pause frames */
+		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
+		cfg |=  CGX_SMUX_RX_FRM_CTL_CTL_BCK;
+		cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg);
+
+		cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL);
+		cfg |=  CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK;
+		cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg);
+
+		/* Enable pause frames transmission */
+		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
+		cfg |= CGX_SMUX_TX_CTL_L2P_BP_CONV;
+		cgx_write(cgx, lmac_id, CGXX_SMUX_TX_CTL, cfg);
+
+		/* Set pause time and interval */
+		cgx_write(cgx, lmac_id, CGXX_SMUX_TX_PAUSE_PKT_TIME,
+			  DEFAULT_PAUSE_TIME);
+		/* Set pause interval as the hardware default is too short */
+		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_PAUSE_PKT_INTERVAL);
+		cfg &= ~0xFFFFULL;
+		cgx_write(cgx, lmac_id, CGXX_SMUX_TX_PAUSE_PKT_INTERVAL,
+			  cfg | (DEFAULT_PAUSE_TIME - 0x1000));
+
+		cgx_write(cgx, lmac_id, CGXX_GMP_GMI_TX_PAUSE_PKT_TIME,
+			  DEFAULT_PAUSE_TIME);
+
+		cfg = cgx_read(cgx, lmac_id,
+			       CGXX_GMP_GMI_TX_PAUSE_PKT_INTERVAL);
+		cfg &= ~0xFFFFULL;
+		cgx_write(cgx, lmac_id, CGXX_GMP_GMI_TX_PAUSE_PKT_INTERVAL,
+			  cfg | (DEFAULT_PAUSE_TIME - 0x1000));
+	} else {
+		/* ALL pause frames received are completely ignored */
+		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL);
+		cfg &= ~CGX_SMUX_RX_FRM_CTL_CTL_BCK;
+		cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg);
+
+		cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL);
+		cfg &= ~CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK;
+		cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg);
+
+		/* Disable pause frames transmission */
+		cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_TX_CTL);
+		cfg &= ~CGX_SMUX_TX_CTL_L2P_BP_CONV;
+		cgx_write(cgx, lmac_id, CGXX_SMUX_TX_CTL, cfg);
+	}
+}
+
 /* CGX Firmware interface low level support */
 static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac)
 {
@@ -823,6 +927,7 @@ static int cgx_lmac_init(struct cgx *cgx)
 
 		/* Add reference */
 		cgx->lmac_idmap[i] = lmac;
+		cgx_lmac_pause_frm_config(cgx, i, true);
 	}
 
 	return cgx_lmac_verify_fwi_version(cgx);
@@ -841,6 +946,7 @@ static int cgx_lmac_exit(struct cgx *cgx)
 
 	/* Free all lmac related resources */
 	for (i = 0; i < cgx->lmac_count; i++) {
+		cgx_lmac_pause_frm_config(cgx, i, false);
 		lmac = cgx->lmac_idmap[i];
 		if (!lmac)
 			continue;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index ad47cb8..fa411d4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -60,10 +60,20 @@
 #define CGX_SMUX_RX_FRM_CTL_CTL_BCK	BIT_ULL(3)
 #define CGXX_GMP_GMI_RXX_FRM_CTL	0x38028
 #define CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK	BIT_ULL(3)
+#define CGXX_SMUX_TX_CTL		0x20178
+#define CGXX_SMUX_TX_PAUSE_PKT_TIME	0x20110
+#define CGXX_SMUX_TX_PAUSE_PKT_INTERVAL	0x20120
+#define CGXX_GMP_GMI_TX_PAUSE_PKT_TIME	0x38230
+#define CGXX_GMP_GMI_TX_PAUSE_PKT_INTERVAL	0x38248
+#define CGX_SMUX_TX_CTL_L2P_BP_CONV	BIT_ULL(7)
+#define CGXX_CMR_RX_OVR_BP		0x130
+#define CGX_CMR_RX_OVR_BP_EN(X)		BIT_ULL(((X) + 8))
+#define CGX_CMR_RX_OVR_BP_BP(X)		BIT_ULL(((X) + 4))
 
 #define CGX_COMMAND_REG			CGXX_SCRATCH1_REG
 #define CGX_EVENT_REG			CGXX_SCRATCH0_REG
 #define CGX_CMD_TIMEOUT			2200 /* msecs */
+#define DEFAULT_PAUSE_TIME		0xFFFF
 
 #define CGX_NVEC			37
 #define CGX_LMAC_FWI			0
@@ -125,5 +135,9 @@ 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_fwdata_base(u64 *base);
+int cgx_lmac_get_pause_frm(void *cgxd, int lmac_id,
+			   u8 *tx_pause, u8 *rx_pause);
+int cgx_lmac_set_pause_frm(void *cgxd, int lmac_id,
+			   u8 tx_pause, u8 rx_pause);
 int cgx_get_mkex_prfl_info(u64 *addr, u64 *size);
 #endif /* CGX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index c68266a..3dcfac5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -143,6 +143,8 @@ M(CGX_STOP_LINKEVENTS,	0x208, cgx_stop_linkevents, msg_req, msg_rsp)	\
 M(CGX_GET_LINKINFO,	0x209, cgx_get_linkinfo, msg_req, cgx_link_info_msg) \
 M(CGX_INTLBK_ENABLE,	0x20A, cgx_intlbk_enable, msg_req, msg_rsp)	\
 M(CGX_INTLBK_DISABLE,	0x20B, cgx_intlbk_disable, msg_req, msg_rsp)	\
+M(CGX_CFG_PAUSE_FRM,	0x20E, cgx_cfg_pause_frm, cgx_pause_frm_cfg,	\
+			       cgx_pause_frm_cfg)			\
 /* NPA mbox IDs (range 0x400 - 0x5FF) */				\
 M(NPA_LF_ALLOC,		0x400, npa_lf_alloc,				\
 				npa_lf_alloc_req, npa_lf_alloc_rsp)	\
@@ -346,6 +348,15 @@ struct cgx_link_info_msg {
 	struct cgx_link_user_info link_info;
 };
 
+struct cgx_pause_frm_cfg {
+	struct mbox_msghdr hdr;
+	u8 set;
+	/* set = 1 if the request is to config pause frames */
+	/* set = 0 if the request is to fetch pause frames config */
+	u8 rx_pause;
+	u8 tx_pause;
+};
+
 /* NPA mbox message formats */
 
 /* NPA mailbox error codes
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index e3c87c2..6859339 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -590,6 +590,30 @@ int rvu_mbox_handler_cgx_intlbk_disable(struct rvu *rvu, struct msg_req *req,
 	return 0;
 }
 
+int rvu_mbox_handler_cgx_cfg_pause_frm(struct rvu *rvu,
+				       struct cgx_pause_frm_cfg *req,
+				       struct cgx_pause_frm_cfg *rsp)
+{
+	int pf = rvu_get_pf(req->hdr.pcifunc);
+	u8 cgx_id, lmac_id;
+
+	/* This msg is expected only from PF/VFs that are mapped to CGX LMACs,
+	 * if received from other PF/VF simply ACK, nothing to do.
+	 */
+	if (!is_pf_cgxmapped(rvu, pf))
+		return -ENODEV;
+
+	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+	if (req->set)
+		cgx_lmac_set_pause_frm(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
+				       req->tx_pause, req->rx_pause);
+	else
+		cgx_lmac_get_pause_frm(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
+				       &rsp->tx_pause, &rsp->rx_pause);
+	return 0;
+}
+
 /* Finds cumulative status of NIX rx/tx counters from LF of a PF and those
  * from its VFs as well. ie. NIX rx/tx counters at the CGX port level
  */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 83bd42e..10b49e5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -193,6 +193,11 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf)
 		pfvf->tx_chan_cnt = 1;
 		cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
 		rvu_npc_set_pkind(rvu, pkind, pfvf);
+
+		/* By default we enable pause frames */
+		if ((pcifunc & RVU_PFVF_FUNC_MASK) == 0)
+			cgx_lmac_set_pause_frm(rvu_cgx_pdata(cgx_id, rvu),
+					       lmac_id, true, true);
 		break;
 	case NIX_INTF_TYPE_LBK:
 		vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 05/16] octeontx2-af: Set discovery ID for RVUM block
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (3 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 04/16] octeontx2-af: Ingress and egress pause frame configuration sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 06/16] octeontx2-af: add debug msgs for NPA block errors sunil.kovvuri
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Sunil Goutham, Geetha sowjanya

From: Sunil Goutham <sgoutham@marvell.com>

Currently there is no way for AF dependent drivers in
any domain to check if the AF driver is loaded. This
patch sets a ID for RVUM block which will automatically
reflects in PF/VFs discovery register which they can
check and defer their probe until AF is up.

Also fixed an issue which occurs when kernel driver is
unbinded, bus mastering gets disabled by the PCI subsystem
which results interrupts not working when driver is reloaded.
Hence enabled bus mastering  in probe(). Also cleared
transaction pending bit which gets set during driver unbind
due to clearing of bus mastering ME bit.

Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: Geetha sowjanya <gakula@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    | 23 +++++++++++++++++++++-
 .../net/ethernet/marvell/octeontx2/af/rvu_struct.h |  3 +++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index d221540..a0c7886 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -421,6 +421,19 @@ static void rvu_check_block_implemented(struct rvu *rvu)
 	}
 }
 
+static void rvu_setup_rvum_blk_revid(struct rvu *rvu)
+{
+	rvu_write64(rvu, BLKADDR_RVUM,
+		    RVU_PRIV_BLOCK_TYPEX_REV(BLKTYPE_RVUM),
+		    RVU_BLK_RVUM_REVID);
+}
+
+static void rvu_clear_rvum_blk_revid(struct rvu *rvu)
+{
+	rvu_write64(rvu, BLKADDR_RVUM,
+		    RVU_PRIV_BLOCK_TYPEX_REV(BLKTYPE_RVUM), 0x00);
+}
+
 int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf)
 {
 	int err;
@@ -2226,6 +2239,9 @@ static int rvu_register_interrupts(struct rvu *rvu)
 	}
 	rvu->irq_allocated[RVU_AF_INT_VEC_PFME] = true;
 
+	/* Clear TRPEND bit for all PF */
+	rvu_write64(rvu, BLKADDR_RVUM,
+		    RVU_AF_PFTRPEND, INTR_MASK(rvu->hw->total_pfs));
 	/* Enable ME interrupt for all PFs*/
 	rvu_write64(rvu, BLKADDR_RVUM,
 		    RVU_AF_PFME_INT, INTR_MASK(rvu->hw->total_pfs));
@@ -2549,6 +2565,8 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto err_release_regions;
 	}
 
+	pci_set_master(pdev);
+
 	/* Map Admin function CSRs */
 	rvu->afreg_base = pcim_iomap(pdev, PCI_AF_REG_BAR_NUM, 0);
 	rvu->pfreg_base = pcim_iomap(pdev, PCI_PF_REG_BAR_NUM, 0);
@@ -2587,6 +2605,8 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (err)
 		goto err_flr;
 
+	rvu_setup_rvum_blk_revid(rvu);
+
 	/* Enable AF's VFs (if any) */
 	err = rvu_enable_sriov(rvu);
 	if (err)
@@ -2607,6 +2627,7 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	rvu_fwdata_exit(rvu);
 	rvu_reset_all_blocks(rvu);
 	rvu_free_hw_resources(rvu);
+	rvu_clear_rvum_blk_revid(rvu);
 err_release_regions:
 	pci_release_regions(pdev);
 err_disable_device:
@@ -2631,7 +2652,7 @@ static void rvu_remove(struct pci_dev *pdev)
 	rvu_disable_sriov(rvu);
 	rvu_reset_all_blocks(rvu);
 	rvu_free_hw_resources(rvu);
-
+	rvu_clear_rvum_blk_revid(rvu);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index 9d8942a..a3ecb5d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -11,6 +11,9 @@
 #ifndef RVU_STRUCT_H
 #define RVU_STRUCT_H
 
+/* RVU Block revision IDs */
+#define RVU_BLK_RVUM_REVID		0x01
+
 /* RVU Block Address Enumeration */
 enum rvu_block_addr_e {
 	BLKADDR_RVUM		= 0x0ULL,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 06/16] octeontx2-af: add debug msgs for NPA block errors
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (4 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 05/16] octeontx2-af: Set discovery ID for RVUM block sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 07/16] octeontx2-af: add debug msgs for NIX " sunil.kovvuri
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Jerin Jacob, Pavan Nikhilesh, Sunil Goutham

From: Jerin Jacob <jerinj@marvell.com>

Added debug messages for NPA NPA_AF_RVU_INT, NPA_AF_GEN_INT, NPA_AF_ERR_INT
and NPA_AF_RAS error AF interrupts.

Signed-off-by: Jerin Jacob <jerinj@marvell.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |   8 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   2 +
 .../net/ethernet/marvell/octeontx2/af/rvu_npa.c    | 230 +++++++++++++++++++++
 .../net/ethernet/marvell/octeontx2/af/rvu_struct.h |  23 +++
 4 files changed, 262 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index a0c7886..68bccd6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -2126,6 +2126,8 @@ static void rvu_unregister_interrupts(struct rvu *rvu)
 {
 	int irq;
 
+	rvu_npa_unregister_interrupts(rvu);
+
 	/* Disable the Mbox interrupt */
 	rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1C,
 		    INTR_MASK(rvu->hw->total_pfs) & ~1ULL);
@@ -2333,8 +2335,12 @@ static int rvu_register_interrupts(struct rvu *rvu)
 		goto fail;
 	}
 	rvu->irq_allocated[offset] = true;
-	return 0;
 
+	ret = rvu_npa_register_interrupts(rvu);
+	if (ret)
+		goto fail;
+
+	return 0;
 fail:
 	rvu_unregister_interrupts(rvu);
 	return ret;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 3691809..c6d1bb8 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -453,6 +453,8 @@ void rvu_npa_freemem(struct rvu *rvu);
 void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf);
 int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req,
 			struct npa_aq_enq_rsp *rsp);
+int rvu_npa_register_interrupts(struct rvu *rvu);
+void rvu_npa_unregister_interrupts(struct rvu *rvu);
 
 /* NIX APIs */
 bool is_nixlf_attached(struct rvu *rvu, u16 pcifunc);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
index 67471cb..2476d20 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c
@@ -8,8 +8,10 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/stringify.h>
 
 #include "rvu_struct.h"
 #include "rvu_reg.h"
@@ -541,3 +543,231 @@ void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf)
 
 	npa_ctx_free(rvu, pfvf);
 }
+
+static irqreturn_t rvu_npa_af_rvu_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	int blkaddr;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NPA_AF_RVU_INT);
+
+	if (intr & BIT_ULL(0))
+		dev_err(rvu->dev, "NPA: Unmapped slot error\n");
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT, intr);
+	return IRQ_HANDLED;
+}
+
+static const char *rvu_npa_inpq_to_str(u16 in)
+{
+	switch (in) {
+	case 0:
+		return NULL;
+	case BIT(NPA_INPQ_NIX0_RX):
+		return __stringify(NPA_INPQ_NIX0_RX);
+	case BIT(NPA_INPQ_NIX0_TX):
+		return __stringify(NPA_INPQ_NIX0_TX);
+	case BIT(NPA_INPQ_NIX1_RX):
+		return __stringify(NPA_INPQ_NIX1_RX);
+	case BIT(NPA_INPQ_NIX1_TX):
+		return __stringify(NPA_INPQ_NIX1_TX);
+	case BIT(NPA_INPQ_SSO):
+		return __stringify(NPA_INPQ_SSO);
+	case BIT(NPA_INPQ_TIM):
+		return __stringify(NPA_INPQ_TIM);
+	case BIT(NPA_INPQ_DPI):
+		return __stringify(NPA_INPQ_DPI);
+	case BIT(NPA_INPQ_AURA_OP):
+		return __stringify(NPA_INPQ_AURA_OP);
+	case BIT(NPA_INPQ_INTERNAL_RSV):
+		return __stringify(NPA_INPQ_INTERNAL_RSV);
+	}
+
+	return "Reserved";
+}
+
+static irqreturn_t rvu_npa_af_gen_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	const char *err_msg;
+	int blkaddr, val;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NPA_AF_GEN_INT);
+
+	if (intr & BIT_ULL(32))
+		dev_err(rvu->dev, "NPA: Unmapped PF func error\n");
+
+	val = FIELD_GET(GENMASK(31, 16), intr);
+	err_msg = rvu_npa_inpq_to_str(val);
+	if (err_msg)
+		dev_err(rvu->dev, "NPA: Alloc disabled for %s\n", err_msg);
+
+	val = FIELD_GET(GENMASK(15, 0), intr);
+	err_msg = rvu_npa_inpq_to_str(val);
+	if (err_msg)
+		dev_err(rvu->dev, "NPA: Free disabled for %s\n", err_msg);
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT, intr);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_npa_af_err_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	int blkaddr;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NPA_AF_ERR_INT);
+
+	if (intr & BIT_ULL(14))
+		dev_err(rvu->dev, "NPA: Memory fault on NPA_AQ_INST_S read\n");
+
+	if (intr & BIT_ULL(13))
+		dev_err(rvu->dev, "NPA: Memory fault on NPA_AQ_RES_S write\n");
+
+	if (intr & BIT_ULL(12))
+		dev_err(rvu->dev, "NPA: AQ doorbell error\n");
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT, intr);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_npa_af_ras_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	int blkaddr;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NPA_AF_RAS);
+
+	if (intr & BIT_ULL(34))
+		dev_err(rvu->dev, "NPA: Poisoned data on NPA_AQ_INST_S read\n");
+
+	if (intr & BIT_ULL(33))
+		dev_err(rvu->dev, "NPA: Poisoned data on NPA_AQ_RES_S write\n");
+
+	if (intr & BIT_ULL(32))
+		dev_err(rvu->dev, "NPA: Poisoned data on HW context read\n");
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NPA_AF_RAS, intr);
+	return IRQ_HANDLED;
+}
+
+static bool rvu_npa_af_request_irq(struct rvu *rvu, int blkaddr, int offset,
+				   const char *name, irq_handler_t fn)
+{
+	int rc;
+
+	WARN_ON(rvu->irq_allocated[offset]);
+	rvu->irq_allocated[offset] = false;
+	sprintf(&rvu->irq_name[offset * NAME_SIZE], name);
+	rc = request_irq(pci_irq_vector(rvu->pdev, offset), fn, 0,
+			 &rvu->irq_name[offset * NAME_SIZE], rvu);
+	if (rc)
+		dev_warn(rvu->dev, "Failed to register %s irq\n", name);
+	else
+		rvu->irq_allocated[offset] = true;
+
+	return rvu->irq_allocated[offset];
+}
+
+int rvu_npa_register_interrupts(struct rvu *rvu)
+{
+	int blkaddr, base;
+	bool rc;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+	if (blkaddr < 0)
+		return blkaddr;
+
+	/* Get NPA AF MSIX vectors offset. */
+	base = rvu_read64(rvu, blkaddr, NPA_PRIV_AF_INT_CFG) & 0x3ff;
+	if (!base) {
+		dev_warn(rvu->dev,
+			 "Failed to get NPA_AF_INT vector offsets\n");
+		return 0;
+	}
+
+	/* Register and enable NPA_AF_RVU_INT interrupt */
+	rc = rvu_npa_af_request_irq(rvu, blkaddr, base +  NPA_AF_INT_VEC_RVU,
+				    "NPA_AF_RVU_INT",
+				    rvu_npa_af_rvu_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1S, ~0ULL);
+
+	/* Register and enable NPA_AF_GEN_INT interrupt */
+	rc = rvu_npa_af_request_irq(rvu, blkaddr, base + NPA_AF_INT_VEC_GEN,
+				    "NPA_AF_RVU_GEN",
+				    rvu_npa_af_gen_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1S, ~0ULL);
+
+	/* Register and enable NPA_AF_ERR_INT interrupt */
+	rc = rvu_npa_af_request_irq(rvu, blkaddr, base + NPA_AF_INT_VEC_AF_ERR,
+				    "NPA_AF_ERR_INT",
+				    rvu_npa_af_err_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1S, ~0ULL);
+
+	/* Register and enable NPA_AF_RAS interrupt */
+	rc = rvu_npa_af_request_irq(rvu, blkaddr, base + NPA_AF_INT_VEC_POISON,
+				    "NPA_AF_RAS",
+				    rvu_npa_af_ras_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1S, ~0ULL);
+
+	return 0;
+err:
+	rvu_npa_unregister_interrupts(rvu);
+	return rc;
+}
+
+void rvu_npa_unregister_interrupts(struct rvu *rvu)
+{
+	int i, offs, blkaddr;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
+	if (blkaddr < 0)
+		return;
+
+	reg = rvu_read64(rvu, blkaddr, NPA_PRIV_AF_INT_CFG);
+	offs = reg & 0x3FF;
+
+	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1C, ~0ULL);
+
+	for (i = 0; i < NPA_AF_INT_VEC_CNT; i++)
+		if (rvu->irq_allocated[offs + i]) {
+			free_irq(pci_irq_vector(rvu->pdev, offs + i), rvu);
+			rvu->irq_allocated[offs + i] = false;
+		}
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index a3ecb5d..bf5f03a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -60,6 +60,16 @@ enum rvu_af_int_vec_e {
 	RVU_AF_INT_VEC_CNT    = 0x5,
 };
 
+/* NPA Admin function Interrupt Vector Enumeration */
+enum npa_af_int_vec_e {
+	NPA_AF_INT_VEC_RVU	= 0x0,
+	NPA_AF_INT_VEC_GEN	= 0x1,
+	NPA_AF_INT_VEC_AQ_DONE	= 0x2,
+	NPA_AF_INT_VEC_AF_ERR	= 0x3,
+	NPA_AF_INT_VEC_POISON	= 0x4,
+	NPA_AF_INT_VEC_CNT	= 0x5,
+};
+
 /**
  * RVU PF Interrupt Vector Enumeration
  */
@@ -100,6 +110,19 @@ enum npa_aq_instop {
 	NPA_AQ_INSTOP_UNLOCK = 0x5,
 };
 
+/* ALLOC/FREE input queues Enumeration from coprocessors */
+enum npa_inpq {
+	NPA_INPQ_NIX0_RX       = 0x0,
+	NPA_INPQ_NIX0_TX       = 0x1,
+	NPA_INPQ_NIX1_RX       = 0x2,
+	NPA_INPQ_NIX1_TX       = 0x3,
+	NPA_INPQ_SSO           = 0x4,
+	NPA_INPQ_TIM           = 0x5,
+	NPA_INPQ_DPI           = 0x6,
+	NPA_INPQ_AURA_OP       = 0xe,
+	NPA_INPQ_INTERNAL_RSV  = 0xf,
+};
+
 /* NPA admin queue instruction structure */
 struct npa_aq_inst_s {
 #if defined(__BIG_ENDIAN_BITFIELD)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 07/16] octeontx2-af: add debug msgs for NIX block errors
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (5 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 06/16] octeontx2-af: add debug msgs for NPA block errors sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 08/16] octeontx2-af: Add SSO unit support to the AF driver sunil.kovvuri
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Jerin Jacob, Pavan Nikhilesh, Sunil Goutham

From: Jerin Jacob <jerinj@marvell.com>

Added debug messages for NIX_AF_RVU_INT, NIX_AF_ERR_INT and NIX_AF_RAS
error AF interrupts.

These will help in detecting issues wrt AQ instruction faults,
LF misconfiguration, NPC MCAM entry trying to forward pkt to PF_FUNC
with no NIXLF mapped etc.

Signed-off-by: Jerin Jacob <jerinj@marvell.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |   5 +
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   2 +
 .../net/ethernet/marvell/octeontx2/af/rvu_nix.c    | 202 +++++++++++++++++++++
 .../net/ethernet/marvell/octeontx2/af/rvu_struct.h |  10 +
 4 files changed, 219 insertions(+)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index 68bccd6..e39aa02 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -2127,6 +2127,7 @@ static void rvu_unregister_interrupts(struct rvu *rvu)
 	int irq;
 
 	rvu_npa_unregister_interrupts(rvu);
+	rvu_nix_unregister_interrupts(rvu);
 
 	/* Disable the Mbox interrupt */
 	rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1C,
@@ -2340,6 +2341,10 @@ static int rvu_register_interrupts(struct rvu *rvu)
 	if (ret)
 		goto fail;
 
+	ret = rvu_nix_register_interrupts(rvu);
+	if (ret)
+		goto fail;
+
 	return 0;
 fail:
 	rvu_unregister_interrupts(rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index c6d1bb8..5936d8e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -465,6 +465,8 @@ void rvu_nix_freemem(struct rvu *rvu);
 int rvu_get_nixlf_count(struct rvu *rvu);
 void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf);
 int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf);
+int rvu_nix_register_interrupts(struct rvu *rvu);
+void rvu_nix_unregister_interrupts(struct rvu *rvu);
 
 /* NPC APIs */
 int rvu_npc_init(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 10b49e5..f1201e0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -3407,3 +3407,205 @@ int rvu_mbox_handler_nix_lso_format_cfg(struct rvu *rvu,
 
 	return 0;
 }
+
+static irqreturn_t rvu_nix_af_rvu_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	int blkaddr;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NIX_AF_RVU_INT);
+
+	if (intr & BIT_ULL(0))
+		dev_err(rvu->dev, "NIX: Unmapped slot error\n");
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NIX_AF_RVU_INT, intr);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_nix_af_err_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	int blkaddr;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NIX_AF_ERR_INT);
+
+	if (intr & BIT_ULL(14))
+		dev_err(rvu->dev, "NIX: Memory fault on NIX_AQ_INST_S read\n");
+
+	if (intr & BIT_ULL(13))
+		dev_err(rvu->dev, "NIX: Memory fault on NIX_AQ_RES_S write\n");
+
+	if (intr & BIT_ULL(12))
+		dev_err(rvu->dev, "NIX: AQ doorbell error\n");
+
+	if (intr & BIT_ULL(6))
+		dev_err(rvu->dev, "NIX: Rx on unmapped PF_FUNC\n");
+
+	if (intr & BIT_ULL(5))
+		dev_err(rvu->dev, "NIX: Rx multicast replication error\n");
+
+	if (intr & BIT_ULL(4))
+		dev_err(rvu->dev, "NIX: Memory fault on NIX_RX_MCE_S read\n");
+
+	if (intr & BIT_ULL(3))
+		dev_err(rvu->dev, "NIX: Memory fault on multicast WQE read\n");
+
+	if (intr & BIT_ULL(2))
+		dev_err(rvu->dev, "NIX: Memory fault on mirror WQE read\n");
+
+	if (intr & BIT_ULL(1))
+		dev_err(rvu->dev, "NIX: Memory fault on mirror pkt write\n");
+
+	if (intr & BIT_ULL(0))
+		dev_err(rvu->dev, "NIX: Memory fault on multicast pkt write\n");
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NIX_AF_ERR_INT, intr);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_nix_af_ras_intr_handler(int irq, void *rvu_irq)
+{
+	struct rvu *rvu = (struct rvu *)rvu_irq;
+	int blkaddr;
+	u64 intr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	intr = rvu_read64(rvu, blkaddr, NIX_AF_RAS);
+
+	if (intr & BIT_ULL(34))
+		dev_err(rvu->dev, "NIX: Poisoned data on NIX_AQ_INST_S read\n");
+
+	if (intr & BIT_ULL(33))
+		dev_err(rvu->dev, "NIX: Poisoned data on NIX_AQ_RES_S write\n");
+
+	if (intr & BIT_ULL(32))
+		dev_err(rvu->dev, "NIX: Poisoned data on HW context read\n");
+
+	if (intr & BIT_ULL(4))
+		dev_err(rvu->dev, "NIX: Poisoned data on packet read from mirror buffer\n");
+
+	if (intr & BIT_ULL(3))
+		dev_err(rvu->dev, "NIX: Poisoned data on packet read from multicast buffer\n");
+
+	if (intr & BIT_ULL(2))
+		dev_err(rvu->dev, "NIX: Poisoned data on WQE read from mirror buffer\n");
+
+	if (intr & BIT_ULL(1))
+		dev_err(rvu->dev, "NIX: Poisoned data on WQE read from multicast buffer\n");
+
+	if (intr & BIT_ULL(0))
+		dev_err(rvu->dev, "NIX: Poisoned data on NIX_RX_MCE_S read\n");
+
+	/* Clear interrupts */
+	rvu_write64(rvu, blkaddr, NIX_AF_RAS, intr);
+	return IRQ_HANDLED;
+}
+
+static bool rvu_nix_af_request_irq(struct rvu *rvu, int blkaddr, int offset,
+				   const char *name, irq_handler_t fn)
+{
+	int rc;
+
+	WARN_ON(rvu->irq_allocated[offset]);
+	rvu->irq_allocated[offset] = false;
+	sprintf(&rvu->irq_name[offset * NAME_SIZE], name);
+	rc = request_irq(pci_irq_vector(rvu->pdev, offset), fn, 0,
+			 &rvu->irq_name[offset * NAME_SIZE], rvu);
+	if (rc)
+		dev_warn(rvu->dev, "Failed to register %s irq\n", name);
+	else
+		rvu->irq_allocated[offset] = true;
+
+	return rvu->irq_allocated[offset];
+}
+
+int rvu_nix_register_interrupts(struct rvu *rvu)
+{
+	int blkaddr, base;
+	bool rc;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+	if (blkaddr < 0)
+		return blkaddr;
+
+	/* Get NIX AF MSIX vectors offset. */
+	base = rvu_read64(rvu, blkaddr, NIX_PRIV_AF_INT_CFG) & 0x3ff;
+	if (!base) {
+		dev_warn(rvu->dev,
+			 "Failed to get NIX_AF_INT vector offsets\n");
+		return 0;
+	}
+
+	/* Register and enable NIX_AF_RVU_INT interrupt */
+	rc = rvu_nix_af_request_irq(rvu, blkaddr, base +  NIX_AF_INT_VEC_RVU,
+				    "NIX_AF_RVU_INT",
+				    rvu_nix_af_rvu_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NIX_AF_RVU_INT_ENA_W1S, ~0ULL);
+
+	/* Register and enable NIX_AF_ERR_INT interrupt */
+	rc = rvu_nix_af_request_irq(rvu, blkaddr, base + NIX_AF_INT_VEC_AF_ERR,
+				    "NIX_AF_ERR_INT",
+				    rvu_nix_af_err_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NIX_AF_ERR_INT_ENA_W1S, ~0ULL);
+
+	/* Register and enable NIX_AF_RAS interrupt */
+	rc = rvu_nix_af_request_irq(rvu, blkaddr, base + NIX_AF_INT_VEC_POISON,
+				    "NIX_AF_RAS",
+				    rvu_nix_af_ras_intr_handler);
+	if (!rc)
+		goto err;
+	rvu_write64(rvu, blkaddr, NIX_AF_RAS_ENA_W1S, ~0ULL);
+
+	return 0;
+err:
+	rvu_nix_unregister_interrupts(rvu);
+	return rc;
+}
+
+void rvu_nix_unregister_interrupts(struct rvu *rvu)
+{
+	int blkaddr, offs, i;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, 0);
+	if (blkaddr < 0)
+		return;
+
+	offs = rvu_read64(rvu, blkaddr, NIX_PRIV_AF_INT_CFG) & 0x3ff;
+	if (!offs)
+		return;
+
+	rvu_write64(rvu, blkaddr, NIX_AF_RVU_INT_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, NIX_AF_ERR_INT_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, NIX_AF_RAS_ENA_W1C, ~0ULL);
+
+	if (rvu->irq_allocated[offs + NIX_AF_INT_VEC_RVU]) {
+		free_irq(pci_irq_vector(rvu->pdev, offs + NIX_AF_INT_VEC_RVU),
+			 rvu);
+		rvu->irq_allocated[offs + NIX_AF_INT_VEC_RVU] = false;
+	}
+
+	for (i = NIX_AF_INT_VEC_AF_ERR; i < NIX_AF_INT_VEC_CNT; i++)
+		if (rvu->irq_allocated[offs + i]) {
+			free_irq(pci_irq_vector(rvu->pdev, offs + i), rvu);
+			rvu->irq_allocated[offs + i] = false;
+		}
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index bf5f03a..a665fa2 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -70,6 +70,16 @@ enum npa_af_int_vec_e {
 	NPA_AF_INT_VEC_CNT	= 0x5,
 };
 
+/* NIX Admin function Interrupt Vector Enumeration */
+enum nix_af_int_vec_e {
+	NIX_AF_INT_VEC_RVU	= 0x0,
+	NIX_AF_INT_VEC_GEN	= 0x1,
+	NIX_AF_INT_VEC_AQ_DONE	= 0x2,
+	NIX_AF_INT_VEC_AF_ERR	= 0x3,
+	NIX_AF_INT_VEC_POISON	= 0x4,
+	NIX_AF_INT_VEC_CNT	= 0x5,
+};
+
 /**
  * RVU PF Interrupt Vector Enumeration
  */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 08/16] octeontx2-af: Add SSO unit support to the AF driver
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (6 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 07/16] octeontx2-af: add debug msgs for NIX " sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:47 ` [PATCH v3 09/16] octeontx2-af: Config support for per HWGRP thresholds sunil.kovvuri
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev
  Cc: davem, jakub.kicinski, Radha Mohan Chintakuntla, Pavan Nikhilesh,
	Stanislaw Kardach, Sunil Goutham

From: Radha Mohan Chintakuntla <radhac@marvell.com>

This patch adds the SSO (Schedule/Synchronize/Order) unit support to the
Adming Function (AF) driver including initial mailboxes, initialization
of SSO hardware groups and workslots and their teardown sequence.

Signed-off-by: Radha Mohan Chintakuntla <radhac@marvell.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Stanislaw Kardach <skardach@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/Makefile |   2 +-
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  90 +++
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |  28 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |  24 +
 .../net/ethernet/marvell/octeontx2/af/rvu_reg.h    | 180 ++++-
 .../net/ethernet/marvell/octeontx2/af/rvu_sso.c    | 837 +++++++++++++++++++++
 6 files changed, 1157 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
index 1b25948..5988d58 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile
+++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
@@ -8,4 +8,4 @@ obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o
 
 octeontx2_mbox-y := mbox.o
 octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
-		  rvu_reg.o rvu_npc.o rvu_debugfs.o
+		  rvu_reg.o rvu_npc.o rvu_debugfs.o rvu_sso.o
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 3dcfac5..ab03769 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -152,6 +152,21 @@ M(NPA_LF_FREE,		0x401, npa_lf_free, msg_req, msg_rsp)		\
 M(NPA_AQ_ENQ,		0x402, npa_aq_enq, npa_aq_enq_req, npa_aq_enq_rsp)   \
 M(NPA_HWCTX_DISABLE,	0x403, npa_hwctx_disable, hwctx_disable_req, msg_rsp)\
 /* SSO/SSOW mbox IDs (range 0x600 - 0x7FF) */				\
+M(SSO_LF_ALLOC,		0x600, sso_lf_alloc,				\
+				sso_lf_alloc_req, sso_lf_alloc_rsp)	\
+M(SSO_LF_FREE,		0x601, sso_lf_free,				\
+				sso_lf_free_req, msg_rsp)		\
+M(SSOW_LF_ALLOC,	0x602, ssow_lf_alloc,				\
+				ssow_lf_alloc_req, msg_rsp)		\
+M(SSOW_LF_FREE,		0x603, ssow_lf_free,				\
+				ssow_lf_free_req, msg_rsp)		\
+M(SSO_HW_SETCONFIG,	0x604, sso_hw_setconfig,			\
+				sso_hw_setconfig, msg_rsp)		\
+M(SSO_GRP_SET_PRIORITY,	0x605, sso_grp_set_priority,			\
+				sso_grp_priority, msg_rsp)		\
+M(SSO_GRP_GET_PRIORITY,	0x606, sso_grp_get_priority,			\
+				sso_info_req, sso_grp_priority)	\
+M(SSO_WS_CACHE_INV,	0x607, sso_ws_cache_inv, msg_req, msg_rsp)	\
 /* TIM mbox IDs (range 0x800 - 0x9FF) */				\
 /* CPT mbox IDs (range 0xA00 - 0xBFF) */				\
 /* NPC mbox IDs (range 0x6000 - 0x7FFF) */				\
@@ -710,6 +725,81 @@ struct nix_bp_cfg_rsp {
 	u8	chan_cnt; /* Number of channel for which bpids are assigned */
 };
 
+/* SSO mailbox error codes
+ * Range 501 - 600.
+ */
+enum sso_af_status {
+	SSO_AF_ERR_PARAM	= -501,
+	SSO_AF_ERR_LF_INVALID	= -502,
+	SSO_AF_ERR_AF_LF_ALLOC	= -503,
+	SSO_AF_ERR_GRP_EBUSY	= -504,
+	SSO_AF_INVAL_NPA_PF_FUNC = -505,
+};
+
+struct sso_lf_alloc_req {
+	struct mbox_msghdr hdr;
+	int node;
+	u16 hwgrps;
+};
+
+struct sso_lf_alloc_rsp {
+	struct mbox_msghdr hdr;
+	u32	xaq_buf_size;
+	u32	xaq_wq_entries;
+	u32	in_unit_entries;
+	u16	hwgrps;
+};
+
+struct sso_lf_free_req {
+	struct mbox_msghdr hdr;
+	int node;
+	u16 hwgrps;
+};
+
+struct sso_hw_setconfig {
+	struct mbox_msghdr hdr;
+	u32	npa_aura_id;
+	u16	npa_pf_func;
+	u16	hwgrps;
+};
+
+struct sso_info_req {
+	struct mbox_msghdr hdr;
+	union {
+		u16 grp;
+		u16 hws;
+	};
+};
+
+struct sso_grp_priority {
+	struct mbox_msghdr hdr;
+	u16 grp;
+	u8 priority;
+	u8 affinity;
+	u8 weight;
+};
+
+/* SSOW mailbox error codes
+ * Range 601 - 700.
+ */
+enum ssow_af_status {
+	SSOW_AF_ERR_PARAM	= -601,
+	SSOW_AF_ERR_LF_INVALID	= -602,
+	SSOW_AF_ERR_AF_LF_ALLOC	= -603,
+};
+
+struct ssow_lf_alloc_req {
+	struct mbox_msghdr hdr;
+	int node;
+	u16 hws;
+};
+
+struct ssow_lf_free_req {
+	struct mbox_msghdr hdr;
+	int node;
+	u16 hws;
+};
+
 /* NPC mbox message structs */
 
 #define NPC_MCAM_ENTRY_INVALID	0xFFFF
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index e39aa02..c1229e5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -653,6 +653,7 @@ static void rvu_free_hw_resources(struct rvu *rvu)
 	rvu_npa_freemem(rvu);
 	rvu_npc_freemem(rvu);
 	rvu_nix_freemem(rvu);
+	rvu_sso_freemem(rvu);
 
 	/* Free block LF bitmaps */
 	for (id = 0; id < BLK_COUNT; id++) {
@@ -954,6 +955,10 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
 	if (err)
 		goto cgx_err;
 
+	err = rvu_sso_init(rvu);
+	if (err)
+		goto cgx_err;
+
 	return 0;
 
 cgx_err:
@@ -1018,7 +1023,7 @@ int rvu_mbox_handler_ready(struct rvu *rvu, struct msg_req *req,
 /* Get current count of a RVU block's LF/slots
  * provisioned to a given RVU func.
  */
-static u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blktype)
+u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blktype)
 {
 	switch (blktype) {
 	case BLKTYPE_NPA:
@@ -1047,7 +1052,7 @@ bool is_pffunc_map_valid(struct rvu *rvu, u16 pcifunc, int blktype)
 	pfvf = rvu_get_pfvf(rvu, pcifunc);
 
 	/* Check if this PFFUNC has a LF of type blktype attached */
-	if (!rvu_get_rsrc_mapcount(pfvf, blktype))
+	if (blktype != BLKTYPE_SSO && !rvu_get_rsrc_mapcount(pfvf, blktype))
 		return false;
 
 	return true;
@@ -1933,12 +1938,30 @@ static void rvu_blklf_teardown(struct rvu *rvu, u16 pcifunc, u8 blkaddr)
 			rvu_nix_lf_teardown(rvu, pcifunc, block->addr, lf);
 		else if (block->addr == BLKADDR_NPA)
 			rvu_npa_lf_teardown(rvu, pcifunc, lf);
+		else if (block->addr == BLKADDR_SSO)
+			rvu_sso_lf_teardown(rvu, pcifunc, lf, slot);
+		else if (block->addr == BLKADDR_SSOW)
+			rvu_ssow_lf_teardown(rvu, pcifunc, lf, slot);
 
 		err = rvu_lf_reset(rvu, block, lf);
 		if (err) {
 			dev_err(rvu->dev, "Failed to reset blkaddr %d LF%d\n",
 				block->addr, lf);
 		}
+
+		if (block->addr == BLKADDR_SSO)
+			rvu_sso_hwgrp_config_thresh(rvu, block->addr, lf);
+	}
+}
+
+static void rvu_sso_pfvf_rst(struct rvu *rvu, u16 pcifunc)
+{
+	struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
+	struct rvu_hwinfo *hw = rvu->hw;
+
+	if (pfvf->sso_uniq_ident) {
+		rvu_free_rsrc(&hw->sso.pfvf_ident, pfvf->sso_uniq_ident);
+		pfvf->sso_uniq_ident = 0;
 	}
 }
 
@@ -1957,6 +1980,7 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc)
 	rvu_blklf_teardown(rvu, pcifunc, BLKADDR_SSO);
 	rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NPA);
 	rvu_detach_rsrcs(rvu, NULL, pcifunc);
+	rvu_sso_pfvf_rst(rvu, pcifunc);
 	mutex_unlock(&rvu->flr_lock);
 }
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 5936d8e..df3cd2b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -129,6 +129,19 @@ struct npc_mcam {
 	u16     rx_miss_act_cntr; /* Counter for RX MISS action */
 };
 
+struct sso_rsrc {
+	u8      sso_hws;
+	u16     sso_hwgrps;
+	u16     sso_xaq_num_works;
+	u16     sso_xaq_buf_size;
+	u16     sso_iue;
+	u64	iaq_rsvd;
+	u64	iaq_max;
+	u64	taq_rsvd;
+	u64	taq_max;
+	struct rsrc_bmap pfvf_ident;
+};
+
 /* Structure for per RVU func info ie PF/VF */
 struct rvu_pfvf {
 	bool		npalf; /* Only one NPALF per RVU_FUNC */
@@ -138,6 +151,7 @@ struct rvu_pfvf {
 	u16		cptlfs;
 	u16		timlfs;
 	u8		cgx_lmac;
+	u8		sso_uniq_ident;
 
 	/* Block LF's MSIX vector info */
 	struct rsrc_bmap msix;      /* Bitmap for MSIX vector alloc */
@@ -257,6 +271,7 @@ struct rvu_hwinfo {
 	struct nix_hw    *nix0;
 	struct npc_pkind pkind;
 	struct npc_mcam  mcam;
+	struct sso_rsrc  sso;
 };
 
 struct mbox_wq_info {
@@ -399,6 +414,7 @@ void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id);
 int rvu_rsrc_free_count(struct rsrc_bmap *rsrc);
 int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc);
 bool rvu_rsrc_check_contig(struct rsrc_bmap *rsrc, int nrsrc);
+u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blktype);
 int rvu_get_pf(u16 pcifunc);
 struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc);
 void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf);
@@ -447,6 +463,14 @@ void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable);
 int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start);
 int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index,
 			   int rxtxflag, u64 *stat);
+
+/* SSO APIs */
+int rvu_sso_init(struct rvu *rvu);
+void rvu_sso_freemem(struct rvu *rvu);
+int rvu_sso_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot_id);
+int rvu_ssow_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot_id);
+void rvu_sso_hwgrp_config_thresh(struct rvu *rvu, int blkaddr, int lf);
+
 /* NPA APIs */
 int rvu_npa_init(struct rvu *rvu);
 void rvu_npa_freemem(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
index 7ca599b..8d319b6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -405,14 +405,167 @@
 #define NIX_PRIV_LFX_INT_CFG		(0x8000020)
 #define NIX_AF_RVU_LF_CFG_DEBUG		(0x8000030)
 
+#define NIX_AF_LF_CFG_SHIFT		17
+#define NIX_AF_LF_SSO_PF_FUNC_SHIFT	16
+
 /* SSO */
 #define SSO_AF_CONST			(0x1000)
 #define SSO_AF_CONST1			(0x1008)
-#define SSO_AF_BLK_RST			(0x10f8)
+#define SSO_AF_NOS_CNT			(0x1050)
+#define SSO_AF_AW_WE			(0x1080)
 #define SSO_AF_LF_HWGRP_RST		(0x10e0)
+#define SSO_AF_AW_CFG			(0x10f0)
+#define SSO_AF_BLK_RST			(0x10f8)
+#define SSO_AF_ACTIVE_CYCLES0		(0x1100)
+#define SSO_AF_ACTIVE_CYCLES1		(0x1108)
+#define SSO_AF_ACTIVE_CYCLES2		(0x1110)
+#define SSO_AF_ERR0			(0x1220)
+#define SSO_AF_ERR0_W1S			(0x1228)
+#define SSO_AF_ERR0_ENA_W1C		(0x1230)
+#define SSO_AF_ERR0_ENA_W1S		(0x1238)
+#define SSO_AF_ERR2			(0x1260)
+#define SSO_AF_ERR2_W1S			(0x1268)
+#define SSO_AF_ERR2_ENA_W1C		(0x1270)
+#define SSO_AF_ERR2_ENA_W1S		(0x1278)
+#define SSO_AF_UNMAP_INFO		(0x12f0)
+#define SSO_AF_UNMAP_INFO2		(0x1300)
+#define SSO_AF_UNMAP_INFO3		(0x1310)
+#define SSO_AF_RAS			(0x1420)
+#define SSO_AF_RAS_W1S			(0x1430)
+#define SSO_AF_RAS_ENA_W1C		(0x1460)
+#define SSO_AF_RAS_ENA_W1S		(0x1470)
+#define SSO_PRIV_AF_INT_CFG		(0x3000)
+#define SSO_AF_AW_ADD			(0x2080)
+#define SSO_AF_AW_READ_ARB		(0x2090)
+#define SSO_AF_XAQ_REQ_PC		(0x20B0)
+#define SSO_AF_XAQ_LATENCY_PC		(0x20B8)
+#define SSO_AF_TAQ_CNT			(0x20c0)
+#define SSO_AF_TAQ_ADD			(0x20e0)
+#define SSO_AF_POISONX(a)		(0x2100 | (a) << 3)
+#define SSO_AF_POISONX_W1S(a)		(0x2200 | (a) << 3)
 #define SSO_AF_RVU_LF_CFG_DEBUG		(0x3800)
 #define SSO_PRIV_LFX_HWGRP_CFG		(0x10000)
 #define SSO_PRIV_LFX_HWGRP_INT_CFG	(0x20000)
+#define SSO_AF_XAQX_GMCTL(a)		(0xe0000 | (a) << 3)
+#define SSO_AF_XAQX_HEAD_PTR(a)		(0x80000 | (a) << 3)
+#define SSO_AF_XAQX_TAIL_PTR(a)		(0x90000 | (a) << 3)
+#define SSO_AF_XAQX_HEAD_NEXT(a)	(0xa0000 | (a) << 3)
+#define SSO_AF_XAQX_TAIL_NEXT(a)	(0xb0000 | (a) << 3)
+#define SSO_AF_TOAQX_STATUS(a)		(0xd0000 | (a) << 3)
+#define SSO_AF_TIAQX_STATUS(a)		(0xc0000 | (a) << 3)
+#define SSO_AF_HWGRPX_IAQ_THR(a)	(0x200000 | (a) << 12)
+#define SSO_AF_HWGRPX_TAQ_THR(a)	(0x200010 | (a) << 12)
+#define SSO_AF_HWGRPX_PRI(a)		(0x200020 | (a) << 12)
+#define SSO_AF_HWGRPX_WS_PC(a)		(0x200050 | (a) << 12)
+#define SSO_AF_HWGRPX_EXT_PC(a)		(0x200060 | (a) << 12)
+#define SSO_AF_HWGRPX_WA_PC(a)		(0x200070 | (a) << 12)
+#define SSO_AF_HWGRPX_TS_PC(a)		(0x200080 | (a) << 12)
+#define SSO_AF_HWGRPX_DS_PC(a)		(0x200090 | (a) << 12)
+#define SSO_AF_HWGRPX_DQ_PC(a)		(0x2000A0 | (a) << 12)
+#define SSO_AF_HWGRPX_PAGE_CNT(a)	(0x200100 | (a) << 12)
+#define SSO_AF_IU_ACCNTX_CFG(a)		(0x50000 | (a) << 3)
+#define SSO_AF_IU_ACCNTX_RST(a)		(0x60000 | (a) << 3)
+#define SSO_AF_HWGRPX_AW_STATUS(a)	(0x200110 | (a) << 12)
+#define SSO_AF_HWGRPX_AW_CFG(a)		(0x200120 | (a) << 12)
+#define SSO_AF_HWGRPX_AW_TAGSPACE(a)	(0x200130 | (a) << 12)
+#define SSO_AF_HWGRPX_XAQ_AURA(a)	(0x200140 | (a) << 12)
+#define SSO_AF_HWGRPX_XAQ_LIMIT(a)	(0x200220 | (a) << 12)
+#define SSO_AF_HWGRPX_IU_ACCNT(a)	(0x200230 | (a) << 12)
+#define SSO_AF_HWSX_ARB(a)		(0x400100 | (a) << 12)
+#define SSO_AF_HWSX_INV(a)		(0x400180 | (a) << 12)
+#define SSO_AF_HWSX_GMCTL(a)		(0x400200 | (a) << 12)
+#define SSO_AF_HWSX_SX_GRPMSKX(a, b, c) \
+				(0x400400 | (a) << 12 | (b) << 5 | (c) << 3)
+#define SSO_AF_TAQX_LINK(a)		(0xc00000 | (a) << 3)
+#define SSO_AF_TAQX_WAEY_TAG(a, b)	(0xe00000 | (a) << 8 | (b) << 4)
+#define SSO_AF_TAQX_WAEY_WQP(a, b)	(0xe00008 | (a) << 8 | (b) << 4)
+#define SSO_AF_IPL_FREEX(a)		(0x800000 | (a) << 3)
+#define SSO_AF_IPL_IAQX(a)		(0x840000 | (a) << 3)
+#define SSO_AF_IPL_DESCHEDX(a)		(0x860000 | (a) << 3)
+#define SSO_AF_IPL_CONFX(a)		(0x880000 | (a) << 3)
+#define SSO_AF_IENTX_TAG(a)		(0Xa00000 | (a) << 3)
+#define SSO_AF_IENTX_GRP(a)		(0xa20000 | (a) << 3)
+#define SSO_AF_IENTX_PENDTAG(a)		(0xa40000 | (a) << 3)
+#define SSO_AF_IENTX_LINKS(a)		(0xa60000 | (a) << 3)
+#define SSO_AF_IENTX_QLINKS(a)		(0xa80000 | (a) << 3)
+#define SSO_AF_IENTX_WQP(a)		(0xaa0000 | (a) << 3)
+#define SSO_AF_XAQDIS_DIGESTX(a)	(0x901000 | (a) << 3)
+#define SSO_AF_FLR_AQ_DIGESTX(a)	(0x901200 | (a) << 3)
+#define SSO_AF_QCTLDIS_DIGESTX(a)	(0x900E00 | (a) << 3)
+#define SSO_AF_WQP0_DIGESTX(a)		(0x900A00 | (a) << 3)
+#define SSO_AF_NPA_DIGESTX(a)		(0x900000 | (a) << 3)
+#define SSO_AF_BFP_DIGESTX(a)		(0x900200 | (a) << 3)
+#define SSO_AF_BFPN_DIGESTX(a)		(0x900400 | (a) << 3)
+#define SSO_AF_GRPDIS_DIGESTX(a)	(0x900600 | (a) << 3)
+
+#define SSO_AF_IAQ_FREE_CNT_MASK	0x3FFFull
+#define SSO_AF_IAQ_RSVD_FREE_MASK	0x3FFFull
+#define SSO_AF_IAQ_RSVD_FREE_SHIFT	16
+#define SSO_AF_IAQ_FREE_CNT_MAX		SSO_AF_IAQ_FREE_CNT_MASK
+#define SSO_AF_AW_ADD_RSVD_FREE_MASK	0x3FFFull
+#define SSO_AF_AW_ADD_RSVD_FREE_SHIFT	16
+#define SSO_HWGRP_IAQ_MAX_THR_MASK	0x3FFFull
+#define SSO_HWGRP_IAQ_RSVD_THR_MASK	0x3FFFull
+#define SSO_HWGRP_IAQ_MAX_THR_SHIFT	32
+#define SSO_HWGRP_IAQ_RSVD_THR		0x2
+#define SSO_HWGRP_IAQ_GRP_CNT_SHIFT	48
+#define SSO_HWGRP_IAQ_GRP_CNT_MASK	0x3FFFull
+#define SSO_AF_HWGRPX_IUEX_NOSCHED(a, b)\
+		(((((b) >> 48) & 0x3FF) == (a)) && ((b) & BIT_ULL(60)))
+#define SSO_AF_HWGRP_PAGE_CNT_MASK	(BIT_ULL(32) - 1)
+#define SSO_AF_HWGRP_PAGE_CNT_MASK	(BIT_ULL(32) - 1)
+#define SSO_HWGRP_IAQ_MAX_THR_STRM_PERF	0xD0
+#define SSO_AF_HWGRP_IU_ACCNT_MAX_THR	0x7FFFull
+
+#define SSO_AF_TAQ_FREE_CNT_MASK	0x7FFull
+#define SSO_AF_TAQ_RSVD_FREE_MASK	0x7FFull
+#define SSO_AF_TAQ_RSVD_FREE_SHIFT	16
+#define SSO_AF_TAQ_FREE_CNT_MAX		SSO_AF_TAQ_FREE_CNT_MASK
+#define SSO_AF_TAQ_ADD_RSVD_FREE_MASK	0x1FFFull
+#define SSO_AF_TAQ_ADD_RSVD_FREE_SHIFT	16
+#define SSO_HWGRP_TAQ_MAX_THR_MASK	0x7FFull
+#define SSO_HWGRP_TAQ_RSVD_THR_MASK	0x7FFull
+#define SSO_HWGRP_TAQ_MAX_THR_SHIFT	32
+#define SSO_HWGRP_TAQ_RSVD_THR		0x3
+#define SSO_AF_ERR0_MASK		0xFFEull
+#define SSO_AF_ERR2_MASK		0xF001F000ull
+#define SSO_HWGRP_TAQ_MAX_THR_STRM_PERF	0x10
+
+#define SSO_HWGRP_PRI_MASK		0x7ull
+#define SSO_HWGRP_PRI_AFF_MASK		0xFull
+#define SSO_HWGRP_PRI_AFF_SHIFT		8
+#define SSO_HWGRP_PRI_WGT_MASK		0x3Full
+#define SSO_HWGRP_PRI_WGT_SHIFT		16
+#define SSO_HWGRP_PRI_WGT_LEFT_MASK	0x3Full
+#define SSO_HWGRP_PRI_WGT_LEFT_SHIFT	24
+
+#define SSO_HWGRP_AW_CFG_RWEN		BIT_ULL(0)
+#define SSO_HWGRP_AW_CFG_LDWB		BIT_ULL(1)
+#define SSO_HWGRP_AW_CFG_LDT		BIT_ULL(2)
+#define SSO_HWGRP_AW_CFG_STT		BIT_ULL(3)
+#define SSO_HWGRP_AW_CFG_XAQ_BYP_DIS	BIT_ULL(4)
+
+#define SSO_HWGRP_AW_STS_TPTR_VLD	BIT_ULL(8)
+#define SSO_HWGRP_AW_STS_NPA_FETCH	BIT_ULL(9)
+#define SSO_HWGRP_AW_STS_XAQ_BUFSC_MASK	0x7ull
+#define SSO_HWGRP_AW_STS_INIT_STS	0x18ull
+
+#define SSO_LF_GGRP_OP_ADD_WORK1	(0x8ull)
+#define SSO_LF_GGRP_QCTL		(0x20ull)
+#define SSO_LF_GGRP_INT			(0x100ull)
+#define SSO_LF_GGRP_INT_ENA_W1S		(0x110ull)
+#define SSO_LF_GGRP_INT_ENA_W1C		(0x118ull)
+#define SSO_LF_GGRP_INT_THR		(0x140ull)
+#define SSO_LF_GGRP_INT_CNT		(0x180ull)
+#define SSO_LF_GGRP_XAQ_CNT		(0x1b0ull)
+#define SSO_LF_GGRP_AQ_CNT		(0x1c0ull)
+#define SSO_LF_GGRP_AQ_THR		(0x1e0ull)
+#define SSO_LF_GGRP_MISC_CNT		(0x200ull)
+
+#define SSO_LF_GGRP_INT_MASK		(0X7)
+#define SSO_LF_GGRP_AQ_THR_MASK		(BIT_ULL(33) - 1)
+#define SSO_LF_GGRP_XAQ_CNT_MASK	(BIT_ULL(33) - 1)
+#define SSO_LF_GGRP_INT_CNT_MASK	(0x3FFF3FFF0000ull)
 
 /* SSOW */
 #define SSOW_AF_RVU_LF_HWS_CFG_DEBUG	(0x0010)
@@ -420,6 +573,22 @@
 #define SSOW_PRIV_LFX_HWS_CFG		(0x1000)
 #define SSOW_PRIV_LFX_HWS_INT_CFG	(0x2000)
 
+#define SSOW_LF_GWS_PENDSTATE		(0x50ull)
+#define SSOW_LF_GWS_NW_TIM		(0x70ull)
+#define SSOW_LF_GWS_INT			(0x100ull)
+#define SSOW_LF_GWS_INT_ENA_W1C		(0x118ull)
+#define SSOW_LF_GWS_TAG			(0x200ull)
+#define SSOW_LF_GWS_WQP			(0x210ull)
+#define SSOW_LF_GWS_OP_GET_WORK		(0x600ull)
+#define SSOW_LF_GWS_OP_SWTAG_FLUSH	(0x800ull)
+#define SSOW_LF_GWS_OP_DESCHED		(0x880ull)
+#define SSOW_LF_GWS_OP_CLR_NSCHED0	(0xA00ull)
+#define SSOW_LF_GWS_OP_GWC_INVAL	(0xe00ull)
+
+#define SSO_TT_EMPTY			(0x3)
+#define SSOW_LF_GWS_INT_MASK		(0x7FF)
+#define SSOW_LF_GWS_MAX_NW_TIM		(BIT_ULL(10) - 1)
+
 /* TIM */
 #define TIM_AF_CONST			(0x90)
 #define TIM_PRIV_LFX_CFG		(0x20000)
@@ -525,4 +694,13 @@
 		(0x00F00 | (a) << 5 | (b) << 4)
 #define NDC_AF_BANKX_HIT_PC(a)		(0x01000 | (a) << 3)
 #define NDC_AF_BANKX_MISS_PC(a)		(0x01100 | (a) << 3)
+
+#define AF_BAR2_ALIASX_SIZE		(0x100000ull)
+#define SSOW_AF_BAR2_SEL		(0x9000000ull)
+#define SSO_AF_BAR2_SEL			(0x9000000ull)
+
+#define AF_BAR2_ALIASX(a, b)		(0x9100000ull | (a) << 12 | (b))
+#define SSOW_AF_BAR2_ALIASX(a, b)	AF_BAR2_ALIASX(a, b)
+#define SSO_AF_BAR2_ALIASX(a, b)	AF_BAR2_ALIASX(a, b)
+
 #endif /* RVU_REG_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
new file mode 100644
index 0000000..cc80cc7
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
@@ -0,0 +1,837 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/types.h>
+
+#include "rvu_struct.h"
+
+#include "rvu_reg.h"
+#include "rvu.h"
+
+#if defined(CONFIG_ARM64)
+#define rvu_sso_store_pair(val0, val1, addr) ({				\
+	__asm__ volatile("stp %x[x0], %x[x1], [%x[p1]]"			\
+			 :						\
+			 :						\
+			 [x0]"r"(val0), [x1]"r"(val1), [p1]"r"(addr));	\
+	})
+#else
+#define rvu_sso_store_pair(val0, val1, addr)				\
+	do {								\
+		u64 *addr1 = (void *)addr;				\
+		*addr1 = val0;						\
+		*(u64 *)(((u8 *)addr1) + 8) = val1;			\
+	} while (0)
+#endif
+
+void rvu_sso_hwgrp_config_thresh(struct rvu *rvu, int blkaddr, int lf)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u64 add, grp_thr, grp_rsvd;
+	u64 reg;
+
+	/* Configure IAQ Thresholds */
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf));
+	grp_rsvd = reg & SSO_HWGRP_IAQ_RSVD_THR_MASK;
+	add = hw->sso.iaq_rsvd - grp_rsvd;
+
+	grp_thr = hw->sso.iaq_rsvd & SSO_HWGRP_IAQ_RSVD_THR_MASK;
+	grp_thr |= ((hw->sso.iaq_max & SSO_HWGRP_IAQ_MAX_THR_MASK) <<
+		    SSO_HWGRP_IAQ_MAX_THR_SHIFT);
+
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf), grp_thr);
+
+	if (add)
+		rvu_write64(rvu, blkaddr, SSO_AF_AW_ADD,
+			    (add & SSO_AF_AW_ADD_RSVD_FREE_MASK) <<
+			    SSO_AF_AW_ADD_RSVD_FREE_SHIFT);
+
+	/* Configure TAQ Thresholds */
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_TAQ_THR(lf));
+	grp_rsvd = reg & SSO_HWGRP_TAQ_RSVD_THR_MASK;
+	add = hw->sso.taq_rsvd - grp_rsvd;
+
+	grp_thr = hw->sso.taq_rsvd & SSO_HWGRP_TAQ_RSVD_THR_MASK;
+	grp_thr |= ((hw->sso.taq_max & SSO_HWGRP_TAQ_MAX_THR_MASK) <<
+		    SSO_HWGRP_TAQ_MAX_THR_SHIFT);
+
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_TAQ_THR(lf), grp_thr);
+
+	if (add)
+		rvu_write64(rvu, blkaddr, SSO_AF_TAQ_ADD,
+			    (add & SSO_AF_TAQ_RSVD_FREE_MASK) <<
+			    SSO_AF_TAQ_ADD_RSVD_FREE_SHIFT);
+}
+
+int rvu_sso_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot)
+{
+	int ssow_lf, iue, blkaddr, ssow_blkaddr, err;
+	struct sso_rsrc *sso = &rvu->hw->sso;
+	struct rvu_hwinfo *hw = rvu->hw;
+	u64 aq_cnt, ds_cnt, cq_ds_cnt;
+	u64 reg, add, wqp, val;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	/* Enable BAR2 ALIAS for this pcifunc. */
+	reg = BIT_ULL(16) | pcifunc;
+	rvu_write64(rvu, blkaddr, SSO_AF_BAR2_SEL, reg);
+
+	rvu_write64(rvu, blkaddr,
+		    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_INT_THR), 0x0);
+	rvu_write64(rvu, blkaddr,
+		    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_AQ_THR),
+		    SSO_LF_GGRP_AQ_THR_MASK);
+
+	rvu_write64(rvu, blkaddr,
+		    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_INT),
+		    SSO_LF_GGRP_INT_MASK);
+	rvu_write64(rvu, blkaddr,
+		    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_INT_ENA_W1C),
+		    SSO_LF_GGRP_INT_MASK);
+
+	ssow_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSOW, 0);
+	if (ssow_blkaddr < 0)
+		goto af_cleanup;
+	/* Check if LF is in slot 0, if not no HWS are attached. */
+	ssow_lf = rvu_get_lf(rvu, &hw->block[ssow_blkaddr], pcifunc, 0);
+	if (ssow_lf < 0)
+		goto af_cleanup;
+
+	rvu_write64(rvu, ssow_blkaddr, SSOW_AF_BAR2_SEL, reg);
+
+	/* Ignore all interrupts */
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_INT_ENA_W1C),
+		    SSOW_LF_GWS_INT_MASK);
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_INT),
+		    SSOW_LF_GWS_INT_MASK);
+
+	/* Prepare WS for GW operations. */
+	do {
+		reg = rvu_read64(rvu, ssow_blkaddr,
+				 SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_TAG));
+	} while (reg & BIT_ULL(63));
+
+	if (reg & BIT_ULL(62))
+		rvu_write64(rvu, ssow_blkaddr,
+			    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_OP_DESCHED), 0);
+	else if (((reg >> 32) & SSO_TT_EMPTY) != SSO_TT_EMPTY)
+		rvu_write64(rvu, ssow_blkaddr,
+			    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_OP_SWTAG_FLUSH),
+			    0);
+
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_OP_GWC_INVAL), 0);
+
+	/* Disable add work. */
+	rvu_write64(rvu, blkaddr, SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_QCTL),
+		    0x0);
+
+	/* HRM 14.13.4 (4) */
+	/* Clean up nscheduled IENT let the work flow. */
+	for (iue = 0; iue < sso->sso_iue; iue++) {
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_GRP(iue));
+		if (SSO_AF_HWGRPX_IUEX_NOSCHED(lf, reg)) {
+			wqp = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_WQP(iue));
+			rvu_sso_store_pair(wqp, iue, rvu->afreg_base +
+					   ((ssow_blkaddr << 28) |
+					    SSOW_AF_BAR2_ALIASX(0,
+						  SSOW_LF_GWS_OP_CLR_NSCHED0)));
+		}
+	}
+
+	/* HRM 14.13.4 (6) */
+	/* Drain all the work using grouped gw. */
+	aq_cnt = rvu_read64(rvu, blkaddr,
+			    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_AQ_CNT));
+	ds_cnt = rvu_read64(rvu, blkaddr,
+			    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_MISC_CNT));
+	cq_ds_cnt = rvu_read64(rvu, blkaddr,
+			       SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_INT_CNT));
+	cq_ds_cnt &= SSO_LF_GGRP_INT_CNT_MASK;
+
+	val  = slot;		/* GGRP ID */
+	val |= BIT_ULL(18);	/* Grouped */
+	val |= BIT_ULL(16);	/* WAIT */
+
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_NW_TIM),
+		    SSOW_LF_GWS_MAX_NW_TIM);
+
+	while (aq_cnt || cq_ds_cnt || ds_cnt) {
+		rvu_write64(rvu, ssow_blkaddr,
+			    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_OP_GET_WORK),
+			    val);
+		do {
+			reg = rvu_read64(rvu, ssow_blkaddr,
+					 SSOW_AF_BAR2_ALIASX(0,
+							     SSOW_LF_GWS_TAG));
+		} while (reg & BIT_ULL(63));
+		if (((reg >> 32) & SSO_TT_EMPTY) != SSO_TT_EMPTY)
+			rvu_write64(rvu, ssow_blkaddr,
+				    SSOW_AF_BAR2_ALIASX(0,
+						SSOW_LF_GWS_OP_SWTAG_FLUSH),
+				    0x0);
+		aq_cnt = rvu_read64(rvu, blkaddr,
+				    SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_AQ_CNT)
+				    );
+		ds_cnt = rvu_read64(rvu, blkaddr,
+				    SSO_AF_BAR2_ALIASX(slot,
+						       SSO_LF_GGRP_MISC_CNT));
+		cq_ds_cnt = rvu_read64(rvu, blkaddr,
+				       SSO_AF_BAR2_ALIASX(slot,
+							  SSO_LF_GGRP_INT_CNT));
+		/* Extract cq and ds count */
+		cq_ds_cnt &= SSO_LF_GGRP_INT_CNT_MASK;
+	}
+
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_NW_TIM), 0x0);
+
+	/* HRM 14.13.4 (7) */
+	reg = rvu_read64(rvu, blkaddr,
+			 SSO_AF_BAR2_ALIASX(slot, SSO_LF_GGRP_XAQ_CNT))
+		& SSO_LF_GGRP_XAQ_CNT_MASK;
+	if (reg != 0)
+		dev_warn(rvu->dev,
+			 "SSO_LF[%d]_GGRP_XAQ_CNT is %lld expected 0", lf, reg);
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_PAGE_CNT(lf))
+		& SSO_AF_HWGRP_PAGE_CNT_MASK;
+	if (reg != 0)
+		dev_warn(rvu->dev,
+			 "SSO_AF_HWGRP[%d]_PAGE_CNT is %lld expected 0", lf,
+			 reg);
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf))
+		>> SSO_HWGRP_IAQ_GRP_CNT_SHIFT;
+	reg &= SSO_HWGRP_IAQ_GRP_CNT_MASK;
+	if (reg != 0)
+		dev_warn(rvu->dev,
+			 "SSO_AF_HWGRP[%d]_IAQ_THR is %lld expected 0", lf,
+			 reg);
+	rvu_write64(rvu, ssow_blkaddr, SSOW_AF_BAR2_SEL, 0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWSX_INV(ssow_lf), 0x1);
+
+af_cleanup:
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_UNMAP_INFO);
+	if ((reg & 0xFFF) == pcifunc)
+		rvu_write64(rvu, blkaddr, SSO_AF_ERR0, SSO_AF_ERR0_MASK);
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_UNMAP_INFO2);
+	if ((reg & 0xFFF) == pcifunc)
+		rvu_write64(rvu, blkaddr, SSO_AF_ERR2, SSO_AF_ERR2_MASK);
+
+	rvu_write64(rvu, blkaddr, SSO_AF_POISONX(lf / 64), lf % 64);
+	rvu_write64(rvu, blkaddr, SSO_AF_IU_ACCNTX_RST(lf), 0x1);
+
+	err = rvu_poll_reg(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf),
+			   SSO_HWGRP_AW_STS_NPA_FETCH, true);
+	if (err)
+		dev_warn(rvu->dev,
+			 "SSO_HWGRP(%d)_AW_STATUS[NPA_FETCH] not cleared", lf);
+
+	/* Remove all pointers from XAQ, HRM 14.13.6 */
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR0_ENA_W1C, ~0ULL);
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_AW_CFG(lf));
+	reg = (reg & ~SSO_HWGRP_AW_CFG_RWEN) | SSO_HWGRP_AW_CFG_XAQ_BYP_DIS;
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_CFG(lf), reg);
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf));
+	if (reg & SSO_HWGRP_AW_STS_TPTR_VLD) {
+		/* aura will be torn down, no need to free the pointer. */
+		rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf),
+			    SSO_HWGRP_AW_STS_TPTR_VLD);
+	}
+
+	err = rvu_poll_reg(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf),
+			   SSO_HWGRP_AW_STS_XAQ_BUFSC_MASK, true);
+	if (err) {
+		dev_warn(rvu->dev,
+			 "SSO_HWGRP(%d)_AW_STATUS[XAQ_BUF_CACHED] not cleared",
+			 lf);
+		return err;
+	}
+
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR0, ~0ULL);
+	/* Re-enable error reporting once we're finished */
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR0_ENA_W1S, ~0ULL);
+
+	/* HRM 14.13.4 (13) */
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_CFG(lf),
+		    SSO_HWGRP_AW_CFG_LDWB | SSO_HWGRP_AW_CFG_LDT |
+		    SSO_HWGRP_AW_CFG_STT);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_XAQ_AURA(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_XAQX_GMCTL(lf), 0x0);
+	reg = (SSO_HWGRP_PRI_AFF_MASK << SSO_HWGRP_PRI_AFF_SHIFT) |
+	      (SSO_HWGRP_PRI_WGT_MASK << SSO_HWGRP_PRI_WGT_SHIFT) |
+	      (0x1 << SSO_HWGRP_PRI_WGT_SHIFT);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_PRI(lf), reg);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_WS_PC(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_EXT_PC(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_WA_PC(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_TS_PC(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_DS_PC(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_XAQ_LIMIT(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_IU_ACCNT(lf), 0x0);
+
+	/* The delta between the current and default thresholds
+	 * need to be returned to the SSO
+	 */
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf)) &
+		SSO_HWGRP_IAQ_RSVD_THR_MASK;
+	add = SSO_HWGRP_IAQ_RSVD_THR - reg;
+	reg = (SSO_HWGRP_IAQ_MAX_THR_MASK << SSO_HWGRP_IAQ_MAX_THR_SHIFT) |
+	      SSO_HWGRP_IAQ_RSVD_THR;
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf), reg);
+
+	if (add)
+		rvu_write64(rvu, blkaddr, SSO_AF_AW_ADD,
+			    (add & SSO_AF_AW_ADD_RSVD_FREE_MASK) <<
+			    SSO_AF_AW_ADD_RSVD_FREE_SHIFT);
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_TAQ_THR(lf)) &
+		SSO_HWGRP_TAQ_RSVD_THR_MASK;
+	add = SSO_HWGRP_TAQ_RSVD_THR - reg;
+	reg = (SSO_HWGRP_TAQ_MAX_THR_MASK << SSO_HWGRP_TAQ_MAX_THR_SHIFT) |
+	      SSO_HWGRP_TAQ_RSVD_THR;
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_TAQ_THR(lf), reg);
+	if (add)
+		rvu_write64(rvu, blkaddr, SSO_AF_TAQ_ADD,
+			    (add & SSO_AF_TAQ_RSVD_FREE_MASK) <<
+			    SSO_AF_TAQ_ADD_RSVD_FREE_SHIFT);
+
+	rvu_write64(rvu, blkaddr, SSO_AF_XAQX_HEAD_PTR(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_XAQX_TAIL_PTR(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_XAQX_HEAD_NEXT(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_XAQX_TAIL_NEXT(lf), 0x0);
+
+	rvu_write64(rvu, blkaddr, SSO_AF_BAR2_SEL, 0);
+
+	return 0;
+}
+
+int rvu_ssow_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot)
+{
+	int blkaddr, ssow_blkaddr;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return SSOW_AF_ERR_LF_INVALID;
+
+	ssow_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSOW, 0);
+	if (ssow_blkaddr < 0)
+		return SSOW_AF_ERR_LF_INVALID;
+
+	/* Enable BAR2 alias access. */
+	reg = BIT_ULL(16) | pcifunc;
+	rvu_write64(rvu, ssow_blkaddr, SSOW_AF_BAR2_SEL, reg);
+
+	/* Ignore all interrupts */
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_INT_ENA_W1C),
+		    SSOW_LF_GWS_INT_MASK);
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_INT),
+		    SSOW_LF_GWS_INT_MASK);
+
+	/* HRM 14.13.4 (3) */
+	/* Wait till waitw/desched completes. */
+	do {
+		reg = rvu_read64(rvu, ssow_blkaddr,
+				 SSOW_AF_BAR2_ALIASX(slot,
+						     SSOW_LF_GWS_PENDSTATE));
+	} while (reg & (BIT_ULL(63) | BIT_ULL(58)));
+
+	reg = rvu_read64(rvu, ssow_blkaddr,
+			 SSOW_AF_BAR2_ALIASX(slot, SSOW_LF_GWS_TAG));
+	/* Switch Tag Pending */
+	if (reg & BIT_ULL(62))
+		rvu_write64(rvu, ssow_blkaddr,
+			    SSOW_AF_BAR2_ALIASX(slot, SSOW_LF_GWS_OP_DESCHED),
+			    0x0);
+	/* Tag Type != EMPTY use swtag_flush to release tag-chain. */
+	else if (((reg >> 32) & SSO_TT_EMPTY) != SSO_TT_EMPTY)
+		rvu_write64(rvu, ssow_blkaddr,
+			    SSOW_AF_BAR2_ALIASX(slot,
+						SSOW_LF_GWS_OP_SWTAG_FLUSH),
+			    0x0);
+
+	/* Wait for desched to complete. */
+	do {
+		reg = rvu_read64(rvu, ssow_blkaddr,
+				 SSOW_AF_BAR2_ALIASX(slot,
+						     SSOW_LF_GWS_PENDSTATE));
+	} while (reg & BIT_ULL(58));
+
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_NW_TIM), 0x0);
+	rvu_write64(rvu, ssow_blkaddr,
+		    SSOW_AF_BAR2_ALIASX(0, SSOW_LF_GWS_OP_GWC_INVAL), 0x0);
+
+	/* set SAI_INVAL bit */
+	rvu_write64(rvu, blkaddr, SSO_AF_HWSX_INV(lf), 0x1);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWSX_ARB(lf), 0x0);
+	rvu_write64(rvu, blkaddr, SSO_AF_HWSX_GMCTL(lf), 0x0);
+
+	rvu_write64(rvu, ssow_blkaddr, SSOW_AF_BAR2_SEL, 0x0);
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_hw_setconfig(struct rvu *rvu,
+				      struct sso_hw_setconfig *req,
+				      struct msg_rsp *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int hwgrp, lf, err, blkaddr;
+	u32 npa_aura_id;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	npa_aura_id = req->npa_aura_id;
+
+	/* Check if requested 'SSOLF <=> NPALF' mapping is valid */
+	if (req->npa_pf_func) {
+		/* If default, use 'this' SSOLF's PFFUNC */
+		if (req->npa_pf_func == RVU_DEFAULT_PF_FUNC)
+			req->npa_pf_func = pcifunc;
+		if (!is_pffunc_map_valid(rvu, req->npa_pf_func, BLKTYPE_NPA))
+			return SSO_AF_INVAL_NPA_PF_FUNC;
+	}
+
+	/* Initialize XAQ ring */
+	for (hwgrp = 0; hwgrp < req->hwgrps; hwgrp++) {
+		lf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, hwgrp);
+		if (lf < 0)
+			return SSO_AF_ERR_LF_INVALID;
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf));
+		if (reg & SSO_HWGRP_AW_STS_XAQ_BUFSC_MASK || reg & BIT_ULL(3)) {
+			reg = rvu_read64(rvu, blkaddr,
+					 SSO_AF_HWGRPX_AW_CFG(lf));
+			reg = (reg & ~SSO_HWGRP_AW_CFG_RWEN) |
+			       SSO_HWGRP_AW_CFG_XAQ_BYP_DIS;
+			rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_CFG(lf),
+				    reg);
+
+			reg = rvu_read64(rvu, blkaddr,
+					 SSO_AF_HWGRPX_AW_STATUS(lf));
+			if (reg & SSO_HWGRP_AW_STS_TPTR_VLD) {
+				rvu_poll_reg(rvu, blkaddr,
+					     SSO_AF_HWGRPX_AW_STATUS(lf),
+					     SSO_HWGRP_AW_STS_NPA_FETCH, true);
+
+				rvu_write64(rvu, blkaddr,
+					    SSO_AF_HWGRPX_AW_STATUS(lf),
+					    SSO_HWGRP_AW_STS_TPTR_VLD);
+			}
+
+			if (rvu_poll_reg(rvu, blkaddr,
+					 SSO_AF_HWGRPX_AW_STATUS(lf),
+					 SSO_HWGRP_AW_STS_XAQ_BUFSC_MASK, true))
+				dev_warn(rvu->dev,
+					 "SSO_HWGRP(%d)_AW_STATUS[XAQ_BUF_CACHED] not cleared",
+					 lf);
+		}
+
+		rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_XAQ_AURA(lf),
+			    npa_aura_id);
+		rvu_write64(rvu, blkaddr, SSO_AF_XAQX_GMCTL(lf),
+			    req->npa_pf_func);
+
+		/* enable XAQ */
+		rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_CFG(lf), 0xF);
+
+		/* Wait for ggrp to ack. */
+		err = rvu_poll_reg(rvu, blkaddr,
+				   SSO_AF_HWGRPX_AW_STATUS(lf),
+				   SSO_HWGRP_AW_STS_INIT_STS, false);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf));
+		if (err || (reg & BIT_ULL(4)) || !(reg & BIT_ULL(8))) {
+			dev_warn(rvu->dev, "SSO_HWGRP(%d) XAQ NPA pointer initialization failed",
+				 lf);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_grp_set_priority(struct rvu *rvu,
+					  struct sso_grp_priority *req,
+					  struct msg_rsp *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+	u64 regval;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	regval = (((u64)(req->weight & SSO_HWGRP_PRI_WGT_MASK)
+		  << SSO_HWGRP_PRI_WGT_SHIFT) |
+		  ((u64)(req->affinity & SSO_HWGRP_PRI_AFF_MASK)
+		   << SSO_HWGRP_PRI_AFF_SHIFT) |
+		  (req->priority & SSO_HWGRP_PRI_MASK));
+
+	lf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, req->grp);
+	if (lf < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_PRI(lf), regval);
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_grp_get_priority(struct rvu *rvu,
+					  struct sso_info_req *req,
+					  struct sso_grp_priority *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+	u64 regval;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, req->grp);
+	if (lf < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	regval = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_PRI(lf));
+
+	rsp->weight = (regval >> SSO_HWGRP_PRI_WGT_SHIFT)
+			& SSO_HWGRP_PRI_WGT_MASK;
+	rsp->affinity = (regval >> SSO_HWGRP_PRI_AFF_SHIFT)
+			& SSO_HWGRP_PRI_AFF_MASK;
+	rsp->priority = regval & SSO_HWGRP_PRI_MASK;
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_lf_alloc(struct rvu *rvu, struct sso_lf_alloc_req *req,
+				  struct sso_lf_alloc_rsp *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int ssolf, uniq_ident, rc = 0;
+	struct rvu_pfvf *pfvf;
+	int hwgrp, blkaddr;
+
+	pfvf = rvu_get_pfvf(rvu, pcifunc);
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (pfvf->sso <= 0 || blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	if (!pfvf->sso_uniq_ident) {
+		uniq_ident = rvu_alloc_rsrc(&hw->sso.pfvf_ident);
+		if (uniq_ident < 0) {
+			rc = SSO_AF_ERR_AF_LF_ALLOC;
+			goto exit;
+		}
+		pfvf->sso_uniq_ident = uniq_ident;
+	} else {
+		uniq_ident = pfvf->sso_uniq_ident;
+	}
+
+	/* Set threshold for the In-Unit Accounting Index*/
+	rvu_write64(rvu, blkaddr, SSO_AF_IU_ACCNTX_CFG(uniq_ident),
+		    SSO_AF_HWGRP_IU_ACCNT_MAX_THR << 16);
+
+	for (hwgrp = 0; hwgrp < req->hwgrps; hwgrp++) {
+		ssolf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, hwgrp);
+		if (ssolf < 0)
+			return SSO_AF_ERR_LF_INVALID;
+
+		/* All groups assigned to single SR-IOV function must be
+		 * assigned same unique in-unit accounting index.
+		 */
+		rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_IU_ACCNT(ssolf),
+			    0x10000 | uniq_ident);
+
+		/* Assign unique tagspace */
+		rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_AW_TAGSPACE(ssolf),
+			    uniq_ident);
+	}
+
+exit:
+	rsp->xaq_buf_size = hw->sso.sso_xaq_buf_size;
+	rsp->xaq_wq_entries = hw->sso.sso_xaq_num_works;
+	rsp->in_unit_entries = hw->sso.sso_iue;
+	rsp->hwgrps = hw->sso.sso_hwgrps;
+	return rc;
+}
+
+int rvu_mbox_handler_sso_lf_free(struct rvu *rvu, struct sso_lf_free_req *req,
+				 struct msg_rsp *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int hwgrp, lf, err, blkaddr;
+	struct rvu_pfvf *pfvf;
+
+	pfvf = rvu_get_pfvf(rvu, pcifunc);
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	/* Perform reset of SSO HW GRPs */
+	for (hwgrp = 0; hwgrp < req->hwgrps; hwgrp++) {
+		lf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, hwgrp);
+		if (lf < 0)
+			return SSO_AF_ERR_LF_INVALID;
+
+		err = rvu_sso_lf_teardown(rvu, pcifunc, lf, hwgrp);
+		if (err)
+			return err;
+
+		/* Reset this SSO LF */
+		err = rvu_lf_reset(rvu, &hw->block[blkaddr], lf);
+		if (err)
+			dev_err(rvu->dev, "SSO%d free: failed to reset\n", lf);
+		/* Reset the IAQ and TAQ thresholds */
+		rvu_sso_hwgrp_config_thresh(rvu, blkaddr, lf);
+	}
+
+	if (pfvf->sso_uniq_ident) {
+		rvu_free_rsrc(&hw->sso.pfvf_ident, pfvf->sso_uniq_ident);
+		pfvf->sso_uniq_ident = 0;
+	}
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_ws_cache_inv(struct rvu *rvu, struct msg_req *req,
+				      struct msg_rsp *rsp)
+{
+	int num_lfs, ssowlf, hws, blkaddr;
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	struct rvu_block *block;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSOW, pcifunc);
+	if (blkaddr < 0)
+		return SSOW_AF_ERR_LF_INVALID;
+
+	block = &hw->block[blkaddr];
+
+	num_lfs = rvu_get_rsrc_mapcount(rvu_get_pfvf(rvu, pcifunc),
+					block->type);
+	if (!num_lfs)
+		return SSOW_AF_ERR_LF_INVALID;
+
+	/* SSO HWS invalidate registers are part of SSO AF */
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	for (hws = 0; hws < num_lfs; hws++) {
+		ssowlf = rvu_get_lf(rvu, block, pcifunc, hws);
+		if (ssowlf < 0)
+			return SSOW_AF_ERR_LF_INVALID;
+
+		/* Reset this SSO LF GWS cache */
+		rvu_write64(rvu, blkaddr, SSO_AF_HWSX_INV(ssowlf), 1);
+	}
+
+	return 0;
+}
+
+int rvu_mbox_handler_ssow_lf_alloc(struct rvu *rvu,
+				   struct ssow_lf_alloc_req *req,
+				   struct msg_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	struct rvu_pfvf *pfvf;
+
+	pfvf = rvu_get_pfvf(rvu, pcifunc);
+	if (pfvf->ssow <= 0)
+		return SSOW_AF_ERR_LF_INVALID;
+
+	return 0;
+}
+
+int rvu_mbox_handler_ssow_lf_free(struct rvu *rvu,
+				  struct ssow_lf_free_req *req,
+				  struct msg_rsp *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int ssowlf, hws, err, blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSOW, pcifunc);
+	if (blkaddr < 0)
+		return SSOW_AF_ERR_LF_INVALID;
+
+	for (hws = 0; hws < req->hws; hws++) {
+		ssowlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, hws);
+		if (ssowlf < 0)
+			return SSOW_AF_ERR_LF_INVALID;
+
+		err = rvu_ssow_lf_teardown(rvu, pcifunc, ssowlf, hws);
+		if (err)
+			return err;
+
+		/* Reset this SSO LF */
+		err = rvu_lf_reset(rvu, &hw->block[blkaddr], ssowlf);
+		if (err)
+			dev_err(rvu->dev, "SSOW%d free: failed to reset\n",
+				ssowlf);
+	}
+
+	return 0;
+}
+
+int rvu_sso_init(struct rvu *rvu)
+{
+	u64 iaq_free_cnt, iaq_rsvd, iaq_max, iaq_rsvd_cnt = 0;
+	u64 taq_free_cnt, taq_rsvd, taq_max, taq_rsvd_cnt = 0;
+	struct sso_rsrc *sso = &rvu->hw->sso;
+	int blkaddr, hwgrp, grpmsk, hws, err;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return 0;
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_CONST);
+	/* number of SSO hardware work slots */
+	sso->sso_hws = (reg >> 56) & 0xFF;
+	/* number of SSO hardware groups */
+	sso->sso_hwgrps = (reg & 0xFFFF);
+	/* number of SSO In-Unit entries */
+	sso->sso_iue =  (reg >> 16) & 0xFFFF;
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_CONST1);
+	/* number of work entries in external admission queue (XAQ) */
+	sso->sso_xaq_num_works = (reg >> 16) & 0xFFFF;
+	/* number of bytes in a XAQ buffer */
+	sso->sso_xaq_buf_size = (reg & 0xFFFF);
+
+	/* Configure IAQ entries */
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_AW_WE);
+	iaq_free_cnt = reg & SSO_AF_IAQ_FREE_CNT_MASK;
+
+	/* Give out half of buffers fairly, rest left floating */
+	iaq_rsvd = iaq_free_cnt / sso->sso_hwgrps / 2;
+
+	/* Enforce minimum per hardware requirements */
+	if (iaq_rsvd < SSO_HWGRP_IAQ_RSVD_THR)
+		iaq_rsvd = SSO_HWGRP_IAQ_RSVD_THR;
+	/* To ensure full streaming performance should be at least 208. */
+	iaq_max = iaq_rsvd + SSO_HWGRP_IAQ_MAX_THR_STRM_PERF;
+
+	if (iaq_max >= (SSO_AF_IAQ_FREE_CNT_MAX + 1))
+		iaq_max = SSO_AF_IAQ_FREE_CNT_MAX;
+
+	/* Configure TAQ entries */
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_TAQ_CNT);
+	taq_free_cnt = reg & SSO_AF_TAQ_FREE_CNT_MASK;
+
+	/* Give out half of buffers fairly, rest left floating */
+	taq_rsvd = taq_free_cnt / sso->sso_hwgrps / 2;
+
+	/* Enforce minimum per hardware requirements */
+	if (taq_rsvd < SSO_HWGRP_TAQ_RSVD_THR)
+		taq_rsvd = SSO_HWGRP_TAQ_RSVD_THR;
+	/* To ensure full streaming performance should be at least 16. */
+	taq_max = taq_rsvd + SSO_HWGRP_TAQ_MAX_THR_STRM_PERF;
+
+	if (taq_max >= (SSO_AF_TAQ_FREE_CNT_MAX + 1))
+		taq_max = SSO_AF_TAQ_FREE_CNT_MAX;
+
+	/* Save thresholds to reprogram HWGRPs on reset */
+	sso->iaq_rsvd = iaq_rsvd;
+	sso->iaq_max = iaq_max;
+	sso->taq_rsvd = taq_rsvd;
+	sso->taq_max = taq_max;
+
+	for (hwgrp = 0; hwgrp < sso->sso_hwgrps; hwgrp++) {
+		rvu_sso_hwgrp_config_thresh(rvu, blkaddr, hwgrp);
+		iaq_rsvd_cnt += iaq_rsvd;
+		taq_rsvd_cnt += taq_rsvd;
+	}
+
+	/* Verify SSO_AW_WE[RSVD_FREE], TAQ_CNT[RSVD_FREE] are greater than
+	 * or equal to sum of IAQ[RSVD_THR], TAQ[RSRVD_THR] fields.
+	 */
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_AW_WE);
+	reg = (reg >> SSO_AF_IAQ_RSVD_FREE_SHIFT) & SSO_AF_IAQ_RSVD_FREE_MASK;
+	if (reg < iaq_rsvd_cnt) {
+		dev_warn(rvu->dev, "WARN: Wrong IAQ resource calculations %llx vs %llx\n",
+			 reg, iaq_rsvd_cnt);
+		rvu_write64(rvu, blkaddr, SSO_AF_AW_WE,
+			    (iaq_rsvd_cnt & SSO_AF_IAQ_RSVD_FREE_MASK) <<
+			    SSO_AF_IAQ_RSVD_FREE_SHIFT);
+	}
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_TAQ_CNT);
+	reg = (reg >> SSO_AF_TAQ_RSVD_FREE_SHIFT) & SSO_AF_TAQ_RSVD_FREE_MASK;
+	if (reg < taq_rsvd_cnt) {
+		dev_warn(rvu->dev, "WARN: Wrong TAQ resource calculations %llx vs %llx\n",
+			 reg, taq_rsvd_cnt);
+		rvu_write64(rvu, blkaddr, SSO_AF_TAQ_CNT,
+			    (taq_rsvd_cnt & SSO_AF_TAQ_RSVD_FREE_MASK) <<
+			    SSO_AF_TAQ_RSVD_FREE_SHIFT);
+	}
+
+	/* Unset the HWS Hardware Group Mask.
+	 * The hardware group mask should be set by PF/VF
+	 * using SSOW_LF_GWS_GRPMSK_CHG based on the LF allocations.
+	 */
+	for (grpmsk = 0; grpmsk < (sso->sso_hwgrps / 64); grpmsk++) {
+		for (hws = 0; hws < sso->sso_hws; hws++) {
+			rvu_write64(rvu, blkaddr,
+				    SSO_AF_HWSX_SX_GRPMSKX(hws, 0, grpmsk),
+				    0x0);
+			rvu_write64(rvu, blkaddr,
+				    SSO_AF_HWSX_SX_GRPMSKX(hws, 1, grpmsk),
+				    0x0);
+		}
+	}
+
+	/* Allocate SSO_AF_CONST::HWS + 1. As the total number of pf/vf are
+	 * limited by the numeber of HWS available.
+	 */
+	sso->pfvf_ident.max = sso->sso_hws + 1;
+	err = rvu_alloc_bitmap(&sso->pfvf_ident);
+	if (err)
+		return err;
+
+	/* Reserve one bit so that identifier starts from 1 */
+	rvu_alloc_rsrc(&sso->pfvf_ident);
+
+	return 0;
+}
+
+void rvu_sso_freemem(struct rvu *rvu)
+{
+	struct sso_rsrc *sso = &rvu->hw->sso;
+
+	kfree(sso->pfvf_ident.bmap);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 09/16] octeontx2-af: Config support for per HWGRP thresholds
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (7 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 08/16] octeontx2-af: Add SSO unit support to the AF driver sunil.kovvuri
@ 2019-11-20 17:47 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 10/16] octeontx2-af: add debug msgs for SSO block errors sunil.kovvuri
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:47 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Pavan Nikhilesh, Sunil Goutham

From: Pavan Nikhilesh <pbhagavatula@marvell.com>

Add mbox to support configuring per queue XAQ/TAQ/IAQ thresholds
that helps in prioritizing each HWGRP differently

Also added support to retrieve stats of a given GWS/GGRP by a PF/VF.

Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  30 ++++++
 .../net/ethernet/marvell/octeontx2/af/rvu_sso.c    | 101 +++++++++++++++++++++
 2 files changed, 131 insertions(+)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index ab03769..df35a05 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -167,6 +167,9 @@ M(SSO_GRP_SET_PRIORITY,	0x605, sso_grp_set_priority,			\
 M(SSO_GRP_GET_PRIORITY,	0x606, sso_grp_get_priority,			\
 				sso_info_req, sso_grp_priority)	\
 M(SSO_WS_CACHE_INV,	0x607, sso_ws_cache_inv, msg_req, msg_rsp)	\
+M(SSO_GRP_QOS_CONFIG,	0x608, sso_grp_qos_config, sso_grp_qos_cfg, msg_rsp)\
+M(SSO_GRP_GET_STATS,	0x609, sso_grp_get_stats, sso_info_req, sso_grp_stats)\
+M(SSO_HWS_GET_STATS,	0x610, sso_hws_get_stats, sso_info_req, sso_hws_stats)\
 /* TIM mbox IDs (range 0x800 - 0x9FF) */				\
 /* CPT mbox IDs (range 0xA00 - 0xBFF) */				\
 /* NPC mbox IDs (range 0x6000 - 0x7FFF) */				\
@@ -800,6 +803,33 @@ struct ssow_lf_free_req {
 	u16 hws;
 };
 
+struct sso_grp_qos_cfg {
+	struct mbox_msghdr hdr;
+	u16 grp;
+	u32 xaq_limit;
+	u16 taq_thr;
+	u16 iaq_thr;
+};
+
+struct sso_grp_stats {
+	struct mbox_msghdr hdr;
+	u16 grp;
+	u64 ws_pc;
+	u64 ext_pc;
+	u64 wa_pc;
+	u64 ts_pc;
+	u64 ds_pc;
+	u64 dq_pc;
+	u64 aw_status;
+	u64 page_cnt;
+};
+
+struct sso_hws_stats {
+	struct mbox_msghdr hdr;
+	u16 hws;
+	u64 arbitration;
+};
+
 /* NPC mbox message structs */
 
 #define NPC_MCAM_ENTRY_INVALID	0xFFFF
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
index cc80cc7..8e0d3df 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
@@ -534,6 +534,107 @@ int rvu_mbox_handler_sso_grp_get_priority(struct rvu *rvu,
 	return 0;
 }
 
+int rvu_mbox_handler_sso_grp_qos_config(struct rvu *rvu,
+					struct sso_grp_qos_cfg *req,
+					struct msg_rsp *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	u64 regval, grp_rsvd;
+	int lf, blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, req->grp);
+	if (lf < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	/* Check if GGRP has been active. */
+	regval = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_WA_PC(lf));
+	if (regval)
+		return SSO_AF_ERR_GRP_EBUSY;
+
+	/* Configure XAQ threhold */
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_XAQ_LIMIT(lf), req->xaq_limit);
+
+	/* Configure TAQ threhold */
+	regval = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_TAQ_THR(lf));
+	grp_rsvd = regval & SSO_HWGRP_TAQ_RSVD_THR_MASK;
+	if (req->taq_thr < grp_rsvd)
+		req->taq_thr = grp_rsvd;
+
+	regval = req->taq_thr & SSO_HWGRP_TAQ_MAX_THR_MASK;
+	regval = (regval << SSO_HWGRP_TAQ_MAX_THR_SHIFT) | grp_rsvd;
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_TAQ_THR(lf), regval);
+
+	/* Configure IAQ threhold */
+	regval = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf));
+	grp_rsvd = regval & SSO_HWGRP_IAQ_RSVD_THR_MASK;
+	if (req->iaq_thr < grp_rsvd + 4)
+		req->iaq_thr = grp_rsvd + 4;
+
+	regval = req->iaq_thr & SSO_HWGRP_IAQ_MAX_THR_MASK;
+	regval = (regval << SSO_HWGRP_IAQ_MAX_THR_SHIFT) | grp_rsvd;
+	rvu_write64(rvu, blkaddr, SSO_AF_HWGRPX_IAQ_THR(lf), regval);
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_grp_get_stats(struct rvu *rvu,
+				       struct sso_info_req *req,
+				       struct sso_grp_stats *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, req->grp);
+	if (lf < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	rsp->ws_pc = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_WS_PC(lf));
+	rsp->ext_pc = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_EXT_PC(lf));
+	rsp->wa_pc = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_WA_PC(lf));
+	rsp->ts_pc = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_TS_PC(lf));
+	rsp->ds_pc = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_DS_PC(lf));
+	rsp->dq_pc = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_DQ_PC(lf));
+	rsp->aw_status = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_AW_STATUS(lf));
+	rsp->page_cnt = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_PAGE_CNT(lf));
+
+	return 0;
+}
+
+int rvu_mbox_handler_sso_hws_get_stats(struct rvu *rvu,
+				       struct sso_info_req *req,
+				       struct sso_hws_stats *rsp)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr, ssow_blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, pcifunc);
+	if (blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	ssow_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSOW, pcifunc);
+	if (ssow_blkaddr < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &hw->block[ssow_blkaddr], pcifunc, req->hws);
+	if (lf < 0)
+		return SSO_AF_ERR_LF_INVALID;
+
+	rsp->arbitration = rvu_read64(rvu, blkaddr, SSO_AF_HWSX_ARB(lf));
+
+	return 0;
+}
+
 int rvu_mbox_handler_sso_lf_alloc(struct rvu *rvu, struct sso_lf_alloc_req *req,
 				  struct sso_lf_alloc_rsp *rsp)
 {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 10/16] octeontx2-af: add debug msgs for SSO block errors
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (8 preceding siblings ...)
  2019-11-20 17:47 ` [PATCH v3 09/16] octeontx2-af: Config support for per HWGRP thresholds sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 11/16] octeontx2-af: add debugfs support for sso sunil.kovvuri
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Pavan Nikhilesh, Sunil Goutham

From: Pavan Nikhilesh <pbhagavatula@marvell.com>

Added debug messages for SSO_AF_ERR0, SSO_AF_ERR2 and SSO_AF_RAS SSO AF
error interrupts.

Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |   5 +
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   2 +
 .../net/ethernet/marvell/octeontx2/af/rvu_sso.c    | 208 +++++++++++++++++++++
 .../net/ethernet/marvell/octeontx2/af/rvu_struct.h |   8 +
 4 files changed, 223 insertions(+)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index c1229e5..bbc0ab7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -2152,6 +2152,7 @@ static void rvu_unregister_interrupts(struct rvu *rvu)
 
 	rvu_npa_unregister_interrupts(rvu);
 	rvu_nix_unregister_interrupts(rvu);
+	rvu_sso_unregister_interrupts(rvu);
 
 	/* Disable the Mbox interrupt */
 	rvu_write64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT_ENA_W1C,
@@ -2369,6 +2370,10 @@ static int rvu_register_interrupts(struct rvu *rvu)
 	if (ret)
 		goto fail;
 
+	ret = rvu_sso_register_interrupts(rvu);
+	if (ret)
+		goto fail;
+
 	return 0;
 fail:
 	rvu_unregister_interrupts(rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index df3cd2b..2216482 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -467,6 +467,8 @@ int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index,
 /* SSO APIs */
 int rvu_sso_init(struct rvu *rvu);
 void rvu_sso_freemem(struct rvu *rvu);
+int rvu_sso_register_interrupts(struct rvu *rvu);
+void rvu_sso_unregister_interrupts(struct rvu *rvu);
 int rvu_sso_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot_id);
 int rvu_ssow_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot_id);
 void rvu_sso_hwgrp_config_thresh(struct rvu *rvu, int blkaddr, int lf);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
index 8e0d3df..832771a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sso.c
@@ -33,6 +33,13 @@
 	} while (0)
 #endif
 
+#define SSO_AF_INT_DIGEST_PRNT(reg)					\
+	for (i = 0; i < block->lf.max / 64; i++) {			\
+		reg0 = rvu_read64(rvu, blkaddr, reg##X(i));		\
+		dev_err(rvu->dev, #reg "(%d) : 0x%llx", i, reg0);	\
+		rvu_write64(rvu, blkaddr, reg##X(i), reg0);		\
+	}
+
 void rvu_sso_hwgrp_config_thresh(struct rvu *rvu, int blkaddr, int lf)
 {
 	struct rvu_hwinfo *hw = rvu->hw;
@@ -808,6 +815,207 @@ int rvu_mbox_handler_ssow_lf_free(struct rvu *rvu,
 	return 0;
 }
 
+static int rvu_sso_do_register_interrupt(struct rvu *rvu, int irq_offs,
+					 irq_handler_t handler,
+					 const char *name)
+{
+	int ret = 0;
+
+	ret = request_irq(pci_irq_vector(rvu->pdev, irq_offs), handler, 0,
+			  name, rvu);
+	if (ret) {
+		dev_err(rvu->dev, "SSOAF: %s irq registration failed", name);
+		goto err;
+	}
+
+	WARN_ON(rvu->irq_allocated[irq_offs]);
+	rvu->irq_allocated[irq_offs] = true;
+err:
+	return ret;
+}
+
+static irqreturn_t rvu_sso_af_err0_intr_handler(int irq, void *ptr)
+{
+	struct rvu *rvu = (struct rvu *)ptr;
+	struct rvu_block *block;
+	int i, blkaddr;
+	u64 reg, reg0;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	block = &rvu->hw->block[blkaddr];
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_ERR0);
+	dev_err(rvu->dev, "Received SSO_AF_ERR0 irq : 0x%llx", reg);
+
+	if (reg & BIT_ULL(15)) {
+		dev_err(rvu->dev, "Received Bad-fill-packet NCB error");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_POISON)
+	}
+
+	if (reg & BIT_ULL(14)) {
+		dev_err(rvu->dev, "An FLR was initiated, but SSO_LF_GGRP_AQ_CNT[AQ_CNT] != 0");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_FLR_AQ_DIGEST)
+	}
+
+	if (reg & BIT_ULL(13)) {
+		dev_err(rvu->dev, "Add work dropped due to XAQ pointers not yet initialized.");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_XAQDIS_DIGEST)
+	}
+
+	if (reg & (0xF << 9)) {
+		dev_err(rvu->dev, "PF_FUNC mapping error.");
+		dev_err(rvu->dev, "SSO_AF_UNMAP_INFO : 0x%llx",
+			rvu_read64(rvu, blkaddr, SSO_AF_UNMAP_INFO));
+	}
+
+	if (reg & BIT_ULL(8)) {
+		dev_err(rvu->dev, "Add work dropped due to QTL being disabled, 0x0");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_QCTLDIS_DIGEST)
+	}
+
+	if (reg & BIT_ULL(7)) {
+		dev_err(rvu->dev, "Add work dropped due to WQP being 0x0");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_WQP0_DIGEST)
+	}
+
+	if (reg & BIT_ULL(6))
+		dev_err(rvu->dev, "Add work dropped due to 64 bit write");
+
+	if (reg & BIT_ULL(5))
+		dev_err(rvu->dev, "Set when received add work with tag type is specified as EMPTY");
+
+	if (reg & BIT_ULL(4)) {
+		dev_err(rvu->dev, "Add work to disabled hardware group. An ADDWQ was received and dropped to a hardware group with SSO_AF_HWGRP(0..255)_IAQ_THR[RSVD_THR] = 0.");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_GRPDIS_DIGEST)
+	}
+
+	if (reg & BIT_ULL(3)) {
+		dev_err(rvu->dev, "Bad-fill-packet NCB error");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_BFPN_DIGEST)
+	}
+
+	if (reg & BIT_ULL(2)) {
+		dev_err(rvu->dev, "Bad-fill-packet error.");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_BFP_DIGEST)
+	}
+
+	if (reg & BIT_ULL(1)) {
+		dev_err(rvu->dev, "The NPA returned an error indication");
+		SSO_AF_INT_DIGEST_PRNT(SSO_AF_NPA_DIGEST)
+	}
+
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR0, reg);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_sso_af_err2_intr_handler(int irq, void *ptr)
+{
+	struct rvu *rvu = (struct rvu *)ptr;
+	int blkaddr;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_ERR2);
+	dev_err(rvu->dev, "received SSO_AF_ERR2 irq : 0x%llx", reg);
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR2, reg);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_sso_af_ras_intr_handler(int irq, void *ptr)
+{
+	struct rvu *rvu = (struct rvu *)ptr;
+	struct rvu_block *block;
+	int i, blkaddr;
+	u64 reg, reg0;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return IRQ_NONE;
+
+	block = &rvu->hw->block[blkaddr];
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_RAS);
+	dev_err(rvu->dev, "received SSO_AF_RAS irq : 0x%llx", reg);
+	rvu_write64(rvu, blkaddr, SSO_AF_RAS, reg);
+	SSO_AF_INT_DIGEST_PRNT(SSO_AF_POISON)
+
+	return IRQ_HANDLED;
+}
+
+void rvu_sso_unregister_interrupts(struct rvu *rvu)
+{
+	int i, blkaddr, offs;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	offs = rvu_read64(rvu, blkaddr, SSO_PRIV_AF_INT_CFG) & 0x7FF;
+	if (!offs)
+		return;
+
+	rvu_write64(rvu, blkaddr, SSO_AF_RAS_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR2_ENA_W1C, ~0ULL);
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR0_ENA_W1C, ~0ULL);
+
+	for (i = 0; i < SSO_AF_INT_VEC_CNT; i++)
+		if (rvu->irq_allocated[offs + i]) {
+			free_irq(pci_irq_vector(rvu->pdev, offs + i), rvu);
+			rvu->irq_allocated[offs + i] = false;
+		}
+}
+
+int rvu_sso_register_interrupts(struct rvu *rvu)
+{
+	int blkaddr, offs, ret = 0;
+
+	if (!is_block_implemented(rvu->hw, BLKADDR_SSO))
+		return 0;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return blkaddr;
+
+	offs = rvu_read64(rvu, blkaddr, SSO_PRIV_AF_INT_CFG) & 0x7FF;
+	if (!offs) {
+		dev_warn(rvu->dev,
+			 "Failed to get SSO_AF_INT vector offsets\n");
+		return 0;
+	}
+
+	ret = rvu_sso_do_register_interrupt(rvu, offs + SSO_AF_INT_VEC_ERR0,
+					    rvu_sso_af_err0_intr_handler,
+					    "SSO_AF_ERR0");
+	if (ret)
+		goto err;
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR0_ENA_W1S, ~0ULL);
+
+	ret = rvu_sso_do_register_interrupt(rvu, offs + SSO_AF_INT_VEC_ERR2,
+					    rvu_sso_af_err2_intr_handler,
+					    "SSO_AF_ERR2");
+	if (ret)
+		goto err;
+	rvu_write64(rvu, blkaddr, SSO_AF_ERR2_ENA_W1S, ~0ULL);
+
+	ret = rvu_sso_do_register_interrupt(rvu, offs + SSO_AF_INT_VEC_RAS,
+					    rvu_sso_af_ras_intr_handler,
+					    "SSO_AF_RAS");
+	if (ret)
+		goto err;
+	rvu_write64(rvu, blkaddr, SSO_AF_RAS_ENA_W1S, ~0ULL);
+
+	return 0;
+err:
+	rvu_sso_unregister_interrupts(rvu);
+	return ret;
+}
+
 int rvu_sso_init(struct rvu *rvu)
 {
 	u64 iaq_free_cnt, iaq_rsvd, iaq_max, iaq_rsvd_cnt = 0;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index a665fa2..3c60abe 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -80,6 +80,14 @@ enum nix_af_int_vec_e {
 	NIX_AF_INT_VEC_CNT	= 0x5,
 };
 
+/* SSO Admin function Interrupt Vector Enumeration */
+enum sso_af_int_vec_e {
+	SSO_AF_INT_VEC_ERR0 = 0x0,
+	SSO_AF_INT_VEC_ERR2 = 0x1,
+	SSO_AF_INT_VEC_RAS  = 0x2,
+	SSO_AF_INT_VEC_CNT  = 0x3,
+};
+
 /**
  * RVU PF Interrupt Vector Enumeration
  */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 11/16] octeontx2-af: add debugfs support for sso
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (9 preceding siblings ...)
  2019-11-20 17:48 ` [PATCH v3 10/16] octeontx2-af: add debug msgs for SSO block errors sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 12/16] octeontx2-af: Add TIM unit support sunil.kovvuri
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Pavan Nikhilesh, Sunil Goutham

From: Pavan Nikhilesh <pbhagavatula@marvell.com>

Add debugfs for HWGRP performance counter stats, internal queue walks
and few HWS debug registers.

Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   3 +
 .../ethernet/marvell/octeontx2/af/rvu_debugfs.c    | 699 +++++++++++++++++++++
 2 files changed, 702 insertions(+)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 2216482..fa0f3ca 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -50,6 +50,9 @@ struct rvu_debugfs {
 	struct dentry *npa;
 	struct dentry *nix;
 	struct dentry *npc;
+	struct dentry *sso;
+	struct dentry *sso_hwgrp;
+	struct dentry *sso_hws;
 	struct dump_ctx npa_aura_ctx;
 	struct dump_ctx npa_pool_ctx;
 	struct dump_ctx nix_cq_ctx;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index 77adad4..524d56d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -1676,6 +1676,704 @@ static void rvu_dbg_npc_init(struct rvu *rvu)
 	debugfs_remove_recursive(rvu->rvu_dbg.npc);
 }
 
+static int parse_sso_cmd_buffer(char *cmd_buf, size_t *count,
+				const char __user *buffer, int *ssolf,
+				bool *all)
+{
+	int ret, bytes_not_copied;
+	char *cmd_buf_tmp;
+	char *subtoken;
+
+	bytes_not_copied = copy_from_user(cmd_buf, buffer, *count);
+	if (bytes_not_copied)
+		return -EFAULT;
+
+	cmd_buf[*count] = '\0';
+	cmd_buf_tmp = strchr(cmd_buf, '\n');
+
+	if (cmd_buf_tmp) {
+		*cmd_buf_tmp = '\0';
+		*count = cmd_buf_tmp - cmd_buf + 1;
+	}
+
+	subtoken = strsep(&cmd_buf, " ");
+	if (subtoken && strcmp(subtoken, "all") == 0) {
+		*all = true;
+	} else {
+		ret = subtoken ? kstrtoint(subtoken, 10, ssolf) : -EINVAL;
+		if (ret < 0)
+			return ret;
+	}
+	if (cmd_buf)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void sso_hwgrp_display_iq_list(struct rvu *rvu, int ssolf, u16 idx,
+				      u16 tail_idx, u8 queue_type)
+{
+	const char *queue[3] = {"DQ", "CQ", "AQ"};
+	int blkaddr;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	pr_info("SSO HWGGRP[%d] [%s] Chain queue head[%d]", ssolf,
+		queue[queue_type], idx);
+	pr_info("SSO HWGGRP[%d] [%s] Chain queue tail[%d]", ssolf,
+		queue[queue_type], tail_idx);
+	pr_info("--------------------------------------------------\n");
+	do {
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_TAG(idx));
+		pr_info("SSO HWGGRP[%d] [%s] IE[%d] TAG      0x%llx\n", ssolf,
+			queue[queue_type], idx, reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_GRP(idx));
+		pr_info("SSO HWGGRP[%d] [%s] IE[%d] GRP      0x%llx\n", ssolf,
+			queue[queue_type], idx, reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_PENDTAG(idx));
+		pr_info("SSO HWGGRP[%d] [%s] IE[%d] PENDTAG  0x%llx\n", ssolf,
+			queue[queue_type], idx, reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_LINKS(idx));
+		pr_info("SSO HWGGRP[%d] [%s] IE[%d] LINKS    0x%llx\n", ssolf,
+			queue[queue_type], idx, reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_QLINKS(idx));
+		pr_info("SSO HWGGRP[%d] [%s] IE[%d] QLINKS   0x%llx\n", ssolf,
+			queue[queue_type], idx, reg);
+		pr_info("--------------------------------------------------\n");
+		if (idx == tail_idx)
+			break;
+		idx = reg & 0x1FFF;
+	} while (idx != 0x1FFF);
+}
+
+static void sso_hwgrp_display_taq_list(struct rvu *rvu, int ssolf, u8 wae_head,
+				       u16 ent_head, u8 wae_used, u8 taq_lines)
+{
+	int i, blkaddr;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	pr_info("--------------------------------------------------\n");
+	do {
+		for (i = wae_head; i < taq_lines && wae_used; i++) {
+			reg = rvu_read64(rvu, blkaddr,
+					 SSO_AF_TAQX_WAEY_TAG(ent_head, i));
+			pr_info("SSO HWGGRP[%d] TAQ[%d] WAE[%d] TAG  0x%llx\n",
+				ssolf, ent_head, i, reg);
+
+			reg = rvu_read64(rvu, blkaddr,
+					 SSO_AF_TAQX_WAEY_WQP(ent_head, i));
+			pr_info("SSO HWGGRP[%d] TAQ[%d] WAE[%d] WQP  0x%llx\n",
+				ssolf, ent_head, i, reg);
+			wae_used--;
+		}
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_TAQX_LINK(ent_head));
+		pr_info("SSO HWGGRP[%d] TAQ[%d] LINK         0x%llx\n",
+			ssolf, ent_head, reg);
+		ent_head = reg & 0x7FF;
+		pr_info("--------------------------------------------------\n");
+	} while (ent_head && wae_used);
+}
+
+static int read_sso_pc(struct rvu *rvu)
+{
+	int blkaddr;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return -ENODEV;
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_ACTIVE_CYCLES0);
+	pr_info("SSO Add-Work active cycles		%lld\n", reg);
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_ACTIVE_CYCLES1);
+	pr_info("SSO Get-Work active cycles		%lld\n", reg);
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_ACTIVE_CYCLES2);
+	pr_info("SSO Work-Slot active cycles		%lld\n", reg);
+	pr_info("\n");
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_NOS_CNT) & 0x1FFF;
+	pr_info("SSO work-queue entries on the no-schedule list	%lld\n", reg);
+	pr_info("\n");
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_AW_READ_ARB);
+	pr_info("SSO XAQ reads outstanding		%lld\n",
+		(reg >> 24) & 0x3F);
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_XAQ_REQ_PC);
+	pr_info("SSO XAQ reads requests			%lld\n", reg);
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_XAQ_LATENCY_PC);
+	pr_info("SSO XAQ read latency cycles		%lld\n", reg);
+	pr_info("\n");
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_AW_WE);
+	pr_info("SSO IAQ reserved			%lld\n",
+		(reg >> 16) & 0x3FFF);
+	pr_info("SSO IAQ total				%lld\n", reg & 0x3FFF);
+	pr_info("\n");
+
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_TAQ_CNT);
+	pr_info("SSO TAQ reserved			%lld\n",
+		(reg >> 16) & 0x7FF);
+	pr_info("SSO TAQ total				%lld\n", reg & 0x7FF);
+	pr_info("\n");
+
+	return 0;
+}
+
+/* Reads SSO hwgrp perfomance counters */
+static void read_sso_hwgrp_pc(struct rvu *rvu, int ssolf, bool all)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	struct rvu_block *block;
+	int blkaddr, max_id;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	block = &hw->block[blkaddr];
+	if (ssolf < 0 || ssolf >= block->lf.max) {
+		pr_info("Invalid SSOLF(HWGRP), valid range is 0-%d\n",
+			block->lf.max - 1);
+		return;
+	}
+	max_id =  block->lf.max;
+
+	if (all)
+		ssolf = 0;
+	else
+		max_id = ssolf + 1;
+
+	pr_info("==================================================\n");
+	for (; ssolf < max_id; ssolf++) {
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_WS_PC(ssolf));
+		pr_info("SSO HWGGRP[%d] Work-Schedule PC     0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_EXT_PC(ssolf));
+		pr_info("SSO HWGGRP[%d] External Schedule PC 0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_WA_PC(ssolf));
+		pr_info("SSO HWGGRP[%d] Work-Add PC          0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_TS_PC(ssolf));
+		pr_info("SSO HWGGRP[%d] Tag Switch PC        0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_DS_PC(ssolf));
+		pr_info("SSO HWGGRP[%d] Deschedule PC        0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWGRPX_DQ_PC(ssolf));
+		pr_info("SSO HWGGRP[%d] Work-Descheduled PC  0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_HWGRPX_PAGE_CNT(ssolf));
+		pr_info("SSO HWGGRP[%d] In-use Page Count    0x%llx\n", ssolf,
+			reg);
+		pr_info("==================================================\n");
+	}
+}
+
+/* Reads SSO hwgrp Threshold */
+static void read_sso_hwgrp_thresh(struct rvu *rvu, int ssolf, bool all)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	struct rvu_block *block;
+	int blkaddr, max_id;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	block = &hw->block[blkaddr];
+	if (ssolf < 0 || ssolf >= block->lf.max) {
+		pr_info("Invalid SSOLF(HWGRP), valid range is 0-%d\n",
+			block->lf.max - 1);
+		return;
+	}
+	max_id =  block->lf.max;
+
+	if (all)
+		ssolf = 0;
+	else
+		max_id = ssolf + 1;
+
+	pr_info("==================================================\n");
+	for (; ssolf < max_id; ssolf++) {
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_HWGRPX_IAQ_THR(ssolf));
+		pr_info("SSO HWGGRP[%d] IAQ Threshold        0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_HWGRPX_TAQ_THR(ssolf));
+		pr_info("SSO HWGGRP[%d] TAQ Threshold        0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_HWGRPX_XAQ_AURA(ssolf));
+		pr_info("SSO HWGGRP[%d] XAQ Aura             0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_HWGRPX_XAQ_LIMIT(ssolf));
+		pr_info("SSO HWGGRP[%d] XAQ Limit            0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_HWGRPX_IU_ACCNT(ssolf));
+		pr_info("SSO HWGGRP[%d] IU Account Index     0x%llx\n", ssolf,
+			reg);
+
+		reg = rvu_read64(rvu, blkaddr,
+				 SSO_AF_IU_ACCNTX_CFG(reg & 0xFF));
+		pr_info("SSO HWGGRP[%d] IU Accounting Cfg    0x%llx\n", ssolf,
+			reg);
+		pr_info("==================================================\n");
+	}
+}
+
+/* Reads SSO hwgrp TAQ list */
+static void read_sso_hwgrp_taq_list(struct rvu *rvu, int ssolf, bool all)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	u8 taq_entries, wae_head;
+	struct rvu_block *block;
+	u16 ent_head, cl_used;
+	int blkaddr, max_id;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	block = &hw->block[blkaddr];
+	if (ssolf < 0 || ssolf >= block->lf.max) {
+		pr_info("Invalid SSOLF(HWGRP), valid range is 0-%d\n",
+			block->lf.max - 1);
+		return;
+	}
+	max_id =  block->lf.max;
+
+	if (all)
+		ssolf = 0;
+	else
+		max_id = ssolf + 1;
+	reg = rvu_read64(rvu, blkaddr, SSO_AF_CONST);
+	taq_entries = (reg >> 48) & 0xFF;
+	pr_info("==================================================\n");
+	for (; ssolf < max_id; ssolf++) {
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("SSO HWGGRP[%d] Transitory Output Admission Queue",
+			ssolf);
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_TOAQX_STATUS(ssolf));
+		pr_info("SSO HWGGRP[%d] TOAQ Status          0x%llx\n", ssolf,
+			reg);
+		ent_head = (reg >> 12) & 0x7FF;
+		cl_used = (reg >> 32) & 0x7FF;
+		if (reg & BIT_ULL(61) && cl_used) {
+			pr_info("SSO HWGGRP[%d] TOAQ CL_USED         0x%x\n",
+				ssolf, cl_used);
+			sso_hwgrp_display_taq_list(rvu, ssolf, ent_head, 0,
+						   cl_used * taq_entries,
+						   taq_entries);
+		}
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("SSO HWGGRP[%d] Transitory Input Admission Queue",
+			ssolf);
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_TIAQX_STATUS(ssolf));
+		pr_info("SSO HWGGRP[%d] TIAQ Status          0x%llx\n", ssolf,
+			reg);
+		wae_head = (reg >> 60) & 0xF;
+		cl_used = (reg >> 32) & 0x7FFF;
+		ent_head = (reg >> 12) & 0x7FF;
+		if (reg & BIT_ULL(61) && cl_used) {
+			pr_info("SSO HWGGRP[%d] TIAQ WAE_USED         0x%x\n",
+				ssolf, cl_used);
+			sso_hwgrp_display_taq_list(rvu, ssolf, ent_head,
+						   wae_head, cl_used,
+						   taq_entries);
+		}
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("==================================================\n");
+	}
+}
+
+/* Reads SSO hwgrp IAQ list */
+static void read_sso_hwgrp_iaq_list(struct rvu *rvu, int ssolf, bool all)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	struct rvu_block *block;
+	u16 head_idx, tail_idx;
+	int blkaddr, max_id;
+	u64 reg;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	block = &hw->block[blkaddr];
+	if (ssolf < 0 || ssolf >= block->lf.max) {
+		pr_info("Invalid SSOLF(HWGRP), valid range is 0-%d\n",
+			block->lf.max - 1);
+		return;
+	}
+	max_id =  block->lf.max;
+
+	if (all)
+		ssolf = 0;
+	else
+		max_id = ssolf + 1;
+	pr_info("==================================================\n");
+	for (; ssolf < max_id; ssolf++) {
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("SSO HWGGRP[%d] Deschedule Queue(DQ)\n", ssolf);
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IPL_DESCHEDX(ssolf));
+		pr_info("SSO HWGGRP[%d] DQ List              0x%llx\n", ssolf,
+			reg);
+		head_idx = (reg >> 13) & 0x1FFF;
+		tail_idx = reg & 0x1FFF;
+		if (reg & (BIT_ULL(26) | BIT_ULL(27)))
+			sso_hwgrp_display_iq_list(rvu, ssolf, head_idx,
+						  tail_idx, 0);
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("SSO HWGGRP[%d] Conflict Queue(CQ)\n", ssolf);
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IPL_CONFX(ssolf));
+		pr_info("SSO HWGGRP[%d] CQ List              0x%llx\n", ssolf,
+			reg);
+		head_idx = (reg >> 13) & 0x1FFF;
+		tail_idx = reg & 0x1FFF;
+		if (reg & (BIT_ULL(26) | BIT_ULL(27)))
+			sso_hwgrp_display_iq_list(rvu, ssolf, head_idx,
+						  tail_idx, 1);
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("SSO HWGGRP[%d] Admission Queue(AQ)\n", ssolf);
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IPL_IAQX(ssolf));
+		pr_info("SSO HWGGRP[%d] AQ List              0x%llx\n", ssolf,
+			reg);
+		head_idx = (reg >> 13) & 0x1FFF;
+		tail_idx = reg & 0x1FFF;
+		if (reg & (BIT_ULL(26) | BIT_ULL(27)))
+			sso_hwgrp_display_iq_list(rvu, ssolf, head_idx,
+						  tail_idx, 2);
+		pr_info("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+		pr_info("==================================================\n");
+	}
+}
+
+/* Reads SSO hwgrp IENT list */
+static int read_sso_hwgrp_ient_list(struct rvu *rvu)
+{
+	const char *tt_c[4] = {"SSO_TT_ORDERED_", "SSO_TT_ATOMIC__",
+				"SSO_TT_UNTAGGED", "SSO_TT_EMPTY___"};
+	struct rvu_hwinfo *hw = rvu->hw;
+	int max_idx = hw->sso.sso_iue;
+	u64 pendtag, qlinks, links;
+	int len, idx, blkaddr;
+	u64 tag, grp, wqp;
+	char str[300];
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return -ENODEV;
+
+	for (idx = 0; idx < max_idx; idx++) {
+		len = 0;
+		tag = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_TAG(idx));
+		grp = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_GRP(idx));
+		pendtag = rvu_read64(rvu, blkaddr,
+				     SSO_AF_IENTX_PENDTAG(idx));
+		links = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_LINKS(idx));
+		qlinks = rvu_read64(rvu, blkaddr,
+				    SSO_AF_IENTX_QLINKS(idx));
+		wqp = rvu_read64(rvu, blkaddr, SSO_AF_IENTX_WQP(idx));
+		len = snprintf(str + len, 300,
+			       "SSO IENT[%4d] TT [%s] HWGRP [%3lld] ", idx,
+				tt_c[(tag >> 32) & 0x3], (grp >> 48) & 0x1f);
+		len += snprintf(str + len, 300 - len,
+				"TAG [0x%010llx] GRP [0x%016llx] ", tag, grp);
+		len += snprintf(str + len, 300 - len, "PENDTAG [0x%010llx] ",
+				pendtag);
+		len += snprintf(str + len, 300 - len,
+				"LINKS [0x%016llx] QLINKS [0x%010llx] ", links,
+				qlinks);
+		snprintf(str + len, 300 - len, "WQP [0x%016llx]\n", wqp);
+		pr_info("%s", str);
+	}
+
+	return 0;
+}
+
+/* Reads SSO hwgrp free list */
+static int read_sso_hwgrp_free_list(struct rvu *rvu)
+{
+	int blkaddr;
+	u64 reg;
+	u8 idx;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return -ENODEV;
+
+	pr_info("==================================================\n");
+	for (idx = 0; idx < 4; idx++) {
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_IPL_FREEX(idx));
+		pr_info("SSO FREE LIST[%d]\n", idx);
+		pr_info("qnum_head : %lld qnum_tail : %lld\n",
+			(reg >> 58) & 0x3, (reg >> 56) & 0x3);
+		pr_info("queue_cnt : %llx\n", (reg >> 26) & 0x7fff);
+		pr_info("queue_val : %lld queue_head : %4lld queue_tail %4lld\n"
+			, (reg >> 40) & 0x1, (reg >> 13) & 0x1fff,
+			reg & 0x1fff);
+		pr_info("==================================================\n");
+	}
+
+	return 0;
+}
+
+/* Reads SSO hwgrp perfomance counters */
+static void read_sso_hws_info(struct rvu *rvu, int ssowlf, bool all)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	struct rvu_block *block;
+	int blkaddr;
+	int max_id;
+	u64 reg;
+	u8 mask;
+	u8 set;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSOW, 0);
+	if (blkaddr < 0)
+		return;
+
+	block = &hw->block[blkaddr];
+	if (ssowlf < 0 || ssowlf >= block->lf.max) {
+		pr_info("Invalid SSOWLF(HWS), valid range is 0-%d\n",
+			block->lf.max - 1);
+		return;
+	}
+	max_id =  block->lf.max;
+
+	if (all)
+		ssowlf = 0;
+	else
+		max_id = ssowlf + 1;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_SSO, 0);
+	if (blkaddr < 0)
+		return;
+
+	pr_info("==================================================\n");
+	for (; ssowlf < max_id; ssowlf++) {
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWSX_ARB(ssowlf));
+		pr_info("SSOW HWS[%d] Arbitration State      0x%llx\n", ssowlf,
+			reg);
+		reg = rvu_read64(rvu, blkaddr, SSO_AF_HWSX_GMCTL(ssowlf));
+		pr_info("SSOW HWS[%d] Guest Machine Control  0x%llx\n", ssowlf,
+			reg);
+		for (set = 0; set < 2; set++)
+			for (mask = 0; mask < 4; mask++) {
+				reg = rvu_read64(rvu, blkaddr,
+						 SSO_AF_HWSX_SX_GRPMSKX(ssowlf, set, mask));
+				pr_info("SSOW HWS[%d] SET[%d] Group Mask[%d] 0x%llx\n",
+					ssowlf, set, mask, reg);
+			}
+		pr_info("==================================================\n");
+	}
+}
+
+typedef void (*sso_dump_cb)(struct rvu *rvu, int ssolf, bool all);
+
+static ssize_t rvu_dbg_sso_cmd_parser(struct file *filp,
+				      const char __user *buffer, size_t count,
+				      loff_t *ppos, char *lf_type,
+				      char *file_nm, sso_dump_cb fn)
+{
+	struct rvu *rvu = filp->private_data;
+	bool all = false;
+	char *cmd_buf;
+	int lf = 0;
+
+	if ((*ppos != 0) || !count)
+		return -EINVAL;
+
+	cmd_buf = kzalloc(count + 1, GFP_KERNEL);
+	if (!cmd_buf)
+		return -ENOSPC;
+
+	if (parse_sso_cmd_buffer(cmd_buf, &count, buffer,
+				 &lf, &all) < 0) {
+		pr_info("Usage: echo [<%s>/all] > %s\n", lf_type, file_nm);
+	} else {
+		fn(rvu, lf, all);
+	}
+	kfree(cmd_buf);
+
+	return count;
+}
+
+/* SSO debugfs APIs */
+static ssize_t rvu_dbg_sso_pc_display(struct file *filp,
+				      char __user *buffer,
+				      size_t count, loff_t *ppos)
+{
+	return read_sso_pc(filp->private_data);
+}
+
+static ssize_t rvu_dbg_sso_hwgrp_pc_display(struct file *filp,
+					    const char __user *buffer,
+					    size_t count, loff_t *ppos)
+{
+	return rvu_dbg_sso_cmd_parser(filp, buffer, count, ppos, "hwgrp",
+			"sso_hwgrp_pc", read_sso_hwgrp_pc);
+}
+
+static ssize_t rvu_dbg_sso_hwgrp_thresh_display(struct file *filp,
+						const char __user *buffer,
+						size_t count, loff_t *ppos)
+{
+	return rvu_dbg_sso_cmd_parser(filp, buffer, count, ppos, "hwgrp",
+			"sso_hwgrp_thresh", read_sso_hwgrp_thresh);
+}
+
+static ssize_t rvu_dbg_sso_hwgrp_taq_wlk_display(struct file *filp,
+						 const char __user *buffer,
+						 size_t count, loff_t *ppos)
+{
+	return rvu_dbg_sso_cmd_parser(filp, buffer, count, ppos, "hwgrp",
+			"sso_hwgrp_taq_wlk", read_sso_hwgrp_taq_list);
+}
+
+static ssize_t rvu_dbg_sso_hwgrp_iaq_wlk_display(struct file *filp,
+						 const char __user *buffer,
+						 size_t count, loff_t *ppos)
+{
+	return rvu_dbg_sso_cmd_parser(filp, buffer, count, ppos, "hwgrp",
+			"sso_hwgrp_iaq_wlk", read_sso_hwgrp_iaq_list);
+}
+
+static ssize_t rvu_dbg_sso_hwgrp_ient_wlk_display(struct file *filp,
+						  char __user *buffer,
+						  size_t count, loff_t *ppos)
+{
+	return read_sso_hwgrp_ient_list(filp->private_data);
+}
+
+static ssize_t rvu_dbg_sso_hwgrp_fl_wlk_display(struct file *filp,
+						char __user *buffer,
+						size_t count, loff_t *ppos)
+{
+	return read_sso_hwgrp_free_list(filp->private_data);
+}
+
+static ssize_t rvu_dbg_sso_hws_info_display(struct file *filp,
+					    const char __user *buffer,
+					    size_t count, loff_t *ppos)
+{
+	return rvu_dbg_sso_cmd_parser(filp, buffer, count, ppos, "hws",
+			"sso_hws_info", read_sso_hws_info);
+}
+
+RVU_DEBUG_FOPS(sso_pc, sso_pc_display, NULL);
+RVU_DEBUG_FOPS(sso_hwgrp_pc, NULL, sso_hwgrp_pc_display);
+RVU_DEBUG_FOPS(sso_hwgrp_thresh, NULL, sso_hwgrp_thresh_display);
+RVU_DEBUG_FOPS(sso_hwgrp_taq_wlk, NULL, sso_hwgrp_taq_wlk_display);
+RVU_DEBUG_FOPS(sso_hwgrp_iaq_wlk, NULL, sso_hwgrp_iaq_wlk_display);
+RVU_DEBUG_FOPS(sso_hwgrp_ient_wlk, sso_hwgrp_ient_wlk_display, NULL);
+RVU_DEBUG_FOPS(sso_hwgrp_fl_wlk, sso_hwgrp_fl_wlk_display, NULL);
+RVU_DEBUG_FOPS(sso_hws_info, NULL, sso_hws_info_display);
+
+static void rvu_dbg_sso_init(struct rvu *rvu)
+{
+	const struct device *dev = &rvu->pdev->dev;
+	struct dentry *pfile;
+
+	rvu->rvu_dbg.sso = debugfs_create_dir("sso", rvu->rvu_dbg.root);
+	if (!rvu->rvu_dbg.sso)
+		return;
+
+	rvu->rvu_dbg.sso_hwgrp = debugfs_create_dir("hwgrp", rvu->rvu_dbg.sso);
+	if (!rvu->rvu_dbg.sso_hwgrp)
+		return;
+
+	rvu->rvu_dbg.sso_hws = debugfs_create_dir("hws", rvu->rvu_dbg.sso);
+	if (!rvu->rvu_dbg.sso_hws)
+		return;
+
+	pfile = debugfs_create_file("sso_pc", 0600,
+				    rvu->rvu_dbg.sso, rvu,
+			&rvu_dbg_sso_pc_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hwgrp_pc", 0600,
+				    rvu->rvu_dbg.sso_hwgrp, rvu,
+			&rvu_dbg_sso_hwgrp_pc_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hwgrp_thresh", 0600,
+				    rvu->rvu_dbg.sso_hwgrp, rvu,
+			&rvu_dbg_sso_hwgrp_thresh_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hwgrp_taq_walk", 0600,
+				    rvu->rvu_dbg.sso_hwgrp, rvu,
+			&rvu_dbg_sso_hwgrp_taq_wlk_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hwgrp_iaq_walk", 0600,
+				    rvu->rvu_dbg.sso_hwgrp, rvu,
+			&rvu_dbg_sso_hwgrp_iaq_wlk_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hwgrp_ient_walk", 0600,
+				    rvu->rvu_dbg.sso_hwgrp, rvu,
+			&rvu_dbg_sso_hwgrp_ient_wlk_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hwgrp_free_list_walk", 0600,
+				    rvu->rvu_dbg.sso_hwgrp, rvu,
+			&rvu_dbg_sso_hwgrp_fl_wlk_fops);
+	if (!pfile)
+		goto create_failed;
+
+	pfile = debugfs_create_file("sso_hws_info", 0600,
+				    rvu->rvu_dbg.sso_hws, rvu,
+			&rvu_dbg_sso_hws_info_fops);
+	if (!pfile)
+		goto create_failed;
+
+	return;
+
+create_failed:
+	dev_err(dev, "Failed to create debugfs dir/file for SSO\n");
+	debugfs_remove_recursive(rvu->rvu_dbg.sso);
+}
+
 void rvu_dbg_init(struct rvu *rvu)
 {
 	struct device *dev = &rvu->pdev->dev;
@@ -1695,6 +2393,7 @@ void rvu_dbg_init(struct rvu *rvu)
 	rvu_dbg_nix_init(rvu);
 	rvu_dbg_cgx_init(rvu);
 	rvu_dbg_npc_init(rvu);
+	rvu_dbg_sso_init(rvu);
 
 	return;
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 12/16] octeontx2-af: Add TIM unit support.
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (10 preceding siblings ...)
  2019-11-20 17:48 ` [PATCH v3 11/16] octeontx2-af: add debugfs support for sso sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 13/16] octeontx2-af: verify ingress channel in MCAM entry sunil.kovvuri
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev
  Cc: davem, jakub.kicinski, Andrew Pinski, Pavan Nikhilesh, Sunil Goutham

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 16306 bytes --]

From: Andrew Pinski <apinski@marvell.com>

Add TIM (Timer) unit support to AF driver that involves initializing
and configuring TIM and its rings through mailbox. This block
helps software to schedule SSO work entries for a future time.

Signed-off-by: Andrew Pinski <apinski@marvell.com>
Co-developed-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/Makefile |   3 +-
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  80 +++++
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |  12 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   4 +
 .../net/ethernet/marvell/octeontx2/af/rvu_reg.h    |  12 +
 .../net/ethernet/marvell/octeontx2/af/rvu_tim.c    | 322 +++++++++++++++++++++
 6 files changed, 429 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_tim.c

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
index 5988d58..9c80d8c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile
+++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o
 
 octeontx2_mbox-y := mbox.o
 octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
-		  rvu_reg.o rvu_npc.o rvu_debugfs.o rvu_sso.o
+		  rvu_reg.o rvu_npc.o rvu_debugfs.o rvu_sso.o \
+		  rvu_tim.o
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index df35a05..5ba6b30 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -171,6 +171,12 @@ M(SSO_GRP_QOS_CONFIG,	0x608, sso_grp_qos_config, sso_grp_qos_cfg, msg_rsp)\
 M(SSO_GRP_GET_STATS,	0x609, sso_grp_get_stats, sso_info_req, sso_grp_stats)\
 M(SSO_HWS_GET_STATS,	0x610, sso_hws_get_stats, sso_info_req, sso_hws_stats)\
 /* TIM mbox IDs (range 0x800 - 0x9FF) */				\
+M(TIM_LF_ALLOC,		0x800, tim_lf_alloc,				\
+				tim_lf_alloc_req, tim_lf_alloc_rsp)	\
+M(TIM_LF_FREE,		0x801, tim_lf_free, tim_ring_req, msg_rsp)	\
+M(TIM_CONFIG_RING,	0x802, tim_config_ring, tim_config_req, msg_rsp)\
+M(TIM_ENABLE_RING,	0x803, tim_enable_ring, tim_ring_req, tim_enable_rsp)\
+M(TIM_DISABLE_RING,	0x804, tim_disable_ring, tim_ring_req, msg_rsp)	\
 /* CPT mbox IDs (range 0xA00 - 0xBFF) */				\
 /* NPC mbox IDs (range 0x6000 - 0x7FFF) */				\
 M(NPC_MCAM_ALLOC_ENTRY,	0x6000, npc_mcam_alloc_entry, npc_mcam_alloc_entry_req,\
@@ -978,4 +984,78 @@ struct npc_get_kex_cfg_rsp {
 	u8 mkex_pfl_name[MKEX_NAME_LEN];
 };
 
+/* TIM mailbox error codes
+ * Range 801 - 900.
+ */
+enum tim_af_status {
+	TIM_AF_NO_RINGS_LEFT			= -801,
+	TIM_AF_INVAL_NPA_PF_FUNC		= -802,
+	TIM_AF_INVAL_SSO_PF_FUNC		= -803,
+	TIM_AF_RING_STILL_RUNNING		= -804,
+	TIM_AF_LF_INVALID			= -805,
+	TIM_AF_CSIZE_NOT_ALIGNED		= -806,
+	TIM_AF_CSIZE_TOO_SMALL			= -807,
+	TIM_AF_CSIZE_TOO_BIG			= -808,
+	TIM_AF_INTERVAL_TOO_SMALL		= -809,
+	TIM_AF_INVALID_BIG_ENDIAN_VALUE		= -810,
+	TIM_AF_INVALID_CLOCK_SOURCE		= -811,
+	TIM_AF_GPIO_CLK_SRC_NOT_ENABLED		= -812,
+	TIM_AF_INVALID_BSIZE			= -813,
+	TIM_AF_INVALID_ENABLE_PERIODIC		= -814,
+	TIM_AF_INVALID_ENABLE_DONTFREE		= -815,
+	TIM_AF_ENA_DONTFRE_NSET_PERIODIC	= -816,
+	TIM_AF_RING_ALREADY_DISABLED		= -817,
+};
+
+enum tim_clk_srcs {
+	TIM_CLK_SRCS_TENNS	= 0,
+	TIM_CLK_SRCS_GPIO	= 1,
+	TIM_CLK_SRCS_GTI	= 2,
+	TIM_CLK_SRCS_PTP	= 3,
+	TIM_CLK_SRSC_INVALID,
+};
+
+enum tim_gpio_edge {
+	TIM_GPIO_NO_EDGE		= 0,
+	TIM_GPIO_LTOH_TRANS		= 1,
+	TIM_GPIO_HTOL_TRANS		= 2,
+	TIM_GPIO_BOTH_TRANS		= 3,
+	TIM_GPIO_INVALID,
+};
+
+struct tim_lf_alloc_req {
+	struct mbox_msghdr hdr;
+	u16	ring;
+	u16	npa_pf_func;
+	u16	sso_pf_func;
+};
+
+struct tim_ring_req {
+	struct mbox_msghdr hdr;
+	u16	ring;
+};
+
+struct tim_config_req {
+	struct mbox_msghdr hdr;
+	u16	ring;
+	u8	bigendian;
+	u8	clocksource;
+	u8	enableperiodic;
+	u8	enabledontfreebuffer;
+	u32	bucketsize;
+	u32	chunksize;
+	u32	interval;
+};
+
+struct tim_lf_alloc_rsp {
+	struct mbox_msghdr hdr;
+	u64 tenns_clk;
+};
+
+struct tim_enable_rsp {
+	struct mbox_msghdr hdr;
+	u64	timestarted;
+	u32	currentbucket;
+};
+
 #endif /* MBOX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index bbc0ab7..9812972 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -959,6 +959,10 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
 	if (err)
 		goto cgx_err;
 
+	err = rvu_tim_init(rvu);
+	if (err)
+		goto cgx_err;
+
 	return 0;
 
 cgx_err:
@@ -1327,12 +1331,12 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu,
 		goto exit;
 
 	/* Now attach the requested resources */
-	if (attach->npalf)
-		rvu_attach_block(rvu, pcifunc, BLKTYPE_NPA, 1);
-
 	if (attach->nixlf)
 		rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1);
 
+	if (attach->npalf)
+		rvu_attach_block(rvu, pcifunc, BLKTYPE_NPA, 1);
+
 	if (attach->sso) {
 		/* RVU func doesn't know which exact LF or slot is attached
 		 * to it, it always sees as slot 0,1,2. So for a 'modify'
@@ -1942,6 +1946,8 @@ static void rvu_blklf_teardown(struct rvu *rvu, u16 pcifunc, u8 blkaddr)
 			rvu_sso_lf_teardown(rvu, pcifunc, lf, slot);
 		else if (block->addr == BLKADDR_SSOW)
 			rvu_ssow_lf_teardown(rvu, pcifunc, lf, slot);
+		else if (block->addr == BLKADDR_TIM)
+			rvu_tim_lf_teardown(rvu, pcifunc, lf, slot);
 
 		err = rvu_lf_reset(rvu, block, lf);
 		if (err) {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index fa0f3ca..7fe1f1c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -524,6 +524,10 @@ void rvu_npc_get_mcam_counter_alloc_info(struct rvu *rvu, u16 pcifunc,
 					 int blkaddr, int *alloc_cnt,
 					 int *enable_cnt);
 
+/* TIM APIs */
+int rvu_tim_init(struct rvu *rvu);
+int rvu_tim_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot);
+
 #ifdef CONFIG_DEBUG_FS
 void rvu_dbg_init(struct rvu *rvu);
 void rvu_dbg_exit(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
index 8d319b6..99c6c7d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -596,6 +596,18 @@
 #define TIM_AF_RVU_LF_CFG_DEBUG		(0x30000)
 #define TIM_AF_BLK_RST			(0x10)
 #define TIM_AF_LF_RST			(0x20)
+#define TIM_AF_BLK_RST			(0x10)
+#define TIM_AF_RINGX_GMCTL(a)		(0x2000 | (a) << 3)
+#define TIM_AF_RINGX_CTL0(a)		(0x4000 | (a) << 3)
+#define TIM_AF_RINGX_CTL1(a)		(0x6000 | (a) << 3)
+#define TIM_AF_RINGX_CTL2(a)		(0x8000 | (a) << 3)
+#define TIM_AF_FLAGS_REG		(0x80)
+#define TIM_AF_FLAGS_REG_ENA_TIM	BIT_ULL(0)
+#define TIM_AF_RINGX_CTL1_ENA		BIT_ULL(47)
+#define TIM_AF_RINGX_CTL1_RCF_BUSY	BIT_ULL(50)
+
+#define TIM_AF_RING_GMCTL_SHIFT		3
+#define TIM_AF_RING_SSO_PF_FUNC_SHIFT	0
 
 /* CPT */
 #define CPT_AF_CONSTANTS0		(0x0000)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_tim.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_tim.c
new file mode 100644
index 0000000..af79729
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_tim.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell OcteonTx2 RVU Admin Function driver
+ *
+ * Copyright (C) 2019 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/types.h>
+#include <clocksource/arm_arch_timer.h>
+
+#include "rvu_struct.h"
+#include "rvu_reg.h"
+#include "rvu.h"
+
+#define TIM_CHUNKSIZE_MULTIPLE	(16)
+#define TIM_CHUNKSIZE_MIN	(TIM_CHUNKSIZE_MULTIPLE * 0x2)
+#define TIM_CHUNKSIZE_MAX	(TIM_CHUNKSIZE_MULTIPLE * 0x1FFF)
+
+static int rvu_tim_disable_lf(struct rvu *rvu, int lf, int blkaddr)
+{
+	u64 regval;
+
+	regval = rvu_read64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf));
+	if ((regval & TIM_AF_RINGX_CTL1_ENA) == 0)
+		return TIM_AF_RING_ALREADY_DISABLED;
+
+	/* Clear TIM_AF_RING(0..255)_CTL1[ENA]. */
+	regval = rvu_read64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf));
+	regval &= ~TIM_AF_RINGX_CTL1_ENA;
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf), regval);
+
+	/* Poll until the corresponding ring’s
+	 * TIM_AF_RING(0..255)_CTL1[RCF_BUSY] is clear.
+	 */
+	rvu_poll_reg(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf),
+		     TIM_AF_RINGX_CTL1_RCF_BUSY, true);
+	return 0;
+}
+
+int rvu_mbox_handler_tim_lf_alloc(struct rvu *rvu,
+				  struct tim_lf_alloc_req *req,
+				  struct tim_lf_alloc_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+	u64 regval;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, pcifunc);
+	if (blkaddr < 0)
+		return TIM_AF_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &rvu->hw->block[blkaddr], pcifunc, req->ring);
+	if (lf < 0)
+		return TIM_AF_LF_INVALID;
+
+	/* Check if requested 'TIMLF <=> NPALF' mapping is valid */
+	if (req->npa_pf_func) {
+		/* If default, use 'this' TIMLF's PFFUNC */
+		if (req->npa_pf_func == RVU_DEFAULT_PF_FUNC)
+			req->npa_pf_func = pcifunc;
+		if (!is_pffunc_map_valid(rvu, req->npa_pf_func, BLKTYPE_NPA))
+			return TIM_AF_INVAL_NPA_PF_FUNC;
+	}
+
+	/* Check if requested 'TIMLF <=> SSOLF' mapping is valid */
+	if (req->sso_pf_func) {
+		/* If default, use 'this' SSOLF's PFFUNC */
+		if (req->sso_pf_func == RVU_DEFAULT_PF_FUNC)
+			req->sso_pf_func = pcifunc;
+		if (!is_pffunc_map_valid(rvu, req->sso_pf_func, BLKTYPE_SSO))
+			return TIM_AF_INVAL_SSO_PF_FUNC;
+	}
+
+	regval = (((u64)req->npa_pf_func) << 16) |
+		 ((u64)req->sso_pf_func);
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_GMCTL(lf), regval);
+
+	rsp->tenns_clk = arch_timer_get_rate();
+
+	return 0;
+}
+
+int rvu_mbox_handler_tim_lf_free(struct rvu *rvu,
+				 struct tim_ring_req *req,
+				 struct msg_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, pcifunc);
+	if (blkaddr < 0)
+		return TIM_AF_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &rvu->hw->block[blkaddr], pcifunc, req->ring);
+	if (lf < 0)
+		return TIM_AF_LF_INVALID;
+
+	rvu_tim_lf_teardown(rvu, pcifunc, lf, req->ring);
+
+	return 0;
+}
+
+int rvu_mbox_handler_tim_config_ring(struct rvu *rvu,
+				     struct tim_config_req *req,
+				     struct msg_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+	u32 intervalmin;
+	u64 regval;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, pcifunc);
+	if (blkaddr < 0)
+		return TIM_AF_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &rvu->hw->block[blkaddr], pcifunc, req->ring);
+	if (lf < 0)
+		return TIM_AF_LF_INVALID;
+
+	/* Check the inputs. */
+	/* bigendian can only be 1 or 0. */
+	if (req->bigendian & ~1)
+		return TIM_AF_INVALID_BIG_ENDIAN_VALUE;
+
+	/* Check GPIO clock source has the GPIO edge set. */
+	if (req->clocksource == TIM_CLK_SRCS_GPIO) {
+		regval = rvu_read64(rvu, blkaddr, TIM_AF_FLAGS_REG);
+		if (((regval >> 5) & 0x3) == 0)
+			return TIM_AF_GPIO_CLK_SRC_NOT_ENABLED;
+	}
+
+	/* enableperiodic can only be 1 or 0. */
+	if (req->enableperiodic & ~1)
+		return TIM_AF_INVALID_ENABLE_PERIODIC;
+
+	/* enabledontfreebuffer can only be 1 or 0. */
+	if (req->enabledontfreebuffer & ~1)
+		return TIM_AF_INVALID_ENABLE_DONTFREE;
+
+	/* enabledontfreebuffer needs to be true if enableperiodic
+	 * is enabled.
+	 */
+	if (req->enableperiodic && !req->enabledontfreebuffer)
+		return TIM_AF_ENA_DONTFRE_NSET_PERIODIC;
+
+	/* bucketsize needs to between 2 and 2M (1<<20). */
+	if (req->bucketsize < 2 || req->bucketsize > 1 << 20)
+		return TIM_AF_INVALID_BSIZE;
+
+	if (req->chunksize % TIM_CHUNKSIZE_MULTIPLE)
+		return TIM_AF_CSIZE_NOT_ALIGNED;
+
+	if (req->chunksize < TIM_CHUNKSIZE_MIN)
+		return TIM_AF_CSIZE_TOO_SMALL;
+
+	if (req->chunksize > TIM_CHUNKSIZE_MAX)
+		return TIM_AF_CSIZE_TOO_BIG;
+
+	switch (req->clocksource) {
+	case TIM_CLK_SRCS_TENNS:
+		intervalmin = 256;
+		break;
+	case TIM_CLK_SRCS_GPIO:
+		intervalmin = 256;
+		break;
+	case TIM_CLK_SRCS_GTI:
+	case TIM_CLK_SRCS_PTP:
+		intervalmin = 300;
+		break;
+	default:
+		return TIM_AF_INVALID_CLOCK_SOURCE;
+	}
+
+	if (req->interval < intervalmin)
+		return TIM_AF_INTERVAL_TOO_SMALL;
+
+	/* CTL0 */
+	/* EXPIRE_OFFSET = 0 and is set correctly when enabling. */
+	regval = req->interval;
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_CTL0(lf), regval);
+
+	/* CTL1 */
+	regval = (((u64)req->bigendian) << 53) |
+		 (((u64)req->clocksource) << 51) |
+		 (1ull << 48) | /* LOCK_EN */
+		 (((u64)req->enableperiodic) << 45) |
+		 (((u64)(req->enableperiodic ^ 1)) << 44) | /* ENA_LDWB */
+		 (((u64)req->enabledontfreebuffer) << 43) |
+		 (u64)(req->bucketsize - 1);
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf), regval);
+
+	/* CTL2 */
+	regval = ((u64)req->chunksize / TIM_CHUNKSIZE_MULTIPLE) << 40;
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_CTL2(lf), regval);
+
+	return 0;
+}
+
+int rvu_mbox_handler_tim_enable_ring(struct rvu *rvu,
+				     struct tim_ring_req *req,
+				     struct tim_enable_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+	u64 regval;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, pcifunc);
+	if (blkaddr < 0)
+		return TIM_AF_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &rvu->hw->block[blkaddr], pcifunc, req->ring);
+	if (lf < 0)
+		return TIM_AF_LF_INVALID;
+
+	/* Error out if the ring is already running. */
+	regval = rvu_read64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf));
+	if (regval & TIM_AF_RINGX_CTL1_ENA)
+		return TIM_AF_RING_STILL_RUNNING;
+
+	/* Enable, the ring. */
+	regval = rvu_read64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf));
+	regval |= TIM_AF_RINGX_CTL1_ENA;
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_CTL1(lf), regval);
+
+	rsp->timestarted = arch_timer_read_counter();
+	rsp->currentbucket = (regval >> 20) & 0xfffff;
+
+	return 0;
+}
+
+int rvu_mbox_handler_tim_disable_ring(struct rvu *rvu,
+				      struct tim_ring_req *req,
+				      struct msg_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	int lf, blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, pcifunc);
+	if (blkaddr < 0)
+		return TIM_AF_LF_INVALID;
+
+	lf = rvu_get_lf(rvu, &rvu->hw->block[blkaddr], pcifunc, req->ring);
+	if (lf < 0)
+		return TIM_AF_LF_INVALID;
+
+	return rvu_tim_disable_lf(rvu, lf, blkaddr);
+}
+
+int rvu_tim_lf_teardown(struct rvu *rvu, u16 pcifunc, int lf, int slot)
+{
+	int blkaddr;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, pcifunc);
+	if (blkaddr < 0)
+		return TIM_AF_LF_INVALID;
+
+	/* Ensure TIM ring is disabled prior to clearing the mapping */
+	rvu_tim_disable_lf(rvu, lf, blkaddr);
+
+	rvu_write64(rvu, blkaddr, TIM_AF_RINGX_GMCTL(lf), 0);
+
+	return 0;
+}
+
+#define FOR_EACH_TIM_LF(lf)	\
+for (lf = 0; lf < hw->block[BLKTYPE_TIM].lf.max; lf++)
+
+int rvu_tim_init(struct rvu *rvu)
+{
+	struct rvu_hwinfo *hw = rvu->hw;
+	int lf, blkaddr;
+	u8 gpio_edge;
+	u64 regval;
+
+	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_TIM, 0);
+	if (blkaddr < 0)
+		return 0;
+
+	regval = rvu_read64(rvu, blkaddr, TIM_AF_FLAGS_REG);
+
+	/* Disable the TIM block, if not already disabled. */
+	if (regval & TIM_AF_FLAGS_REG_ENA_TIM) {
+		/* Disable each ring(lf). */
+		FOR_EACH_TIM_LF(lf) {
+			regval = rvu_read64(rvu, blkaddr,
+					    TIM_AF_RINGX_CTL1(lf));
+			if (!(regval & TIM_AF_RINGX_CTL1_ENA))
+				continue;
+
+			rvu_tim_disable_lf(rvu, lf, blkaddr);
+		}
+
+		/* Disable the TIM block. */
+		regval = rvu_read64(rvu, blkaddr, TIM_AF_FLAGS_REG);
+		regval &= ~TIM_AF_FLAGS_REG_ENA_TIM;
+		rvu_write64(rvu, blkaddr, TIM_AF_FLAGS_REG, regval);
+	}
+
+	/* Reset each LF. */
+	FOR_EACH_TIM_LF(lf) {
+		rvu_lf_reset(rvu, &hw->block[BLKTYPE_TIM], lf);
+	}
+
+	/* Reset the TIM block; getting a clean slate. */
+	rvu_write64(rvu, blkaddr, TIM_AF_BLK_RST, 0x1);
+	rvu_poll_reg(rvu, blkaddr, TIM_AF_BLK_RST, BIT_ULL(63), true);
+
+	gpio_edge = TIM_GPIO_NO_EDGE;
+
+	/* Enable TIM block. */
+	regval = (((u64)gpio_edge) << 6) |
+		 BIT_ULL(2) | /* RESET */
+		 BIT_ULL(0); /* ENA_TIM */
+	rvu_write64(rvu, blkaddr, TIM_AF_FLAGS_REG, regval);
+
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 13/16] octeontx2-af: verify ingress channel in MCAM entry
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (11 preceding siblings ...)
  2019-11-20 17:48 ` [PATCH v3 12/16] octeontx2-af: Add TIM unit support sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 14/16] octeontx2-af: NPC Tx parsed data key extraction profile sunil.kovvuri
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Subbaraya Sundeep, Sunil Goutham

From: Subbaraya Sundeep <sbhatta@marvell.com>

A RVU PF and it's VFs share a CGX port and can only take pkts
received at that port. While installing MCAM entries for forwarding
packets it should be made sure that this is not violated. Hence
before installing MCAM entry sent by PF/VF the ingress channel
in the match key needs to be verified.

This patch does this channel verification.

Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/rvu.c    |  4 +-
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |  1 +
 .../net/ethernet/marvell/octeontx2/af/rvu_npc.c    | 47 ++++++++++++++++++++++
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index 9812972..f561dfa 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -2479,7 +2479,7 @@ static void rvu_enable_afvf_intr(struct rvu *rvu)
 
 #define PCI_DEVID_OCTEONTX2_LBK 0xA061
 
-static int lbk_get_num_chans(void)
+int rvu_get_num_lbk_chans(void)
 {
 	struct pci_dev *pdev;
 	void __iomem *base;
@@ -2514,7 +2514,7 @@ static int rvu_enable_sriov(struct rvu *rvu)
 		return 0;
 	}
 
-	chans = lbk_get_num_chans();
+	chans = rvu_get_num_lbk_chans();
 	if (chans < 0)
 		return chans;
 
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 7fe1f1c..a90af41 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -427,6 +427,7 @@ int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot);
 int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf);
 int rvu_get_blkaddr(struct rvu *rvu, int blktype, u16 pcifunc);
 int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero);
+int rvu_get_num_lbk_chans(void);
 
 /* RVU HW reg validation */
 enum regmap_block {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 40e431d..cf61796 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -28,11 +28,40 @@
 
 #define NPC_PARSE_RESULT_DMAC_OFFSET	8
 
+#define NPC_KEX_CHAN_MASK	0xFFFULL
+
 static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
 				      int blkaddr, u16 pcifunc);
 static void npc_mcam_free_all_counters(struct rvu *rvu, struct npc_mcam *mcam,
 				       u16 pcifunc);
 
+static int npc_mcam_verify_channel(struct rvu *rvu, u16 pcifunc,
+				   u8 intf, u16 channel)
+{
+	int pf = rvu_get_pf(pcifunc);
+	u8 cgx_id, lmac_id;
+	int base = 0, end;
+
+	if (intf == NIX_INTF_TX)
+		return 0;
+
+	if (is_afvf(pcifunc)) {
+		end = rvu_get_num_lbk_chans();
+		if (end < 0)
+			return -EINVAL;
+	} else {
+		rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+		base = NIX_CHAN_CGX_LMAC_CHX(cgx_id, lmac_id, 0x0);
+		/* CGX mapped functions has maximum of 16 channels */
+		end = NIX_CHAN_CGX_LMAC_CHX(cgx_id, lmac_id, 0xF);
+	}
+
+	if (channel < base || channel > end)
+		return -EINVAL;
+
+	return 0;
+}
+
 void rvu_npc_set_pkind(struct rvu *rvu, int pkind, struct rvu_pfvf *pfvf)
 {
 	int blkaddr;
@@ -1808,12 +1837,17 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu,
 {
 	struct npc_mcam *mcam = &rvu->hw->mcam;
 	u16 pcifunc = req->hdr.pcifunc;
+	u16 channel, chan_mask;
 	int blkaddr, rc;
 
 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
 	if (blkaddr < 0)
 		return NPC_MCAM_INVALID_REQ;
 
+	chan_mask = req->entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK;
+	channel = req->entry_data.kw[0] & NPC_KEX_CHAN_MASK;
+	channel &= chan_mask;
+
 	mutex_lock(&mcam->lock);
 	rc = npc_mcam_verify_entry(mcam, pcifunc, req->entry);
 	if (rc)
@@ -1830,6 +1864,11 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu,
 		goto exit;
 	}
 
+	if (npc_mcam_verify_channel(rvu, pcifunc, req->intf, channel)) {
+		rc = NPC_MCAM_INVALID_REQ;
+		goto exit;
+	}
+
 	npc_config_mcam_entry(rvu, mcam, blkaddr, req->entry, req->intf,
 			      &req->entry_data, req->enable_entry);
 
@@ -2165,6 +2204,7 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu,
 	struct npc_mcam *mcam = &rvu->hw->mcam;
 	u16 entry = NPC_MCAM_ENTRY_INVALID;
 	u16 cntr = NPC_MCAM_ENTRY_INVALID;
+	u16 channel, chan_mask;
 	int blkaddr, rc;
 
 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
@@ -2174,6 +2214,13 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu,
 	if (req->intf != NIX_INTF_RX && req->intf != NIX_INTF_TX)
 		return NPC_MCAM_INVALID_REQ;
 
+	chan_mask = req->entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK;
+	channel = req->entry_data.kw[0] & NPC_KEX_CHAN_MASK;
+	channel &= chan_mask;
+
+	if (npc_mcam_verify_channel(rvu, req->hdr.pcifunc, req->intf, channel))
+		return NPC_MCAM_INVALID_REQ;
+
 	/* Try to allocate a MCAM entry */
 	entry_req.hdr.pcifunc = req->hdr.pcifunc;
 	entry_req.contig = true;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 14/16] octeontx2-af: NPC Tx parsed data key extraction profile
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (12 preceding siblings ...)
  2019-11-20 17:48 ` [PATCH v3 13/16] octeontx2-af: verify ingress channel in MCAM entry sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 15/16] octeontx2-af: Support to get CGX link info like current speed, fec etc sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview sunil.kovvuri
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev
  Cc: davem, jakub.kicinski, Kiran Kumar K, Subbaraya Sundeep, Sunil Goutham

From: Kiran Kumar K <kirankumark@marvell.com>

This patch enables Tx side parsing by configuring the pkind 63 in
tx_parse_cfg and add default ldata profile for tx.

Unlike Ingress parsing where CHAN field represents the port where the
pkt is received, for a transmitted pkt, NIX HW adds a header which will
have PF_FUNC, SQ idx information, which if extracted to NPC parse key
can be used to do egress side filtering/forwarding.

This patch configures HW to extract this header info into parse key.

Signed-off-by: Kiran Kumar K <kirankumark@marvell.com>
Signed-off-by: Subbaraya Sundeep <sbhatta@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 .../net/ethernet/marvell/octeontx2/af/rvu_nix.c    |   6 +
 .../net/ethernet/marvell/octeontx2/af/rvu_npc.c    | 235 ++++++++++++++++-----
 2 files changed, 191 insertions(+), 50 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index f1201e0..07f0f4b 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -58,6 +58,8 @@ enum nix_makr_fmt_indexes {
 	NIX_MARK_CFG_MAX,
 };
 
+#define NIX_TX_PKIND   63ULL
+
 /* For now considering MC resources needed for broadcast
  * pkt replication only. i.e 256 HWVFs + 12 PFs.
  */
@@ -1110,6 +1112,10 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
 	/* Config Rx pkt length, csum checks and apad  enable / disable */
 	rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
 
+	/* Configure pkind for TX parse config, 63 from npc_profile */
+	cfg = NIX_TX_PKIND;
+	rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+
 	intf = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX;
 	err = nix_interface_init(rvu, pcifunc, intf, nixlf);
 	if (err)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index cf61796..d1aab99 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -29,12 +29,33 @@
 #define NPC_PARSE_RESULT_DMAC_OFFSET	8
 
 #define NPC_KEX_CHAN_MASK	0xFFFULL
+#define NPC_KEX_PF_FUNC_MASK    0xFFFFULL
 
 static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
 				      int blkaddr, u16 pcifunc);
 static void npc_mcam_free_all_counters(struct rvu *rvu, struct npc_mcam *mcam,
 				       u16 pcifunc);
 
+static int npc_mcam_verify_pf_func(struct rvu *rvu,
+				   struct mcam_entry *entry_data,
+				   u8 intf, u16 pcifunc)
+{
+	u16 pf_func, pf_func_mask;
+
+	if (intf == NIX_INTF_RX)
+		return 0;
+
+	pf_func_mask = (entry_data->kw_mask[0] >> 32) &
+		NPC_KEX_PF_FUNC_MASK;
+	pf_func = (entry_data->kw[0] >> 32) & NPC_KEX_PF_FUNC_MASK;
+
+	pf_func = htons(pf_func);
+	if (pf_func_mask != NPC_KEX_PF_FUNC_MASK || pf_func != pcifunc)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int npc_mcam_verify_channel(struct rvu *rvu, u16 pcifunc,
 				   u8 intf, u16 channel)
 {
@@ -720,37 +741,78 @@ void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
 			(((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \
 			 ((flags_ena) << 6) | ((key_ofs) & 0x3F))
 
-static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
+static void npc_config_tx_ldata_extract(struct rvu *rvu, int blkaddr)
 {
-	struct npc_mcam *mcam = &rvu->hw->mcam;
-	int lid, ltype;
-	int lid_count;
 	u64 cfg;
 
-	cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST);
-	lid_count = (cfg >> 4) & 0xF;
+	/* Default TX MCAM KEX profile */
+	/* Layer A: Ethernet: */
 
-	/* First clear any existing config i.e
-	 * disable LDATA and FLAGS extraction.
-	 */
-	for (lid = 0; lid < lid_count; lid++) {
-		for (ltype = 0; ltype < 16; ltype++) {
-			SET_KEX_LD(NIX_INTF_RX, lid, ltype, 0, 0ULL);
-			SET_KEX_LD(NIX_INTF_RX, lid, ltype, 1, 0ULL);
-			SET_KEX_LD(NIX_INTF_TX, lid, ltype, 0, 0ULL);
-			SET_KEX_LD(NIX_INTF_TX, lid, ltype, 1, 0ULL);
+	/* PF_FUNC: 2B , KW0 [47:32] */
+	cfg = KEX_LD_CFG(0x01, 0x0, 0x1, 0x0, 0x4);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, 0, cfg);
 
-			SET_KEX_LDFLAGS(NIX_INTF_RX, 0, ltype, 0ULL);
-			SET_KEX_LDFLAGS(NIX_INTF_RX, 1, ltype, 0ULL);
-			SET_KEX_LDFLAGS(NIX_INTF_TX, 0, ltype, 0ULL);
-			SET_KEX_LDFLAGS(NIX_INTF_TX, 1, ltype, 0ULL);
-		}
-	}
+	/* PF_FUNC incase of higig2 */
+	cfg = KEX_LD_CFG(0x01, 0x0, 0x1, 0x0, 0x4);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, 0,
+		   cfg);
 
-	if (mcam->keysize != NPC_MCAM_KEY_X2)
-		return;
+	/* Layer B: Single VLAN (CTAG) */
+	/* CTAG VLAN[2..3] KW0[63:48] */
+	cfg = KEX_LD_CFG(0x01, 0x2, 0x1, 0x0, 0x6);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LB, NPC_LT_LB_CTAG, 0, cfg);
+
+	/* CTAG VLAN[2..3] KW1[15:0] */
+	cfg = KEX_LD_CFG(0x01, 0x4, 0x1, 0x0, 0x8);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LB, NPC_LT_LB_CTAG, 1, cfg);
+
+	/* Layer B: Stacked VLAN (STAG|QinQ) */
+	/* Outer VLAN: 2 bytes, KW0[63:48] */
+	cfg = KEX_LD_CFG(0x01, 0x2, 0x1, 0x0, 0x6);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, cfg);
+
+	/* Outer VLAN: 2 Bytes, KW1[15:0] */
+	cfg = KEX_LD_CFG(0x01, 0x8, 0x1, 0x0, 0x8);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 1, cfg);
+
+	/* DMAC: 6 bytes, KW1[63:16] */
+	cfg = KEX_LD_CFG(0x05, 0x8, 0x1, 0x0, 0xa);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, 1, cfg);
+
+	/* clasification in higig2 header */
+	cfg = KEX_LD_CFG(0x01, 0x10, 0x1, 0x0, 0xa);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, 1,
+		   cfg);
+
+	/* Layer C: IPv4 */
+	/* SIP+DIP: 8 bytes, KW2[63:0] */
+	cfg = KEX_LD_CFG(0x07, 0xc, 0x1, 0x0, 0x10);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LC, NPC_LT_LC_IP, 0, cfg);
+
+	/* Layer D:UDP */
+	/* SPORT: 2 bytes, KW3[15:0] */
+	cfg = KEX_LD_CFG(0x1, 0x0, 0x1, 0x0, 0x18);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LD, NPC_LT_LD_UDP, 0, cfg);
+
+	/* DPORT: 2 bytes, KW3[31:16] */
+	cfg = KEX_LD_CFG(0x1, 0x2, 0x1, 0x0, 0x1a);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LD, NPC_LT_LD_UDP, 1, cfg);
+
+	/* Layer D:TCP */
+	/* SPORT: 2 bytes, KW3[15:0] */
+	cfg = KEX_LD_CFG(0x1, 0x0, 0x1, 0x0, 0x18);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LD, NPC_LT_LD_TCP, 0, cfg);
+
+	/* DPORT: 2 bytes, KW3[31:16] */
+	cfg = KEX_LD_CFG(0x1, 0x2, 0x1, 0x0, 0x1a);
+	SET_KEX_LD(NIX_INTF_TX, NPC_LID_LD, NPC_LT_LD_TCP, 1, cfg);
+}
+
+static void npc_config_rx_ldata_extract(struct rvu *rvu, int blkaddr)
+{
+	u64 cfg;
 
-	/* Default MCAM KEX profile */
+	/* Default RX MCAM KEX profile */
 	/* Layer A: Ethernet: */
 
 	/* DMAC: 6 bytes, KW1[47:0] */
@@ -761,21 +823,34 @@ static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
 	cfg = KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x4);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LA, NPC_LT_LA_ETHER, 1, cfg);
 
+	/* Classification in higig2 header */
+	cfg = KEX_LD_CFG(0x01, 0x8, 0x1, 0x0, NPC_PARSE_RESULT_DMAC_OFFSET);
+	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, 0, cfg);
+
+	/* Vid in higig2 header */
+	cfg = KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, NPC_PARSE_RESULT_DMAC_OFFSET + 2);
+	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, 1, cfg);
+
 	/* Layer B: Single VLAN (CTAG) */
 	/* CTAG VLAN[2..3] + Ethertype, 4 bytes, KW0[63:32] */
-	cfg = KEX_LD_CFG(0x03, 0x0, 0x1, 0x0, 0x4);
+	cfg = KEX_LD_CFG(0x03, 0x2, 0x1, 0x0, 0x4);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LB, NPC_LT_LB_CTAG, 0, cfg);
 
 	/* Layer B: Stacked VLAN (STAG|QinQ) */
-	/* CTAG VLAN[2..3] + Ethertype, 4 bytes, KW0[63:32] */
-	cfg = KEX_LD_CFG(0x03, 0x4, 0x1, 0x0, 0x4);
+	/* Outer VLAN: 2 bytes, KW0[63:48] */
+	cfg = KEX_LD_CFG(0x01, 0x2, 0x1, 0x0, 0x6);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, cfg);
 
+	/* Ethertype: 2 bytes, KW0[47:32] */
+	cfg = KEX_LD_CFG(0x01, 0x8, 0x1, 0x0, 0x4);
+	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 1, cfg);
+
 	/* Layer C: IPv4 */
 	/* SIP+DIP: 8 bytes, KW2[63:0] */
 	cfg = KEX_LD_CFG(0x07, 0xc, 0x1, 0x0, 0x10);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LC, NPC_LT_LC_IP, 0, cfg);
 	/* TOS: 1 byte, KW1[63:56] */
+
 	cfg = KEX_LD_CFG(0x0, 0x1, 0x1, 0x0, 0xf);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LC, NPC_LT_LC_IP, 1, cfg);
 
@@ -783,6 +858,7 @@ static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
 	/* SPORT: 2 bytes, KW3[15:0] */
 	cfg = KEX_LD_CFG(0x1, 0x0, 0x1, 0x0, 0x18);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LD, NPC_LT_LD_UDP, 0, cfg);
+
 	/* DPORT: 2 bytes, KW3[31:16] */
 	cfg = KEX_LD_CFG(0x1, 0x2, 0x1, 0x0, 0x1a);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LD, NPC_LT_LD_UDP, 1, cfg);
@@ -791,11 +867,49 @@ static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
 	/* SPORT: 2 bytes, KW3[15:0] */
 	cfg = KEX_LD_CFG(0x1, 0x0, 0x1, 0x0, 0x18);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LD, NPC_LT_LD_TCP, 0, cfg);
+
 	/* DPORT: 2 bytes, KW3[31:16] */
 	cfg = KEX_LD_CFG(0x1, 0x2, 0x1, 0x0, 0x1a);
 	SET_KEX_LD(NIX_INTF_RX, NPC_LID_LD, NPC_LT_LD_TCP, 1, cfg);
 }
 
+static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr)
+{
+	int lid, ltype;
+	int lid_count;
+	u64 cfg;
+
+	cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST);
+	lid_count = (cfg >> 4) & 0xF;
+
+	/* First clear any existing config i.e
+	 * disable LDATA and FLAGS extraction.
+	 */
+	for (lid = 0; lid < lid_count; lid++) {
+		for (ltype = 0; ltype < 16; ltype++) {
+			SET_KEX_LD(NIX_INTF_RX, lid, ltype, 0, 0ULL);
+			SET_KEX_LD(NIX_INTF_RX, lid, ltype, 1, 0ULL);
+			SET_KEX_LD(NIX_INTF_TX, lid, ltype, 0, 0ULL);
+			SET_KEX_LD(NIX_INTF_TX, lid, ltype, 1, 0ULL);
+
+			SET_KEX_LDFLAGS(NIX_INTF_RX, 0, ltype, 0ULL);
+			SET_KEX_LDFLAGS(NIX_INTF_RX, 1, ltype, 0ULL);
+			SET_KEX_LDFLAGS(NIX_INTF_TX, 0, ltype, 0ULL);
+			SET_KEX_LDFLAGS(NIX_INTF_TX, 1, ltype, 0ULL);
+		}
+	}
+
+	cfg = (rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(0)) >> 32) & 0x07;
+	/* Default profile works with key size NPC_MCAM_KEY_X2 */
+	if (cfg != NPC_MCAM_KEY_X2)
+		return;
+
+	/* Config RX ldata extract */
+	npc_config_rx_ldata_extract(rvu, blkaddr);
+	/* Config TX ldata extract */
+	npc_config_tx_ldata_extract(rvu, blkaddr);
+}
+
 static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
 				     struct npc_mcam_kex *mkex)
 {
@@ -837,6 +951,20 @@ static void npc_program_mkex_profile(struct rvu *rvu, int blkaddr,
 	}
 }
 
+static bool is_parse_nibble_config_valid(struct rvu *rvu,
+					 struct npc_mcam_kex *mcam_kex)
+{
+	if (!is_rvu_96xx_B0(rvu))
+		return true;
+
+	/* Due to a HW issue in above silicon versions, parse nibble enable
+	 * configuration has to be identical for both Rx and Tx interfaces.
+	 */
+	if (mcam_kex->keyx_cfg[NIX_INTF_RX] != mcam_kex->keyx_cfg[NIX_INTF_TX])
+		return false;
+	return true;
+}
+
 /* strtoull of "mkexprof" with base:36 */
 #define MKEX_SIGN      0x19bbfdbd15f
 #define MKEX_END_SIGN  0xdeadbeef
@@ -854,8 +982,10 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr)
 	if (!strncmp(mkex_profile, "default", MKEX_NAME_LEN))
 		goto load_default;
 
-	if (cgx_get_mkex_prfl_info(&prfl_addr, &prfl_sz))
+	if (!rvu->fwdata)
 		goto load_default;
+	prfl_addr = rvu->fwdata->mcam_addr;
+	prfl_sz = rvu->fwdata->mcam_sz;
 
 	if (!prfl_addr || !prfl_sz)
 		goto load_default;
@@ -870,13 +1000,7 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr)
 		/* 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/B0 pass silicon,
-			 * parse nibble enable configuration has to be
-			 * identical for both Rx and Tx interfaces.
-			 */
-			if (is_rvu_96xx_B0(rvu) &&
-			    mcam_kex->keyx_cfg[NIX_INTF_RX] !=
-			    mcam_kex->keyx_cfg[NIX_INTF_TX])
+			if (!is_parse_nibble_config_valid(rvu, mcam_kex))
 				goto load_default;
 
 			/* Program selected mkex profile */
@@ -1219,36 +1343,36 @@ int rvu_npc_init(struct rvu *rvu)
 
 	/* Enable below for Rx pkts.
 	 * - Outer IPv4 header checksum validation.
-	 * - Detect outer L2 broadcast address and set NPC_RESULT_S[L2M].
+	 * - Detect outer L2 broadcast address and set NPC_RESULT_S[L2B].
+	 * - Detect outer L2 multicast address and set NPC_RESULT_S[L2M].
 	 * - Inner IPv4 header checksum validation.
 	 * - Set non zero checksum error code value
 	 */
 	rvu_write64(rvu, blkaddr, NPC_AF_PCK_CFG,
 		    rvu_read64(rvu, blkaddr, NPC_AF_PCK_CFG) |
-		    BIT_ULL(32) | BIT_ULL(24) | BIT_ULL(6) |
-		    BIT_ULL(2) | BIT_ULL(1));
+		    ((u64)NPC_EC_OIP4_CSUM << 32) | (NPC_EC_IIP4_CSUM << 24) |
+		    BIT_ULL(7) | BIT_ULL(6) | BIT_ULL(2) | BIT_ULL(1));
 
 	/* Set RX and TX side MCAM search key size.
-	 * LA..LD (ltype only) + Channel
+	 * LA..LE (ltype only) + Channel
 	 */
-	nibble_ena = 0x49247;
+	nibble_ena = 0x249207;
 	rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX),
 			((keyz & 0x3) << 32) | nibble_ena);
-	/* Due to an errata (35786) in A0 pass silicon, parse nibble enable
-	 * configuration has to be identical for both Rx and Tx interfaces.
-	 */
+
+	/* Extract Ltypes LID_LA to LID_LE */
 	if (!is_rvu_96xx_B0(rvu))
-		nibble_ena = (1ULL << 19) - 1;
+		nibble_ena = 0x249200;
 	rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX),
 			((keyz & 0x3) << 32) | nibble_ena);
 
+	/* Configure MKEX profile */
+	npc_load_mkex_profile(rvu, blkaddr);
+
 	err = npc_mcam_rsrcs_init(rvu, blkaddr);
 	if (err)
 		return err;
 
-	/* 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.
 	 */
@@ -1262,7 +1386,6 @@ int rvu_npc_init(struct rvu *rvu)
 		    NIX_RX_ACTIONOP_DROP);
 	rvu_write64(rvu, blkaddr, NPC_AF_INTFX_MISS_STAT_ACT(NIX_INTF_RX),
 		    BIT_ULL(9) | mcam->rx_miss_act_cntr);
-
 	return 0;
 }
 
@@ -1869,6 +1992,12 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu,
 		goto exit;
 	}
 
+	if (npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf,
+				    pcifunc)) {
+		rc = NPC_MCAM_INVALID_REQ;
+		goto exit;
+	}
+
 	npc_config_mcam_entry(rvu, mcam, blkaddr, req->entry, req->intf,
 			      &req->entry_data, req->enable_entry);
 
@@ -2091,10 +2220,11 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu,
 		index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry);
 		if (index >= mcam->bmap_entries)
 			break;
+		entry = index + 1;
+
 		if (mcam->entry2cntr_map[index] != req->cntr)
 			continue;
 
-		entry = index + 1;
 		npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
 					      index, req->cntr);
 	}
@@ -2137,10 +2267,11 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu,
 		index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry);
 		if (index >= mcam->bmap_entries)
 			break;
+		entry = index + 1;
+
 		if (mcam->entry2cntr_map[index] != req->cntr)
 			continue;
 
-		entry = index + 1;
 		npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
 					      index, req->cntr);
 	}
@@ -2221,6 +2352,10 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu,
 	if (npc_mcam_verify_channel(rvu, req->hdr.pcifunc, req->intf, channel))
 		return NPC_MCAM_INVALID_REQ;
 
+	if (npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf,
+				    req->hdr.pcifunc))
+		return NPC_MCAM_INVALID_REQ;
+
 	/* Try to allocate a MCAM entry */
 	entry_req.hdr.pcifunc = req->hdr.pcifunc;
 	entry_req.contig = true;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 15/16] octeontx2-af: Support to get CGX link info like current speed, fec etc
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (13 preceding siblings ...)
  2019-11-20 17:48 ` [PATCH v3 14/16] octeontx2-af: NPC Tx parsed data key extraction profile sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-20 17:48 ` [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview sunil.kovvuri
  15 siblings, 0 replies; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev
  Cc: davem, jakub.kicinski, Christina Jacob, Linu Cherian, Sunil Goutham

From: Christina Jacob <cjacob@marvell.com>

- Implements CGX_FW_DATA_GET command to get the cgx link info shared
  from atf.
- Implement CGX_FEC_SET mailbox message to set current FEC value.
- Update the link status structre in cgx with additional information
  such as the port type, current fec etc.
- Upon request, fetch FEC corrected and uncorrected block counters
  for the mapped CGX LMAC.
- If present get phy's EEPROM data as response to ethtool command.

Signed-off-by: Christina Jacob <cjacob@marvell.com>
Signed-off-by: Linu Cherian <lcherian@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 drivers/net/ethernet/marvell/octeontx2/af/cgx.c    | 310 +++++++++++++++++++--
 drivers/net/ethernet/marvell/octeontx2/af/cgx.h    |  11 +-
 .../net/ethernet/marvell/octeontx2/af/cgx_fw_if.h  |  72 ++++-
 drivers/net/ethernet/marvell/octeontx2/af/mbox.h   |  76 +++++
 drivers/net/ethernet/marvell/octeontx2/af/rvu.h    |   4 +
 .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c    |  99 ++++++-
 6 files changed, 542 insertions(+), 30 deletions(-)

diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index 6379010..52293b5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -14,12 +14,14 @@
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/of.h>
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 
 #include "cgx.h"
+#include "rvu.h"
 
 #define DRV_NAME	"octeontx2-cgx"
 #define DRV_STRING      "Marvell OcteonTX2 CGX/MAC Driver"
@@ -326,6 +328,11 @@ int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat)
 
 	if (!cgx || lmac_id >= cgx->lmac_count)
 		return -ENODEV;
+#define CGX_RX_STAT_GLOBAL_INDEX	9
+	/* pass lmac as 0 for CGX_CMR_RX_STAT9-12 */
+	if (idx >= CGX_RX_STAT_GLOBAL_INDEX)
+		lmac_id = 0;
+
 	*rx_stat =  cgx_read(cgx, lmac_id, CGXX_CMRX_RX_STAT0 + (idx * 8));
 	return 0;
 }
@@ -342,6 +349,58 @@ int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat)
 }
 EXPORT_SYMBOL(cgx_get_tx_stats);
 
+static int cgx_set_fec_stats_count(struct cgx_link_user_info *linfo)
+{
+	if (linfo->fec) {
+		switch (linfo->lmac_type_id) {
+		case LMAC_MODE_SGMII:
+		case LMAC_MODE_XAUI:
+		case LMAC_MODE_RXAUI:
+		case LMAC_MODE_QSGMII:
+			return 0;
+		case LMAC_MODE_10G_R:
+		case LMAC_MODE_25G_R:
+		case LMAC_MODE_100G_R:
+		case LMAC_MODE_USXGMII:
+			return 1;
+		case LMAC_MODE_40G_R:
+			return 4;
+		case LMAC_MODE_50G_R:
+			if (linfo->fec == OTX2_FEC_BASER)
+				return 2;
+			else
+				return 1;
+		}
+	}
+	return 0;
+}
+
+int cgx_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp)
+{
+	int stats, fec_stats_count = 0;
+	int corr_reg, uncorr_reg;
+	struct cgx *cgx = cgxd;
+
+	if (!cgx || lmac_id >= cgx->lmac_count)
+		return -ENODEV;
+	fec_stats_count =
+		cgx_set_fec_stats_count(&cgx->lmac_idmap[lmac_id]->link_info);
+	if (cgx->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_BASER) {
+		corr_reg = CGXX_SPUX_LNX_FEC_CORR_BLOCKS;
+		uncorr_reg = CGXX_SPUX_LNX_FEC_UNCORR_BLOCKS;
+	} else {
+		corr_reg = CGXX_SPUX_RSFEC_CORR;
+		uncorr_reg = CGXX_SPUX_RSFEC_UNCORR;
+	}
+	for (stats = 0; stats < fec_stats_count; stats++) {
+		rsp->fec_corr_blks +=
+			cgx_read(cgx, lmac_id, corr_reg + (stats * 8));
+		rsp->fec_uncorr_blks +=
+			cgx_read(cgx, lmac_id, uncorr_reg + (stats * 8));
+	}
+	return 0;
+}
+
 int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable)
 {
 	struct cgx *cgx = cgxd;
@@ -352,9 +411,9 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable)
 
 	cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG);
 	if (enable)
-		cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN;
+		cfg |= DATA_PKT_RX_EN | DATA_PKT_TX_EN;
 	else
-		cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN);
+		cfg &= ~(DATA_PKT_RX_EN | DATA_PKT_TX_EN);
 	cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg);
 	return 0;
 }
@@ -534,8 +593,8 @@ static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac)
 	return err;
 }
 
-static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp,
-				      struct cgx *cgx, int lmac_id)
+static int cgx_fwi_cmd_generic(u64 req, u64 *resp,
+			       struct cgx *cgx, int lmac_id)
 {
 	struct lmac *lmac;
 	int err;
@@ -557,7 +616,7 @@ static inline int cgx_fwi_cmd_generic(u64 req, u64 *resp,
 	return err;
 }
 
-static inline void cgx_link_usertable_init(void)
+static void cgx_link_usertable_init(void)
 {
 	cgx_speed_mbps[CGX_LINK_NONE] = 0;
 	cgx_speed_mbps[CGX_LINK_10M] = 10;
@@ -570,6 +629,7 @@ static inline void cgx_link_usertable_init(void)
 	cgx_speed_mbps[CGX_LINK_25G] = 25000;
 	cgx_speed_mbps[CGX_LINK_40G] = 40000;
 	cgx_speed_mbps[CGX_LINK_50G] = 50000;
+	cgx_speed_mbps[CGX_LINK_80G] = 80000;
 	cgx_speed_mbps[CGX_LINK_100G] = 100000;
 
 	cgx_lmactype_string[LMAC_MODE_SGMII] = "SGMII";
@@ -584,23 +644,175 @@ static inline void cgx_link_usertable_init(void)
 	cgx_lmactype_string[LMAC_MODE_USXGMII] = "USXGMII";
 }
 
-static inline void link_status_user_format(u64 lstat,
-					   struct cgx_link_user_info *linfo,
-					   struct cgx *cgx, u8 lmac_id)
+static int cgx_link_usertable_index_map(int speed)
+{
+	switch (speed) {
+	case SPEED_10:
+		return CGX_LINK_10M;
+	case SPEED_100:
+		return CGX_LINK_100M;
+	case SPEED_1000:
+		return CGX_LINK_1G;
+	case SPEED_2500:
+		return CGX_LINK_2HG;
+	case SPEED_5000:
+		return CGX_LINK_5G;
+	case SPEED_10000:
+		return CGX_LINK_10G;
+	case SPEED_20000:
+		return CGX_LINK_20G;
+	case SPEED_25000:
+		return CGX_LINK_25G;
+	case SPEED_40000:
+		return CGX_LINK_40G;
+	case SPEED_50000:
+		return CGX_LINK_50G;
+	case 80000:
+		return CGX_LINK_80G;
+	case SPEED_100000:
+		return CGX_LINK_100G;
+	case SPEED_UNKNOWN:
+		return CGX_LINK_NONE;
+	}
+	return CGX_LINK_NONE;
+}
+
+static void set_mod_args(struct cgx_set_link_mode_args *args,
+			 u32 speed, u8 duplex, u8 autoneg, u64 mode)
+{
+	/* firmware requires this value in the reverse format */
+	args->duplex = duplex;
+	args->speed = speed;
+	args->mode = mode;
+	args->an = autoneg;
+	args->ports = 0;
+}
+
+static void otx2_map_ethtool_link_modes(u64 bitmask,
+					struct cgx_set_link_mode_args *args)
+{
+	switch (bitmask) {
+	case BIT_ULL(ETHTOOL_LINK_MODE_10baseT_Half_BIT):
+		set_mod_args(args, 10, 1, 1, BIT_ULL(CGX_MODE_SGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10baseT_Full_BIT):
+		set_mod_args(args, 10, 0, 1, BIT_ULL(CGX_MODE_SGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_100baseT_Half_BIT):
+		set_mod_args(args, 100, 1, 1, BIT_ULL(CGX_MODE_SGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_100baseT_Full_BIT):
+		set_mod_args(args, 100, 0, 1, BIT_ULL(CGX_MODE_SGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_1000baseT_Half_BIT):
+		set_mod_args(args, 1000, 1, 1, BIT_ULL(CGX_MODE_SGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_1000baseT_Full_BIT):
+		set_mod_args(args, 1000, 0, 1, BIT_ULL(CGX_MODE_SGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_1000baseX_Full_BIT):
+		set_mod_args(args, 1000, 0, 0, BIT_ULL(CGX_MODE_1000_BASEX));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseT_Full_BIT):
+		set_mod_args(args, 1000, 0, 1, BIT_ULL(CGX_MODE_QSGMII));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT):
+		set_mod_args(args, 10000, 0, 0, BIT_ULL(CGX_MODE_10G_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT):
+		set_mod_args(args, 10000, 0, 0, BIT_ULL(CGX_MODE_10G_C2M));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT):
+		set_mod_args(args, 10000, 0, 1, BIT_ULL(CGX_MODE_10G_KR));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT):
+		set_mod_args(args, 20000, 0, 0, BIT_ULL(CGX_MODE_20G_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT):
+		set_mod_args(args, 25000, 0, 0, BIT_ULL(CGX_MODE_25G_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT):
+		set_mod_args(args, 25000, 0, 0, BIT_ULL(CGX_MODE_25G_C2M));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT):
+		set_mod_args(args, 25000, 0, 0, BIT_ULL(CGX_MODE_25G_2_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT):
+		set_mod_args(args, 25000, 0, 1, BIT_ULL(CGX_MODE_25G_CR));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT):
+		set_mod_args(args, 25000, 0, 1, BIT_ULL(CGX_MODE_25G_KR));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT):
+		set_mod_args(args, 40000, 0, 0, BIT_ULL(CGX_MODE_40G_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT):
+		set_mod_args(args, 40000, 0, 0, BIT_ULL(CGX_MODE_40G_C2M));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT):
+		set_mod_args(args, 40000, 0, 1, BIT_ULL(CGX_MODE_40G_CR4));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT):
+		set_mod_args(args, 40000, 0, 1, BIT_ULL(CGX_MODE_40G_KR4));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT):
+		set_mod_args(args, 40000, 0, 0, BIT_ULL(CGX_MODE_40GAUI_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT):
+		set_mod_args(args, 50000, 0, 0, BIT_ULL(CGX_MODE_50G_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT):
+		set_mod_args(args, 50000, 0, 0, BIT_ULL(CGX_MODE_50G_4_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT):
+		set_mod_args(args, 50000, 0, 0, BIT_ULL(CGX_MODE_50G_C2M));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT):
+		set_mod_args(args, 50000, 0, 1, BIT_ULL(CGX_MODE_50G_CR));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT):
+		set_mod_args(args, 50000, 0, 1, BIT_ULL(CGX_MODE_50G_KR));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT):
+		set_mod_args(args, 80000, 0, 0, BIT_ULL(CGX_MODE_80GAUI_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT):
+		set_mod_args(args, 100000, 0, 0, BIT_ULL(CGX_MODE_100G_C2C));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT):
+		set_mod_args(args, 100000, 0, 0, BIT_ULL(CGX_MODE_100G_C2M));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT):
+		set_mod_args(args, 100000, 0, 1, BIT_ULL(CGX_MODE_100G_CR4));
+		break;
+	case  BIT_ULL(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT):
+		set_mod_args(args, 100000, 0, 1, BIT_ULL(CGX_MODE_100G_KR4));
+		break;
+	default:
+		set_mod_args(args, 0, 1, 0, BIT_ULL(CGX_MODE_MAX));
+		break;
+	}
+}
+
+static void link_status_user_format(u64 lstat,
+				    struct cgx_link_user_info *linfo,
+				    struct cgx *cgx, u8 lmac_id)
 {
 	char *lmac_string;
 
 	linfo->link_up = FIELD_GET(RESP_LINKSTAT_UP, lstat);
 	linfo->full_duplex = FIELD_GET(RESP_LINKSTAT_FDUPLEX, lstat);
 	linfo->speed = cgx_speed_mbps[FIELD_GET(RESP_LINKSTAT_SPEED, lstat)];
+	linfo->an = FIELD_GET(RESP_LINKSTAT_AN, lstat);
+	linfo->fec = FIELD_GET(RESP_LINKSTAT_FEC, lstat);
+	linfo->port = FIELD_GET(RESP_LINKSTAT_PORT, lstat);
 	linfo->lmac_type_id = cgx_get_lmac_type(cgx, lmac_id);
 	lmac_string = cgx_lmactype_string[linfo->lmac_type_id];
 	strncpy(linfo->lmac_type, lmac_string, LMACTYPE_STR_LEN - 1);
 }
 
 /* Hardware event handlers */
-static inline void cgx_link_change_handler(u64 lstat,
-					   struct lmac *lmac)
+static void cgx_link_change_handler(u64 lstat, struct lmac *lmac)
 {
 	struct cgx_link_user_info *linfo;
 	struct cgx *cgx = lmac->cgx;
@@ -620,6 +832,8 @@ static inline void cgx_link_change_handler(u64 lstat,
 	lmac->link_info = event.link_uinfo;
 	linfo = &lmac->link_info;
 
+	if (err_type == CGX_ERR_SPEED_CHANGE_INVALID)
+		return;
 	/* Ensure callback doesn't get unregistered until we finish it */
 	spin_lock(&lmac->event_cb_lock);
 
@@ -642,13 +856,14 @@ static inline void cgx_link_change_handler(u64 lstat,
 	spin_unlock(&lmac->event_cb_lock);
 }
 
-static inline bool cgx_cmdresp_is_linkevent(u64 event)
+static bool cgx_cmdresp_is_linkevent(u64 event)
 {
 	u8 id;
 
 	id = FIELD_GET(EVTREG_ID, event);
 	if (id == CGX_CMD_LINK_BRING_UP ||
-	    id == CGX_CMD_LINK_BRING_DOWN)
+	    id == CGX_CMD_LINK_BRING_DOWN ||
+	    id == CGX_CMD_MODE_CHANGE)
 		return true;
 	else
 		return false;
@@ -746,7 +961,7 @@ static irqreturn_t cgx_fwi_event_handler(int irq, void *data)
 
 		/* Release thread waiting for completion  */
 		lmac->cmd_pend = false;
-		wake_up_interruptible(&lmac->wq_cmd_cmplt);
+		wake_up(&lmac->wq_cmd_cmplt);
 		break;
 	case CGX_EVT_ASYNC:
 		if (cgx_event_is_linkevent(event))
@@ -819,6 +1034,53 @@ int cgx_get_fwdata_base(u64 *base)
 	return err;
 }
 
+int cgx_set_fec(u64 fec, int cgx_id, int lmac_id)
+{
+	u64 req = 0, resp;
+	struct cgx *cgx;
+	int err = 0;
+
+	cgx = cgx_get_pdata(cgx_id);
+	if (!cgx)
+		return -ENXIO;
+
+	req = FIELD_SET(CMDREG_ID, CGX_CMD_SET_FEC, req);
+	req = FIELD_SET(CMDSETFEC, fec, req);
+	err = cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id);
+	if (!err) {
+		cgx->lmac_idmap[lmac_id]->link_info.fec =
+			FIELD_GET(RESP_LINKSTAT_FEC, resp);
+		return cgx->lmac_idmap[lmac_id]->link_info.fec;
+	}
+	return err;
+}
+
+int cgx_set_link_mode(void *cgxd, struct cgx_set_link_mode_args args,
+		      int cgx_id, int lmac_id)
+{
+	struct cgx *cgx = cgxd;
+	u64 req = 0, resp;
+	int err = 0;
+
+	if (!cgx)
+		return -ENODEV;
+
+	if (args.mode)
+		otx2_map_ethtool_link_modes(args.mode, &args);
+	if (!args.speed && args.duplex && !args.an)
+		return -EINVAL;
+
+	req = FIELD_SET(CMDREG_ID, CGX_CMD_MODE_CHANGE, req);
+	req = FIELD_SET(CMDMODECHANGE_SPEED,
+			cgx_link_usertable_index_map(args.speed), req);
+	req = FIELD_SET(CMDMODECHANGE_DUPLEX, args.duplex, req);
+	req = FIELD_SET(CMDMODECHANGE_AN, args.an, req);
+	req = FIELD_SET(CMDMODECHANGE_PORT, args.ports, req);
+	req = FIELD_SET(CMDMODECHANGE_FLAGS, args.mode, req);
+	err = cgx_fwi_cmd_generic(req, &resp, cgx, lmac_id);
+	return err;
+}
+
 static int cgx_fwi_link_change(struct cgx *cgx, int lmac_id, bool enable)
 {
 	u64 req = 0;
@@ -880,6 +1142,16 @@ static void cgx_lmac_linkup_work(struct work_struct *work)
 	}
 }
 
+int cgx_set_link_state(void *cgxd, int lmac_id, bool enable)
+{
+	struct cgx *cgx = cgxd;
+
+	if (!cgx)
+		return -ENODEV;
+
+	return cgx_fwi_link_change(cgx, lmac_id, enable);
+}
+
 int cgx_lmac_linkup_start(void *cgxd)
 {
 	struct cgx *cgx = cgxd;
@@ -912,6 +1184,7 @@ static int cgx_lmac_init(struct cgx *cgx)
 		sprintf(lmac->name, "cgx_fwi_%d_%d", cgx->cgx_id, i);
 		lmac->lmac_id = i;
 		lmac->cgx = cgx;
+
 		init_waitqueue_head(&lmac->wq_cmd_cmplt);
 		mutex_init(&lmac->cmd_lock);
 		spin_lock_init(&lmac->event_cb_lock);
@@ -1009,7 +1282,7 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (!cgx->cgx_cmd_workq) {
 		dev_err(dev, "alloc workqueue failed for cgx cmd");
 		err = -ENOMEM;
-		goto err_free_irq_vectors;
+		goto err_release_regions;
 	}
 
 	list_add(&cgx->cgx_list, &cgx_list);
@@ -1025,8 +1298,6 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 err_release_lmac:
 	cgx_lmac_exit(cgx);
 	list_del(&cgx->cgx_list);
-err_free_irq_vectors:
-	pci_free_irq_vectors(pdev);
 err_release_regions:
 	pci_release_regions(pdev);
 err_disable_device:
@@ -1039,8 +1310,11 @@ static void cgx_remove(struct pci_dev *pdev)
 {
 	struct cgx *cgx = pci_get_drvdata(pdev);
 
-	cgx_lmac_exit(cgx);
-	list_del(&cgx->cgx_list);
+	if (cgx) {
+		cgx_lmac_exit(cgx);
+		list_del(&cgx->cgx_list);
+	}
+
 	pci_free_irq_vectors(pdev);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index fa411d4..b50e897 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -52,10 +52,14 @@
 #define CGXX_SCRATCH1_REG		0x1058
 #define CGX_CONST			0x2000
 #define CGXX_SPUX_CONTROL1		0x10000
+#define CGXX_SPUX_LNX_FEC_CORR_BLOCKS	0x10700
+#define CGXX_SPUX_LNX_FEC_UNCORR_BLOCKS	0x10800
+#define CGXX_SPUX_RSFEC_CORR		0x10088
+#define CGXX_SPUX_RSFEC_UNCORR		0x10090
+
 #define CGXX_SPUX_CONTROL1_LBK		BIT_ULL(14)
 #define CGXX_GMP_PCS_MRX_CTL		0x30000
 #define CGXX_GMP_PCS_MRX_CTL_LBK	BIT_ULL(14)
-
 #define CGXX_SMUX_RX_FRM_CTL		0x20020
 #define CGX_SMUX_RX_FRM_CTL_CTL_BCK	BIT_ULL(3)
 #define CGXX_GMP_GMI_RXX_FRM_CTL	0x38028
@@ -124,6 +128,7 @@ int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id);
 int cgx_lmac_evh_unregister(void *cgxd, int lmac_id);
 int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat);
 int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat);
+int cgx_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp);
 int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable);
 int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable);
 int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr);
@@ -135,9 +140,13 @@ 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_fwdata_base(u64 *base);
+int cgx_set_fec(u64 fec, int cgx_id, int lmac_id);
+int cgx_set_link_mode(void *cgxd, struct cgx_set_link_mode_args args,
+		      int cgx_id, int lmac_id);
 int cgx_lmac_get_pause_frm(void *cgxd, int lmac_id,
 			   u8 *tx_pause, u8 *rx_pause);
 int cgx_lmac_set_pause_frm(void *cgxd, int lmac_id,
 			   u8 tx_pause, u8 rx_pause);
+int cgx_set_link_state(void *cgxd, int lmac_id, bool enable);
 int cgx_get_mkex_prfl_info(u64 *addr, u64 *size);
 #endif /* CGX_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
index c3702fa..f16cdd0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx_fw_if.h
@@ -43,7 +43,13 @@ enum cgx_error_type {
 	CGX_ERR_TRAINING_FAIL,
 	CGX_ERR_RX_EQU_FAIL,
 	CGX_ERR_SPUX_BER_FAIL,
-	CGX_ERR_SPUX_RSFEC_ALGN_FAIL,   /* = 22 */
+	CGX_ERR_SPUX_RSFEC_ALGN_FAIL,
+	CGX_ERR_SPUX_MARKER_LOCK_FAIL,
+	CGX_ERR_SET_FEC_INVALID,
+	CGX_ERR_SET_FEC_FAIL,
+	CGX_ERR_MODULE_INVALID,
+	CGX_ERR_MODULE_NOT_PRESENT,
+	CGX_ERR_SPEED_CHANGE_INVALID,
 };
 
 /* LINK speed types */
@@ -59,10 +65,42 @@ enum cgx_link_speed {
 	CGX_LINK_25G,
 	CGX_LINK_40G,
 	CGX_LINK_50G,
+	CGX_LINK_80G,
 	CGX_LINK_100G,
 	CGX_LINK_SPEED_MAX,
 };
 
+enum CGX_MODE_ {
+	CGX_MODE_SGMII,
+	CGX_MODE_1000_BASEX,
+	CGX_MODE_QSGMII,
+	CGX_MODE_10G_C2C,
+	CGX_MODE_10G_C2M,
+	CGX_MODE_10G_KR,
+	CGX_MODE_20G_C2C,
+	CGX_MODE_25G_C2C,
+	CGX_MODE_25G_C2M,
+	CGX_MODE_25G_2_C2C,
+	CGX_MODE_25G_CR,
+	CGX_MODE_25G_KR,
+	CGX_MODE_40G_C2C,
+	CGX_MODE_40G_C2M,
+	CGX_MODE_40G_CR4,
+	CGX_MODE_40G_KR4,
+	CGX_MODE_40GAUI_C2C,
+	CGX_MODE_50G_C2C,
+	CGX_MODE_50G_C2M,
+	CGX_MODE_50G_4_C2C,
+	CGX_MODE_50G_CR,
+	CGX_MODE_50G_KR,
+	CGX_MODE_80GAUI_C2C,
+	CGX_MODE_100G_C2C,
+	CGX_MODE_100G_C2M,
+	CGX_MODE_100G_CR4,
+	CGX_MODE_100G_KR4,
+	CGX_MODE_MAX /* = 29 */
+};
+
 /* REQUEST ID types. Input to firmware */
 enum cgx_cmd_id {
 	CGX_CMD_NONE,
@@ -75,12 +113,20 @@ enum cgx_cmd_id {
 	CGX_CMD_INTERNAL_LBK,
 	CGX_CMD_EXTERNAL_LBK,
 	CGX_CMD_HIGIG,
-	CGX_CMD_LINK_STATE_CHANGE,
+	CGX_CMD_LINK_STAT_CHANGE,
 	CGX_CMD_MODE_CHANGE,		/* hot plug support */
 	CGX_CMD_INTF_SHUTDOWN,
 	CGX_CMD_GET_MKEX_PRFL_SIZE,
 	CGX_CMD_GET_MKEX_PRFL_ADDR,
 	CGX_CMD_GET_FWD_BASE,		/* get base address of shared FW data */
+	CGX_CMD_GET_LINK_MODES,		/* Supported Link Modes */
+	CGX_CMD_SET_LINK_MODE,
+	CGX_CMD_GET_SUPPORTED_FEC,
+	CGX_CMD_SET_FEC,
+	CGX_CMD_GET_AN,
+	CGX_CMD_SET_AN,
+	CGX_CMD_GET_ADV_LINK_MODES,
+	CGX_CMD_GET_ADV_FEC,
 };
 
 /* async event ids */
@@ -149,7 +195,6 @@ enum cgx_cmd_own {
  * CGX_STAT_SUCCESS
  */
 #define RESP_MKEX_PRFL_ADDR		GENMASK_ULL(63, 9)
-
 /* Response to cmd ID as CGX_CMD_GET_FWD_BASE with cmd status as
  * CGX_STAT_SUCCESS
  */
@@ -171,13 +216,19 @@ struct cgx_lnk_sts {
 	uint64_t full_duplex:1;
 	uint64_t speed:4;		/* cgx_link_speed */
 	uint64_t err_type:10;
-	uint64_t reserved2:39;
+	uint64_t an:1;			/* AN supported or not */
+	uint64_t fec:2;			/* FEC type if enabled, if not 0 */
+	uint64_t port:8;
+	uint64_t reserved2:28;
 };
 
 #define RESP_LINKSTAT_UP		GENMASK_ULL(9, 9)
 #define RESP_LINKSTAT_FDUPLEX		GENMASK_ULL(10, 10)
 #define RESP_LINKSTAT_SPEED		GENMASK_ULL(14, 11)
 #define RESP_LINKSTAT_ERRTYPE		GENMASK_ULL(24, 15)
+#define RESP_LINKSTAT_AN		GENMASK_ULL(25, 25)
+#define RESP_LINKSTAT_FEC		GENMASK_ULL(27, 26)
+#define RESP_LINKSTAT_PORT		GENMASK_ULL(35, 28)
 
 /* scratchx(1) CSR used for non-secure SW->ATF communication
  * This CSR acts as a command register
@@ -198,5 +249,18 @@ struct cgx_lnk_sts {
 #define CMDLINKCHANGE_LINKUP	BIT_ULL(8)
 #define CMDLINKCHANGE_FULLDPLX	BIT_ULL(9)
 #define CMDLINKCHANGE_SPEED	GENMASK_ULL(13, 10)
+#define CMDSETFEC		GENMASK_ULL(9, 8)
+/* command argument to be passed for cmd ID - CGX_CMD_MODE_CHANGE */
+#define CMDMODECHANGE_SPEED		GENMASK_ULL(11, 8)
+#define CMDMODECHANGE_DUPLEX		GENMASK_ULL(12, 12)
+#define CMDMODECHANGE_AN		GENMASK_ULL(13, 13)
+#define CMDMODECHANGE_PORT		GENMASK_ULL(21, 14)
+#define CMDMODECHANGE_FLAGS		GENMASK_ULL(63, 22)
+
+/* command argument to be passed for cmd ID - CGX_CMD_SET_PHY_MOD_TYPE */
+#define CMDSETPHYMODTYPE	GENMASK_ULL(8, 8)
+
+/* response to cmd ID - RESP_GETPHYMODTYPE */
+#define RESP_GETPHYMODTYPE	GENMASK_ULL(9, 9)
 
 #endif /* __CGX_FW_INTF_H__ */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 5ba6b30..a3b69fb 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -145,6 +145,13 @@ M(CGX_INTLBK_ENABLE,	0x20A, cgx_intlbk_enable, msg_req, msg_rsp)	\
 M(CGX_INTLBK_DISABLE,	0x20B, cgx_intlbk_disable, msg_req, msg_rsp)	\
 M(CGX_CFG_PAUSE_FRM,	0x20E, cgx_cfg_pause_frm, cgx_pause_frm_cfg,	\
 			       cgx_pause_frm_cfg)			\
+M(CGX_FW_DATA_GET,	0x20F, cgx_get_aux_link_info, msg_req, cgx_fw_data) \
+M(CGX_FEC_SET,		0x210, cgx_set_fec_param, fec_mode, fec_mode) \
+M(CGX_SET_LINK_STATE,	0x214, cgx_set_link_state,    \
+				cgx_set_link_state_msg, msg_rsp)	\
+M(CGX_FEC_STATS,	0x217, cgx_fec_stats, msg_req, cgx_fec_stats_rsp) \
+M(CGX_SET_LINK_MODE,	0x218, cgx_set_link_mode, cgx_set_link_mode_req,\
+			       cgx_set_link_mode_rsp)	\
 /* NPA mbox IDs (range 0x400 - 0x5FF) */				\
 M(NPA_LF_ALLOC,		0x400, npa_lf_alloc,				\
 				npa_lf_alloc_req, npa_lf_alloc_rsp)	\
@@ -350,6 +357,12 @@ struct cgx_stats_rsp {
 	u64 tx_stats[CGX_TX_STATS_COUNT];
 };
 
+struct cgx_fec_stats_rsp {
+	struct mbox_msghdr hdr;
+	u64 fec_corr_blks;
+	u64 fec_uncorr_blks;
+};
+
 /* Structure for requesting the operation for
  * setting/getting mac address in the CGX interface
  */
@@ -363,6 +376,9 @@ struct cgx_link_user_info {
 	uint64_t full_duplex:1;
 	uint64_t lmac_type_id:4;
 	uint64_t speed:20; /* speed in Mbps */
+	uint64_t an:1;	  /* AN supported or not */
+	uint64_t fec:2;	 /* FEC type if enabled else 0 */
+	uint64_t port:8;
 #define LMACTYPE_STR_LEN 16
 	char lmac_type[LMACTYPE_STR_LEN];
 };
@@ -381,6 +397,66 @@ struct cgx_pause_frm_cfg {
 	u8 tx_pause;
 };
 
+struct sfp_eeprom_s {
+#define SFP_EEPROM_SIZE 256
+	u16 sff_id;
+	u8 buf[SFP_EEPROM_SIZE];
+	u64 reserved;
+};
+
+enum fec_type {
+	OTX2_FEC_NONE,
+	OTX2_FEC_BASER,
+	OTX2_FEC_RS,
+};
+
+struct cgx_lmac_fwdata_s {
+	u16 rw_valid;
+	u64 supported_fec;
+	u64 supported_an;
+	u64 supported_link_modes;
+	/* only applicable if AN is supported */
+	u64 advertised_fec;
+	u64 advertised_link_modes;
+	/* Only applicable if SFP/QSFP slot is present */
+	struct sfp_eeprom_s sfp_eeprom;
+#define LMAC_FWDATA_RESERVED_MEM 1024
+	u64 reserved[LMAC_FWDATA_RESERVED_MEM];
+};
+
+struct cgx_fw_data {
+	struct mbox_msghdr hdr;
+	struct cgx_lmac_fwdata_s fwdata;
+};
+
+struct fec_mode {
+	struct mbox_msghdr hdr;
+	int fec;
+};
+
+struct cgx_set_link_state_msg {
+	struct mbox_msghdr hdr;
+	u8 enable; /* '1' for link up, '0' for link down */
+};
+
+struct cgx_set_link_mode_args {
+	u32 speed;
+	u8 duplex;
+	u8 an;
+	u8 ports;
+	u64 mode;
+};
+
+struct cgx_set_link_mode_req {
+	struct mbox_msghdr hdr;
+	struct cgx_set_link_mode_args args;
+};
+
+struct cgx_set_link_mode_rsp {
+	struct mbox_msghdr hdr;
+	int status;
+};
+
 /* NPA mbox message formats */
 
 /* NPA mailbox error codes
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index a90af41..6f0a7ef 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -305,6 +305,10 @@ struct rvu_fwdata {
 	u64 msixtr_base;
 #define FWDATA_RESERVED_MEM 1023
 	u64 reserved[FWDATA_RESERVED_MEM];
+	/* Do not add new fields below this line */
+#define CGX_MAX         4
+#define CGX_LMACS_MAX   4
+	struct cgx_lmac_fwdata_s cgx_fw_data[CGX_MAX][CGX_LMACS_MAX];
 };
 
 struct rvu {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index 6859339..ec129c7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -185,12 +185,8 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu)
 		clear_bit(pfid, &pfmap);
 
 		/* check if notification is enabled */
-		if (!test_bit(pfid, &rvu->pf_notify_bmap)) {
-			dev_info(rvu->dev, "cgx %d: lmac %d Link status %s\n",
-				 event->cgx_id, event->lmac_id,
-				 linfo->link_up ? "UP" : "DOWN");
+		if (!test_bit(pfid, &rvu->pf_notify_bmap))
 			continue;
-		}
 
 		/* Send mbox message to PF */
 		msg = otx2_mbox_alloc_msg_cgx_link_event(rvu, pfid);
@@ -286,7 +282,7 @@ int rvu_cgx_init(struct rvu *rvu)
 	rvu->cgx_cnt_max = cgx_get_cgxcnt_max();
 	if (!rvu->cgx_cnt_max) {
 		dev_info(rvu->dev, "No CGX devices found!\n");
-		return -ENODEV;
+		return 0;
 	}
 
 	rvu->cgx_idmap = devm_kzalloc(rvu->dev, rvu->cgx_cnt_max *
@@ -445,6 +441,24 @@ int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req,
 	return 0;
 }
 
+int rvu_mbox_handler_cgx_fec_stats(struct rvu *rvu,
+				   struct msg_req *req,
+				   struct cgx_fec_stats_rsp *rsp)
+{
+	int pf = rvu_get_pf(req->hdr.pcifunc);
+	u8 cgx_idx, lmac;
+	int err = 0;
+	void *cgxd;
+
+	if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+		return -EPERM;
+	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
+
+	cgxd = rvu_cgx_pdata(cgx_idx, rvu);
+	err = cgx_get_fec_stats(cgxd, lmac, rsp);
+	return err;
+}
+
 int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu,
 				      struct cgx_mac_addr_set_or_get *req,
 				      struct cgx_mac_addr_set_or_get *rsp)
@@ -553,7 +567,7 @@ int rvu_mbox_handler_cgx_get_linkinfo(struct rvu *rvu, struct msg_req *req,
 	pf = rvu_get_pf(req->hdr.pcifunc);
 
 	if (!is_pf_cgxmapped(rvu, pf))
-		return -ENODEV;
+		return -EPERM;
 
 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
 
@@ -704,3 +718,74 @@ int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start)
 	mutex_unlock(&rvu->cgx_cfg_lock);
 	return err;
 }
+
+int rvu_mbox_handler_cgx_get_aux_link_info(struct rvu *rvu, struct msg_req *req,
+					   struct cgx_fw_data *rsp)
+{
+	int pf = rvu_get_pf(req->hdr.pcifunc);
+	u8 cgx_id, lmac_id;
+
+	if (!rvu->fwdata)
+		return -ENXIO;
+
+	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+	memcpy(&rsp->fwdata, &rvu->fwdata->cgx_fw_data[cgx_id][lmac_id],
+	       sizeof(struct cgx_lmac_fwdata_s));
+	return 0;
+}
+
+int rvu_mbox_handler_cgx_set_fec_param(struct rvu *rvu,
+				       struct fec_mode *req,
+				       struct fec_mode *rsp)
+{
+	int pf = rvu_get_pf(req->hdr.pcifunc);
+	u8 cgx_id, lmac_id;
+
+	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+	rsp->fec = cgx_set_fec(req->fec, cgx_id, lmac_id);
+	return 0;
+}
+
+int rvu_mbox_handler_cgx_set_link_state(struct rvu *rvu,
+					struct cgx_set_link_state_msg *req,
+					struct msg_rsp *rsp)
+{
+	u16 pcifunc = req->hdr.pcifunc;
+	u8 cgx_id, lmac_id;
+	int pf, err;
+
+	pf = rvu_get_pf(pcifunc);
+
+	if (!is_cgx_config_permitted(rvu, pcifunc))
+		return -EPERM;
+
+	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+
+	err = cgx_set_link_state(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
+				 !!req->enable);
+	if (err)
+		dev_warn(rvu->dev, "Cannot set link state to %s, err %d\n",
+			 (req->enable) ? "enable" : "disable", err);
+
+	return err;
+}
+
+int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu,
+				       struct cgx_set_link_mode_req *req,
+				       struct cgx_set_link_mode_rsp *rsp)
+{
+	int pf = rvu_get_pf(req->hdr.pcifunc);
+	u8 cgx_idx, lmac;
+	void *cgxd;
+
+	if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc))
+		return -EPERM;
+
+	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
+
+	cgxd = rvu_cgx_pdata(cgx_idx, rvu);
+
+	rsp->status =  cgx_set_link_mode(cgxd, req->args, cgx_idx, lmac);
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
                   ` (14 preceding siblings ...)
  2019-11-20 17:48 ` [PATCH v3 15/16] octeontx2-af: Support to get CGX link info like current speed, fec etc sunil.kovvuri
@ 2019-11-20 17:48 ` sunil.kovvuri
  2019-11-21  0:41   ` Jakub Kicinski
  15 siblings, 1 reply; 24+ messages in thread
From: sunil.kovvuri @ 2019-11-20 17:48 UTC (permalink / raw)
  To: netdev; +Cc: davem, jakub.kicinski, Sunil Goutham

From: Sunil Goutham <sgoutham@marvell.com>

Added high level overview of OcteonTx2 RVU HW and functionality of
various drivers which will be upstreamed.

Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 Documentation/networking/device_drivers/index.rst  |    1 +
 .../device_drivers/marvell/octeontx2.rst           |  162 +
 .../marvell/resource_virtualization_unit.svg       | 3297 ++++++++++++++++++++
 MAINTAINERS                                        |    1 +
 4 files changed, 3461 insertions(+)
 create mode 100644 Documentation/networking/device_drivers/marvell/octeontx2.rst
 create mode 100644 Documentation/networking/device_drivers/marvell/resource_virtualization_unit.svg

diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst
index c1f7f75..8aba64b 100644
--- a/Documentation/networking/device_drivers/index.rst
+++ b/Documentation/networking/device_drivers/index.rst
@@ -22,6 +22,7 @@ Contents:
    intel/iavf
    intel/ice
    google/gve
+   marvell/octeontx2
    mellanox/mlx5
    netronome/nfp
    pensando/ionic
diff --git a/Documentation/networking/device_drivers/marvell/octeontx2.rst b/Documentation/networking/device_drivers/marvell/octeontx2.rst
new file mode 100644
index 0000000..c8a5150
--- /dev/null
+++ b/Documentation/networking/device_drivers/marvell/octeontx2.rst
@@ -0,0 +1,162 @@
+.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+=============================================
+Marvell OcteonTx2 RVU Kernel Drivers
+=============================================
+
+Copyright (c) 2019 Marvell International Ltd.
+
+Contents
+========
+
+- `Overview`_
+- `Drivers`_
+- `Basic packet flow`_
+
+Overview
+========
+Resource virtualization unit (RVU) on Marvell's OcteonTX2 SOC maps HW
+resources from the network, crypto and other functional blocks into
+PCI-compatible physical and virtual functions. Each functional block
+again has multiple local functions (LFs) for provisioning to PCI devices.
+RVU supports multiple PCIe SRIOV physical functions (PFs) and virtual
+functions (VFs). PF0 is called the administrative / admin function (AF)
+and has privileges to provision RVU functional block's LFs to each of the
+PF/VF.
+
+RVU managed networking functional blocks
+ - Network pool or buffer allocator (NPA)
+ - Network interface controller (NIX)
+ - Network parser CAM (NPC)
+ - Schedule/Synchronize/Order unit (SSO)
+ - Loopback interface (LBK)
+
+RVU managed non-networking functional blocks
+ - Crypto accelerator (CPT)
+ - Scheduled timers unit (TIM)
+ - Schedule/Synchronize/Order unit (SSO)
+   Used for both networking and non networking usecases
+
+Resource provisioning examples
+ - A PF/VF with NIX-LF & NPA-LF resources works as a pure network device
+ - A PF/VF with CPT-LF resource works as a pure cyrpto offload device.
+
+.. kernel-figure::  resource_virtualization_unit.svg
+   :alt:	RVU
+   :align:	center
+   :figwidth:	60em
+
+   RVU HW block connectivity
+
+RVU functional blocks are highly configurable as per software requirements.
+
+Firmware setups following stuff before kernel boots
+ - Enables required number of RVU PFs based on number of physical links.
+ - Number of VFs per PF are either static or configurable at compile time.
+   Based on config, firmware assigns VFs to each of the PFs.
+ - Also assigns MSIX vectors to each of PF and VFs.
+ - These are not changed after kernel boot.
+
+Drivers
+=======
+
+Linux kernel will have multiple drivers registering to different PF and VFs
+of RVU. Wrt networking there will be 3 flavours of drivers.
+
+Admin Function driver
+---------------------
+
+As mentioned above RVU PF0 is called the admin function (AF), this driver
+supports resource provisioning and configuration of functional blocks.
+Doesn't handle any I/O. It sets up few basic stuff but most of the
+funcionality is achieved via configuration requests from PFs and VFs.
+
+PF/VFs communicates with AF via a shared memory region (mailbox). Upon
+receiving requests AF does resource provisioning and other HW configuration.
+AF is always attached to host kernel, but PFs and their VFs may be used by host
+kernel itself, or attached to VMs or to userspace applications like
+DPDK etc. So AF has to handle provisioning/configuration requests sent
+by any device from any domain.
+
+AF driver also interacts with underlying firmware to
+ - Manage physical ethernet links ie CGX LMACs.
+ - Retrieve information like speed, duplex, autoneg etc
+ - Retrieve PHY EEPROM and stats.
+ - Configure FEC, PAM modes
+ - etc
+
+From pure networking side AF driver supports following functionality.
+ - Map a physical link to a RVU PF to which a netdev is registered.
+ - Attach NIX and NPA block LFs to RVU PF/VF which provide buffer pools, RQs, SQs
+   for regular networking functionality.
+ - Flow control (pause frames) enable/disable/config.
+ - HW PTP timestamping related config.
+ - NPC parser profile config, basically how to parse pkt and what info to extract.
+ - NPC extract profile config, what to extract from the pkt to match data in MCAM entries.
+ - Manage NPC MCAM entries, upon request can frame and install requested packet forwarding rules.
+ - Defines receive side scaling (RSS) algorithms.
+ - Defines segmentation offload algorithms (eg TSO)
+ - VLAN stripping, capture and insertion config.
+ - SSO and TIM blocks config which provide packet scheduling support.
+ - Debugfs support, to check current resource provising, current status of
+   NPA pools, NIX RQ, SQ and CQs, various stats etc which helps in debugging issues.
+ - And many more.
+
+Physical Function driver
+------------------------
+
+This RVU PF handles IO, is mapped to a physical ethernet link and this
+driver registers a netdev. This supports SR-IOV. As said above this driver
+communicates with AF with a mailbox. To retrieve information from physical
+links this driver talks to AF and AF gets that info from firmware and responds
+back ie cannot talk to firmware directly.
+
+Supports ethtool for configuring links, RSS, queue count, queue size,
+flow control, ntuple filters, dump PHY EEPROM, config FEC etc.
+
+Virtual Function driver
+-----------------------
+
+There are two types VFs, VFs that share the physical link with their parent
+SR-IOV PF and the VFs which work in pairs using internal HW loopback channels (LBK).
+
+Type1:
+ - These VFs and their parent PF share a physical link and used for outside communication.
+ - VFs cannot communicate with AF directly, they send mbox message to PF and PF
+   forwards that to AF. AF after processing, responds back to PF and PF forwards
+   the reply to VF.
+ - From functionality point of view there is no difference between PF and VF as same type
+   HW resources are attached to both. But user would be able to configure few stuff only
+   from PF as PF is treated as owner/admin of the link.
+
+Type2:
+ - RVU PF0 ie admin function creates these VFs and maps them to loopback block's channels.
+ - A set of two VFs (VF0 & VF1, VF2 & VF3 .. so on) works as a pair ie pkts sent out of
+   VF0 will be received by VF1 and viceversa.
+ - These VFs can be used by applications or virtual machines to communicate between them
+   without sending traffic outside. There is no switch present in HW, hence the support
+   for loopback VFs.
+ - These communicate directly with AF (PF0) via mbox.
+
+Except for the IO channels or links used for packet reception and transmission there is
+no other difference between these VF types. AF driver takes care of IO channel mapping,
+hence same VF driver works for both types of devices.
+
+Basic packet flow
+===========
+Ingress
+-------
+1. CGX LMAC receives packet.
+2. Forwards the packet to the NIX block.
+3. Then submitted to NPC block for parsing and then MCAM lookup to get the destination RVU device.
+4. NIX LF attached to the destination RVU device allocates a buffer from RQ mapped buffer pool of NPA block LF.
+5. RQ may be selected by RSS or by configuring MCAM rule with a RQ number.
+6. Packet is DMA'ed and driver is notified.
+
+Egress
+------
+1. Driver prepares a send descriptor and submits to SQ for transmission.
+2. The SQ is already configured (by AF) to transmit on a specific link/channel.
+3. The SQ descriptor ring is maintained in buffers allocated from SQ mapped pool of NPA block LF.
+4. NIX block transmits the pkt on the designated channel.
+5. NPC MCAM entries can be installed to divert pkt onto a different channel.
diff --git a/Documentation/networking/device_drivers/marvell/resource_virtualization_unit.svg b/Documentation/networking/device_drivers/marvell/resource_virtualization_unit.svg
new file mode 100644
index 0000000..3ff9839
--- /dev/null
+++ b/Documentation/networking/device_drivers/marvell/resource_virtualization_unit.svg
@@ -0,0 +1,3297 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1280px" height="720px" viewBox="0 0 1280 720" enable-background="new 0 0 1280 720" xml:space="preserve">  <image id="image0" width="1280" height="720" x="0" y="0"
+    href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAIAAABAH0oBAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAA
+CXBIWXMAAA7DAAAOwwHHb6hkAACAAElEQVR42uz9ebwkV3kneP+e55yIyMy7ValKC1gIsQgkgZAB
+s0gsFjQGY+xp2z2vZ7rdnm6/Pe3dBrEYMHjF+4zttt09bnf39PS8jfG0TXsbd3sBxCKBAEmIRUJC
+bAIJbaWl6i6ZGRHnPM/7x8nMe6u0UBIqlUr39/1chW7lzRsZETeX+MU55zni7iAiIiIiIiJ6rNPj
+vQFEREREREREjwQGYCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIiol2BAZiIiIiIiIh2BQZgIiIi
+IiIi2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAiIiIiIiLaFRiAiYiIiIiIaFdg
+ACYiIiIiIqJdgQGYiIiIiIiIdgUGYCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIiol2BAZiIiIiI
+iIh2BQZgIiIiIiIi2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAiIiIiIiLaFRiA
+iYiIiIiIaFdgACYiIiIiIqJdgQGYiIiIiIiIdgUGYCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIi
+ol2BAZiIiIiIiIh2BQZgIiIiIiIi2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAi
+IiIiIiLaFRiAiYiIiIiIaFdgACYiIiIiIqJdgQGYiIiIiIiIdgUGYCIiIiIiItoVGICJiIiIiIho
+V2AAJiIiIiIiol2BAZiIiIiIiIh2BQZgIiIiIiIi2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiI
+iIiIiHYFBmAiIiIiIiLaFRiAiYiIiIiIaFdgACYiIiIiIqJdgQGYiIiIiIiIdgUGYCIiIiIiItoV
+GICJiIiIiIhoV2AAJiIiIiIiol2BAZiIiIiIiIh2BQZgIiIiIiIi2hUYgImIiIiIiGhXYAAmIiIi
+IiKiXYEBmIiIiIiIiHYFBmAiIiIiIiLaFRiAiYiIiIiIaFdgACYiIiIiIqJdgQGYiIiIiIiIdgUG
+YCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIiol2BAZiIiIiIiIh2BQZgIiIiIiIi2hUYgImIiIiI
+iGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAiIiIiIiLaFRiAiYiIiIiIaFdgACYiIiIiIqJdgQGY
+iIiIiIiIdgUGYCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIiol2BAZiIiIiIiIh2BQZgIiIiIiIi
+2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAiIiIiIiLaFRiAiYiIiIiIaFdgACYi
+IiIiIqJdgQGYiIiIiIiIdgUGYCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIiol2BAZiIiIiIiIh2
+BQZgIiIiIiIi2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAiIiIiIiLaFRiAiYiI
+iIiIaFdgACYiIiIiIqJdgQGYiIiIiIiIdgUGYCIiIiIiItoVGICJiIiIiIhoV2AAJiIiIiIiol2B
+AZiIiIiIiIh2BQZgIiIiIiIi2hUYgImIiIiIiGhXYAAmIiIiIiKiXYEBmIiIiIiIiHYFBmAiIiIi
+IiLaFRiAiYiIiIiIaFdgACYiIiIiIqJdgQGYiIiIiIiIdoV4vDeA6KFw9+O9CURERETHhIgc700g
+esxiAKYTEgMwERERnegYdIkeeQzA9GhnZqpaljlnMzMzfmAQERHRY4O7xxhTSjHGcs4TQjjeG0X0
+mCVsSaNHOXcXkZSSiLRtG0Iws7Ztj/d2EREREX1DykmOiNR1DaB8U67y81o/0THCFmA6Abi7u+ec
++75vmgbAcDg83htFRERE9I0qbVEiknPe2toCEEKIMZZsfLy3jugxiAGYHtXKp4KZ5ZxTSuPxeG1t
+rdxyvDeNiIiI6BuiqouUq6rj8VhEVJXpl+jYYQCmR7Xy7u/uKaXJZLK+vn7qqacCUOUMXkRERHRi
+yzljR2/n9fV1VY0xLsYAMwYTPewYgOlRrdS7KoWvuq4rV0b5YUBERESPAUcUu9ra2hoMBsPhsKoq
+MP0SHRtsRqNHtdLVeTEGuG1bfhgQERHRY0MZ5IV5U3DbtjlnERapJTqG2AJMj2qL9l4z6/u+bdvS
+JswYTERERCe6xZCucmLTdV1KqYRhIjpGGIDpUS2EkHNefDyU2YCP90YRERERPWzcvRS+Kuc8ZraY
+Hul4bxrRYxCzBBEREREREe0KDMBERERERES0KzAAExERERER0a7AAExERERERES7AgMwERERERER
+7QoMwERERERERLQrMAATERERERHRrsAATERERERERLsCAzARERERERHtCgzAREREREREtCswABMR
+EREREdGuwABMREREREREuwIDMBEREREREe0KDMBERERERES0KzAAExERERER0a7AAExERERERES7
+AgMwERERERER7QoMwERERERERLQrMAATERERERHRrsAATERERERERLsCAzARERERERHtCgzARERE
+REREtCswABMREREREdGuwABMREREREREuwIDMBEREREREe0KDMBERERERES0KzAAExERERER0a7A
+AExERERERES7AgMwERERERER7QoMwERERERERLQrMAATERERERHRrsAATERERERERLsCAzARERER
+ERHtCgzAREREREREtCswABMREREREdGuwABMREREREREuwIDMBEREREREe0KDMBERERERES0K8Tj
+vQFE9OjlAABZfDf7x+J223kRzWc/fNAPITuW93bET2XHL94XO3wbdl7js3v984Hv8BAOk/lstXHH
+lqgDBgOgULmPX7X5ful8VXZf238M+PYfVHbeiPu5/SH8gYmIiIgeTRiAiei+OZBh7tBeQwASUAGA
+AS4AEErYM4XA52n4aCOSAwKfh87F8t6O+KlbjioAMhwIACwjBJhDxARZ+l5DgKpDZDtA2mw1O8Lq
+LOq5AiVzZj8iiGL7zkfeUO5Tcvl2as2G5LOtzhFmbirD5DDJDo+ow+zCAeAKgcEcJnC4I8UQFKlD
+pRA3QA/b/h2H5N7pX2y2I/c2/5P44aua3ezqO65kyHx3LLtEMZhABCIGZCAyAxMREdGJjV2giej+
+2NSmIggRJWz2kxYC2w6DDti8cdbu1fqK+460fljrrR6+3PmNzhP1Yulw9wxHbqfmCTAzVAp1REHb
+TQWuoYIEQOw+24gPe3Q7/BabBd37a1yG2WKP/PB1HnaLAtp1pck3wMqFxmBwWxwRt8WvGry1KURD
+UDgQYjcdo+zbYYfRdnxzPx5KOrXF3mHH3olnwLo0TZ4AIJerDUREREQnNrYAE9H9GmgQ5K7rK4kS
+pRpWgIWgBigSkAAFIgSCHGBAtd0OKfNAtfOW7e+B0t54LwE4LOM5RABXEYsCg8MtVHUQAGYmMDGz
+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
+BF2CdGngXdx5Z7Nw+VFK6eqrrxaR5z3veTsfd/F9GXV8lFMrEREREdE3jgGYiHaj0izc9/155513
+zjnn/O3f/u2dd9557wJXpe90mTG4/Gh9fR3z3Nv3/aIhtwzrLd+XNVxzzTUHDhx4yUteUoJuSul4
+7zQRERHRbsf6K0S0G5UuyjHGMkXwnj17PvjBDz71qU8999xzVbXruqqqSujt+750aa7reu/evVtb
+W2tra2YWQqiqysxKtWcAIYQQgpmp6uWXX37XXXd953d+Z8m9qsp6V0RERETHHVuAiWjXKV2au64r
+UwSb2Z49e170ohfdfvvtV111FYC6rruuAzCZTKqqapqm/Mrq6uqBAwfMbNFKvOj5XAYbl/R7zTXX
+3HXXXd/xHd8BQFVFhMN9iYiIiB4NGICJaNdx95RSGRvc930ZHrx///7nP//5d9555+WXX16afFNK
+w+Fw5+Dexz/+8XfddVdpzi2tvjHG0hEaQF3XIvLJT37ypptues1rXiMi7l4CcIyR1Z6JiIiIjjsG
+YCLadUqCbdu2dGAGUFpol5eXL7roorZtL7300q2trUWn5b7vRcTMVlZW7rjjjtKrOYQwnU5zzuVu
+pcX4hhtuuP322y+44ILF4GF3X3x/vPebiIiIaLdjACaiXappmhJrMe8UXaZKuuiii9bW1haloVW1
+qip37/ve3Zum+ehHP/qXf/mX73znO2+66aYQwmK+3+uuu+6GG2648MIL9+zZswjPJQDj6GYPJiIi
+IqJjikVZiO6fA2IA4AoAMr/t6JbHSUlZeq/vH/j+C0fe+UHvb+nnK/OHfriPxdFvz9ddWs4agook
+y3VdZzeFxKrq+/5Z33x+Xdcfu+Ljz/nmZ59y6qnjra2PfPTy2265FSpRw1du+modK41hPB5nN3GI
+6s0333zd567/9le+qhkOcs4aguUsQVW1qmszE9WHd/uP+fPtG3v+77blI/P8J3okPRpeWY/o65eI
+dge2ABMBsPlXCUaAw5IDBjdYhlm5ff7Do1r6faz/8C/HkV87b8dsc+Zf9/W72+tf/DMDeX57D+T7
+eJQjHu7+tu2o99R2rs8BM1iGG2BIvn2PIw71/Sv7mz31uXMgWXYgP8jj/3WXGkL5XjQ4AFGIZHis
+Koecc+65T3zSkz58+Uduuf220dLS3n37muEgVJXGkMyy2/Lq6meuveaTn/50svy122799DWfecm3
+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
+pkm/KaWUUl3X06ekU+03572F4w8qwNiPwURERETnvxBCjLFpGjObzWaqGkKYRrfd24dGdNESBgY6
+nx28B5RSzCzGaGY55yn94k7lX75hEBER0YViup6Zmn1Ohd+6rjmojeicYgWYzmvT7N/pPcA5V0rx
+3qeUcPti77TPNEz63j5kIiIioi/IdPUyNfs8uOCZvry3D43oosUKMF2QGHSJiIjoYsWVkIjOHX68
+RBckjgsiIiIiIqIvFivAREREREREdChwfAUREREREREdCgzAREREREREdCgwABMREREREdGhwABM
+REREREREhwIDMBERERERER0KDMBERERERER0KDAAExERERER0aHAAExERERERESHAgMwERERERER
+HQoMwERERERERHQoMAATERERERHRocAATERERERERIcCAzAREREREREdCgzAREREREREdCgwABMR
+EREREdGhwABMREREREREhwIDMBERERERER0KDMBERERERER0KDAAExERERER0aHAAExERERERESH
+AgMwERERERERHQoMwERERERERHQoMAATERERERHRocAATERERERERIcCAzAREREREREdCgzARERE
+REREdCgwABMREREREdGhwABMREREREREhwIDMBERERERER0KDMBERERERER0KDAAExERERER0aHA
+AExERERERESHAgMwERERERERHQoMwERERERERHQoMAATERERERHRocAATERERERERIcCAzARERER
+EREdCv8/0HwlipEPAtMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMTEtMjBUMDU6NDY6MjgtMDc6
+MDAoBxS+AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTExLTIwVDA1OjQ2OjI5LTA3OjAw/y2ntgAA
+AABJRU5ErkJggg==" />
+</svg>
diff --git a/MAINTAINERS b/MAINTAINERS
index 7600494..bcce963 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9860,6 +9860,7 @@ M:	Jerin Jacob <jerinj@marvell.com>
 L:	netdev@vger.kernel.org
 S:	Supported
 F:	drivers/net/ethernet/marvell/octeontx2/af/
+F:	Documentation/networking/device_drivers/marvell/octeontx2.rst
 
 MATROX FRAMEBUFFER DRIVER
 L:	linux-fbdev@vger.kernel.org
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-20 17:48 ` [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview sunil.kovvuri
@ 2019-11-21  0:41   ` Jakub Kicinski
  2019-11-21  2:49     ` Sunil Kovvuri
  0 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2019-11-21  0:41 UTC (permalink / raw)
  To: sunil.kovvuri; +Cc: netdev, davem, Sunil Goutham

On Wed, 20 Nov 2019 23:18:06 +0530, sunil.kovvuri@gmail.com wrote:
> From: Sunil Goutham <sgoutham@marvell.com>
> 
> Added high level overview of OcteonTx2 RVU HW and functionality of
> various drivers which will be upstreamed.
> 
> Signed-off-by: Sunil Goutham <sgoutham@marvell.com>

Please double check this renders the way you expect. You may want to
add empty lines before lists.

> diff --git a/Documentation/networking/device_drivers/index.rst b/Documentation/networking/device_drivers/index.rst
> index c1f7f75..8aba64b 100644
> --- a/Documentation/networking/device_drivers/index.rst
> +++ b/Documentation/networking/device_drivers/index.rst
> @@ -22,6 +22,7 @@ Contents:
>     intel/iavf
>     intel/ice
>     google/gve
> +   marvell/octeontx2
>     mellanox/mlx5
>     netronome/nfp
>     pensando/ionic
> diff --git a/Documentation/networking/device_drivers/marvell/octeontx2.rst b/Documentation/networking/device_drivers/marvell/octeontx2.rst
> new file mode 100644
> index 0000000..c8a5150
> --- /dev/null
> +++ b/Documentation/networking/device_drivers/marvell/octeontx2.rst
> @@ -0,0 +1,162 @@
> +.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +
> +=============================================
> +Marvell OcteonTx2 RVU Kernel Drivers
> +=============================================

Shouldn't these lines be the length of the text?

> +
> +Copyright (c) 2019 Marvell International Ltd.
> +
> +Contents
> +========
> +
> +- `Overview`_
> +- `Drivers`_
> +- `Basic packet flow`_
> +
> +Overview
> +========
> +Resource virtualization unit (RVU) on Marvell's OcteonTX2 SOC maps HW
> +resources from the network, crypto and other functional blocks into
> +PCI-compatible physical and virtual functions. Each functional block
> +again has multiple local functions (LFs) for provisioning to PCI devices.
> +RVU supports multiple PCIe SRIOV physical functions (PFs) and virtual
> +functions (VFs). PF0 is called the administrative / admin function (AF)
> +and has privileges to provision RVU functional block's LFs to each of the
> +PF/VF.
> +
> +RVU managed networking functional blocks
> + - Network pool or buffer allocator (NPA)
> + - Network interface controller (NIX)
> + - Network parser CAM (NPC)
> + - Schedule/Synchronize/Order unit (SSO)
> + - Loopback interface (LBK)
> +
> +RVU managed non-networking functional blocks
> + - Crypto accelerator (CPT)
> + - Scheduled timers unit (TIM)
> + - Schedule/Synchronize/Order unit (SSO)
> +   Used for both networking and non networking usecases
> +
> +Resource provisioning examples
> + - A PF/VF with NIX-LF & NPA-LF resources works as a pure network device
> + - A PF/VF with CPT-LF resource works as a pure cyrpto offload device.

s/cyrpto/crypto/

> +
> +.. kernel-figure::  resource_virtualization_unit.svg
> +   :alt:	RVU
> +   :align:	center
> +   :figwidth:	60em
> +
> +   RVU HW block connectivity

The diagram isn't really bringing much value if you ask me. The text in
the last section is quite a bit better. Perhaps show packet flow?

> +RVU functional blocks are highly configurable as per software requirements.
> +
> +Firmware setups following stuff before kernel boots
> + - Enables required number of RVU PFs based on number of physical links.
> + - Number of VFs per PF are either static or configurable at compile time.

compile time of the firmware?

> +   Based on config, firmware assigns VFs to each of the PFs.
> + - Also assigns MSIX vectors to each of PF and VFs.
> + - These are not changed after kernel boot.

Can they be changed without FW rebuild?

> +Drivers
> +=======
> +
> +Linux kernel will have multiple drivers registering to different PF and VFs
> +of RVU. Wrt networking there will be 3 flavours of drivers.
> +
> +Admin Function driver
> +---------------------

> +Physical Function driver
> +------------------------

Thanks for the description, I was hoping you'd also provide more info
on how the software componets of the system fit together. Today we only
have an AF driver upstream. Without the PF or VF drivers the card is
pretty much unusable with only the upstream drivers, right?

There is a bunch of cgx_* exports in the AF module, which seem to have
no uses upstream, too (they are only called from rvu_cgx.c which is
compiled into the same module).

We'd like to see you build up a self-sufficient upstream-only solution,
and adding more and more code to the AF driver with unused exports
doesn't really inspire confidence this is the direction.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-21  0:41   ` Jakub Kicinski
@ 2019-11-21  2:49     ` Sunil Kovvuri
  2019-11-21 18:43       ` Jakub Kicinski
  0 siblings, 1 reply; 24+ messages in thread
From: Sunil Kovvuri @ 2019-11-21  2:49 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: Linux Netdev List, David S. Miller, Sunil Goutham

On Thu, Nov 21, 2019 at 6:11 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
>
> Please double check this renders the way you expect. You may want to
> add empty lines before lists.

Okay, will recheck.

> > +
> > +=============================================
> > +Marvell OcteonTx2 RVU Kernel Drivers
> > +=============================================
>
> Shouldn't these lines be the length of the text?

Haven't done this documentation before, will other files and fix if necessary,

> > +
> > +Resource provisioning examples
> > + - A PF/VF with NIX-LF & NPA-LF resources works as a pure network device
> > + - A PF/VF with CPT-LF resource works as a pure cyrpto offload device.
>
> s/cyrpto/crypto/

Thanks, will fix.

> > +
> > +.. kernel-figure::  resource_virtualization_unit.svg
> > +   :alt:     RVU
> > +   :align:   center
> > +   :figwidth:        60em
> > +
> > +   RVU HW block connectivity
>
> The diagram isn't really bringing much value if you ask me. The text in
> the last section is quite a bit better. Perhaps show packet flow?

If someone doesn't want read the text fully, then i thought the
diagram would help
in getting an idea about the RVU HW block connectivity.

> > +Firmware setups following stuff before kernel boots
> > + - Enables required number of RVU PFs based on number of physical links.
> > + - Number of VFs per PF are either static or configurable at compile time.
>
> compile time of the firmware?

Yes, firmware.

>
> > +   Based on config, firmware assigns VFs to each of the PFs.
> > + - Also assigns MSIX vectors to each of PF and VFs.
> > + - These are not changed after kernel boot.
>
> Can they be changed without FW rebuild?

No, they cannot be.

>
> Thanks for the description, I was hoping you'd also provide more info
> on how the software componets of the system fit together. Today we only
> have an AF driver upstream. Without the PF or VF drivers the card is
> pretty much unusable with only the upstream drivers, right?
>

I will start submitting netdev drivers (PF and VF) right after this patchset.
And just FYI this is not a NIC card, this HW is found only on the ARM64
based OcteonTX2 SOC.

> There is a bunch of cgx_* exports in the AF module, which seem to have
> no uses upstream, too (they are only called from rvu_cgx.c which is
> compiled into the same module).

In the very first patchset submitted CGX and AF drivers were separate modules.
Based on suggestions we merged both of them into a single module.
The export symbols are not needed, i will submit a separate patch to
clean them up.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-21  2:49     ` Sunil Kovvuri
@ 2019-11-21 18:43       ` Jakub Kicinski
  2019-11-21 19:13         ` Sunil Kovvuri
  0 siblings, 1 reply; 24+ messages in thread
From: Jakub Kicinski @ 2019-11-21 18:43 UTC (permalink / raw)
  To: Sunil Kovvuri; +Cc: Linux Netdev List, David S. Miller, Sunil Goutham

On Thu, 21 Nov 2019 08:19:29 +0530, Sunil Kovvuri wrote:
> > Thanks for the description, I was hoping you'd also provide more info
> > on how the software componets of the system fit together. Today we only
> > have an AF driver upstream. Without the PF or VF drivers the card is
> > pretty much unusable with only the upstream drivers, right?
> 
> I will start submitting netdev drivers (PF and VF) right after this patchset.
> And just FYI this is not a NIC card, this HW is found only on the ARM64
> based OcteonTX2 SOC.

Right, that's kind of my point, it's not a simple NIC, so we want
to know what are all the software components. How does a real life
application make use of this HW.

Seems like your DPDK documentation lays that out pretty nicely:

https://doc.dpdk.org/guides/platform/octeontx2.html

It appears the data path components are supposed to be controlled by
DPDK.

After reading that DPDK documentation I feel like you'd need to do some
convincing to prove it makes sense to go forward with this AF driver at
all. For all practical purposes nobody will make use of this HW other
than through the DPDK-based SDK, so perhaps just keep your drivers in
the SDK and everyone will be happy?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-21 18:43       ` Jakub Kicinski
@ 2019-11-21 19:13         ` Sunil Kovvuri
  2019-11-21 19:23           ` Jakub Kicinski
  0 siblings, 1 reply; 24+ messages in thread
From: Sunil Kovvuri @ 2019-11-21 19:13 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: Linux Netdev List, David S. Miller, Sunil Goutham

On Fri, Nov 22, 2019 at 12:13 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Thu, 21 Nov 2019 08:19:29 +0530, Sunil Kovvuri wrote:
> > > Thanks for the description, I was hoping you'd also provide more info
> > > on how the software componets of the system fit together. Today we only
> > > have an AF driver upstream. Without the PF or VF drivers the card is
> > > pretty much unusable with only the upstream drivers, right?
> >
> > I will start submitting netdev drivers (PF and VF) right after this patchset.
> > And just FYI this is not a NIC card, this HW is found only on the ARM64
> > based OcteonTX2 SOC.
>
> Right, that's kind of my point, it's not a simple NIC, so we want
> to know what are all the software components. How does a real life
> application make use of this HW.
>
> Seems like your DPDK documentation lays that out pretty nicely:
>
> https://doc.dpdk.org/guides/platform/octeontx2.html
>
> It appears the data path components are supposed to be controlled by
> DPDK.
>
> After reading that DPDK documentation I feel like you'd need to do some
> convincing to prove it makes sense to go forward with this AF driver at
> all. For all practical purposes nobody will make use of this HW other
> than through the DPDK-based SDK, so perhaps just keep your drivers in
> the SDK and everyone will be happy?

Based on what you concluded that nobody would use the HW otherthan with DPDK ?

Just because it's not a NIC, it doesn't mean it cannot be used with
applications otherthan DPDK.
Imagine a server (on the lines of Intel xeon) with on-chip NIC instead
of a external PCIe NIC.
A server machine is used for lots of workload applications which are
not DPDK based.
Marvell's ThunderX machine is one such example,
- It is an SoC with an on-chip NIC.
- Both kernel and DPDK network drivers are upstreamed.
  kernel: drivers/net/ethernet/cavium/thunder
  DPDK: https://doc.dpdk.org/guides/nics/thunderx.html

Even for a DPDK only application, there is still a management ethernet
needed to which user can do ssh etc
when there is no console available. And there is no need to supply
whole SDK to customer, just supply
firmware, get latest kernel and DPDK from mainline and use it.

Sorry, i don't understand why a driver for on-chip ethernet cannot be
upstreamed.

Thanks,
Sunil.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-21 19:13         ` Sunil Kovvuri
@ 2019-11-21 19:23           ` Jakub Kicinski
  2019-11-21 19:45             ` Sunil Kovvuri
  2019-11-21 20:17             ` David Miller
  0 siblings, 2 replies; 24+ messages in thread
From: Jakub Kicinski @ 2019-11-21 19:23 UTC (permalink / raw)
  To: Sunil Kovvuri; +Cc: Linux Netdev List, David S. Miller, Sunil Goutham

On Fri, 22 Nov 2019 00:43:14 +0530, Sunil Kovvuri wrote:
> On Fri, Nov 22, 2019 at 12:13 AM Jakub Kicinski wrote:
> > On Thu, 21 Nov 2019 08:19:29 +0530, Sunil Kovvuri wrote:  
> > > > Thanks for the description, I was hoping you'd also provide more info
> > > > on how the software componets of the system fit together. Today we only
> > > > have an AF driver upstream. Without the PF or VF drivers the card is
> > > > pretty much unusable with only the upstream drivers, right?  
> > >
> > > I will start submitting netdev drivers (PF and VF) right after this patchset.
> > > And just FYI this is not a NIC card, this HW is found only on the ARM64
> > > based OcteonTX2 SOC.  
> >
> > Right, that's kind of my point, it's not a simple NIC, so we want
> > to know what are all the software components. How does a real life
> > application make use of this HW.
> >
> > Seems like your DPDK documentation lays that out pretty nicely:
> >
> > https://doc.dpdk.org/guides/platform/octeontx2.html
> >
> > It appears the data path components are supposed to be controlled by
> > DPDK.
> >
> > After reading that DPDK documentation I feel like you'd need to do some
> > convincing to prove it makes sense to go forward with this AF driver at
> > all. For all practical purposes nobody will make use of this HW other
> > than through the DPDK-based SDK, so perhaps just keep your drivers in
> > the SDK and everyone will be happy?  
> 
> Based on what you concluded that nobody would use the HW otherthan with DPDK ?

Based on the fact that you only have a DPDK SDK for it?

> Just because it's not a NIC, it doesn't mean it cannot be used with
> applications otherthan DPDK.
> Imagine a server (on the lines of Intel xeon) with on-chip NIC instead
> of a external PCIe NIC.
> A server machine is used for lots of workload applications which are
> not DPDK based.
> Marvell's ThunderX machine is one such example,
> - It is an SoC with an on-chip NIC.
> - Both kernel and DPDK network drivers are upstreamed.
>   kernel: drivers/net/ethernet/cavium/thunder
>   DPDK: https://doc.dpdk.org/guides/nics/thunderx.html

Are you saying someone will use a Octeon as just an ARM
server? Seriously someone will buy an NPU and use it for
something else than network processing? 

> Even for a DPDK only application, there is still a management ethernet
> needed to which user can do ssh etc
> when there is no console available. And there is no need to supply
> whole SDK to customer, just supply
> firmware, get latest kernel and DPDK from mainline and use it.
> 
> Sorry, i don't understand why a driver for on-chip ethernet cannot be
> upstreamed.

Well you didn't bother to upstream it until now. You're just pushing
admin parts of your DPDK solution. Can you honestly be surprised the
upstream netdev community doesn't like that?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-21 19:23           ` Jakub Kicinski
@ 2019-11-21 19:45             ` Sunil Kovvuri
  2019-11-21 20:17             ` David Miller
  1 sibling, 0 replies; 24+ messages in thread
From: Sunil Kovvuri @ 2019-11-21 19:45 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: Linux Netdev List, David S. Miller, Sunil Goutham

On Fri, Nov 22, 2019 at 12:53 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:

> > > It appears the data path components are supposed to be controlled by
> > > DPDK.
> > >
> > > After reading that DPDK documentation I feel like you'd need to do some
> > > convincing to prove it makes sense to go forward with this AF driver at
> > > all. For all practical purposes nobody will make use of this HW other
> > > than through the DPDK-based SDK, so perhaps just keep your drivers in
> > > the SDK and everyone will be happy?
> >
> > Based on what you concluded that nobody would use the HW otherthan with DPDK ?
>
> Based on the fact that you only have a DPDK SDK for it?

Again how do you know there is only DPDK SDK available with us ?
Just by reading DPDK documentation, is it right to conclude that way.

>
> > Just because it's not a NIC, it doesn't mean it cannot be used with
> > applications otherthan DPDK.
> > Imagine a server (on the lines of Intel xeon) with on-chip NIC instead
> > of a external PCIe NIC.
> > A server machine is used for lots of workload applications which are
> > not DPDK based.
> > Marvell's ThunderX machine is one such example,
> > - It is an SoC with an on-chip NIC.
> > - Both kernel and DPDK network drivers are upstreamed.
> >   kernel: drivers/net/ethernet/cavium/thunder
> >   DPDK: https://doc.dpdk.org/guides/nics/thunderx.html
>
> Are you saying someone will use a Octeon as just an ARM
> server? Seriously someone will buy an NPU and use it for
> something else than network processing?

If a Intel machine with external NIC can be used for something otherthan
pure network processing, then why can't this. I am not saying this is 'the'
intended application, just giving an example of the previous silicon
with on-chip NIC.

There are many other things, can use it for NFVs, containers, virtual machines
with PF (netdev) in kernel and VFs in userspace. There are many real
life applications.

>
> > Even for a DPDK only application, there is still a management ethernet
> > needed to which user can do ssh etc
> > when there is no console available. And there is no need to supply
> > whole SDK to customer, just supply
> > firmware, get latest kernel and DPDK from mainline and use it.
> >
> > Sorry, i don't understand why a driver for on-chip ethernet cannot be
> > upstreamed.
>
> Well you didn't bother to upstream it until now. You're just pushing
> admin parts of your DPDK solution. Can you honestly be surprised the
> upstream netdev community doesn't like that?

Yes, I am very well aware of the fact that upstream netdev community
doesn't like DPDK.
I did attend couple of netdev conferences where it was loudly said
"DPDK is not kernel" :-)

And yes I agree there was a long gap in between, but this time i am
going to publish PF/VF netdev drivers.

Thanks,
Sunil.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview.
  2019-11-21 19:23           ` Jakub Kicinski
  2019-11-21 19:45             ` Sunil Kovvuri
@ 2019-11-21 20:17             ` David Miller
  1 sibling, 0 replies; 24+ messages in thread
From: David Miller @ 2019-11-21 20:17 UTC (permalink / raw)
  To: jakub.kicinski; +Cc: sunil.kovvuri, netdev, sgoutham

From: Jakub Kicinski <jakub.kicinski@netronome.com>
Date: Thu, 21 Nov 2019 11:23:35 -0800

> Well you didn't bother to upstream it until now. You're just pushing
> admin parts of your DPDK solution. Can you honestly be surprised the
> upstream netdev community doesn't like that?

I agree with Jakub, this is a serious problem and the whole premise of
the code being upstreamed is not acceptable.

I'm going to look really strictly at octeon submissions from this point
forward, as I'm really disappointed in what is going on here.

I will have to see explicit explanations clearly showing how upstream
usage of the driver will be done, no DPDK only stuff, no SDK only
situations, none of that.  It's simply unacceptable.

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2019-11-21 20:17 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-20 17:47 [PATCH v3 00/16] octeontx2-af: SSO, TIM HW blocks and other config support sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 01/16] octeontx2-af: Interface backpressure configuration support sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 02/16] octeontx2-af: Add support for importing firmware data sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 03/16] octeontx2-af: Cleanup CGX config permission checks sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 04/16] octeontx2-af: Ingress and egress pause frame configuration sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 05/16] octeontx2-af: Set discovery ID for RVUM block sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 06/16] octeontx2-af: add debug msgs for NPA block errors sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 07/16] octeontx2-af: add debug msgs for NIX " sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 08/16] octeontx2-af: Add SSO unit support to the AF driver sunil.kovvuri
2019-11-20 17:47 ` [PATCH v3 09/16] octeontx2-af: Config support for per HWGRP thresholds sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 10/16] octeontx2-af: add debug msgs for SSO block errors sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 11/16] octeontx2-af: add debugfs support for sso sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 12/16] octeontx2-af: Add TIM unit support sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 13/16] octeontx2-af: verify ingress channel in MCAM entry sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 14/16] octeontx2-af: NPC Tx parsed data key extraction profile sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 15/16] octeontx2-af: Support to get CGX link info like current speed, fec etc sunil.kovvuri
2019-11-20 17:48 ` [PATCH v3 16/16] Documentation: net: octeontx2: Add RVU HW and drivers overview sunil.kovvuri
2019-11-21  0:41   ` Jakub Kicinski
2019-11-21  2:49     ` Sunil Kovvuri
2019-11-21 18:43       ` Jakub Kicinski
2019-11-21 19:13         ` Sunil Kovvuri
2019-11-21 19:23           ` Jakub Kicinski
2019-11-21 19:45             ` Sunil Kovvuri
2019-11-21 20:17             ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).