Commit a3280efd authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'octeon-drr-config'



Sunil Goutham says:

====================
cn10k: DWRR MTU and weights configuration

On OcteonTx2 DWRR quantum is directly configured into each of
the transmit scheduler queues. And PF/VF drivers were free to
config any value upto 2^24.

On CN10K, HW is modified, the quantum configuration at scheduler
queues is in terms of weight. And SW needs to setup a base DWRR MTU
at NIX_AF_DWRR_RPM_MTU / NIX_AF_DWRR_SDP_MTU. HW will do
'DWRR MTU * weight' to get the quantum.

This patch series addresses this HW change on CN10K silicons,
both admin function and PF/VF drivers are modified.

Also added support to program DWRR MTU via devlink params.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cfba3fb6 c39830a4
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -146,10 +146,7 @@ enum nix_scheduler {
#define TXSCH_RR_QTM_MAX		((1 << 24) - 1)
#define TXSCH_TL1_DFLT_RR_QTM		TXSCH_RR_QTM_MAX
#define TXSCH_TL1_DFLT_RR_PRIO		(0x1ull)
#define MAX_SCHED_WEIGHT		0xFF
#define DFLT_RR_WEIGHT			71
#define DFLT_RR_QTM	((DFLT_RR_WEIGHT * TXSCH_RR_QTM_MAX) \
			 / MAX_SCHED_WEIGHT)
#define CN10K_MAX_DWRR_WEIGHT          16384 /* Weight is 14bit on CN10K */

/* Min/Max packet sizes, excluding FCS */
#define	NIC_HW_MIN_FRS			40
+4 −0
Original line number Diff line number Diff line
@@ -1032,8 +1032,12 @@ struct nix_bp_cfg_rsp {

struct nix_hw_info {
	struct mbox_msghdr hdr;
	u16 rsvs16;
	u16 max_mtu;
	u16 min_mtu;
	u32 rpm_dwrr_mtu;
	u32 sdp_dwrr_mtu;
	u64 rsvd[16]; /* Add reserved fields for future expansion */
};

struct nix_bandprof_alloc_req {
+3 −0
Original line number Diff line number Diff line
@@ -329,6 +329,7 @@ struct hw_cap {
	bool	nix_shaping;		 /* Is shaping and coloring supported */
	bool	nix_tx_link_bp;		 /* Can link backpressure TL queues ? */
	bool	nix_rx_multicast;	 /* Rx packet replication support */
	bool	nix_common_dwrr_mtu;	 /* Common DWRR MTU for quantum config */
	bool	per_pf_mbox_regs; /* PF mbox specified in per PF registers ? */
	bool	programmable_chans; /* Channels programmable ? */
	bool	ipolicer;
@@ -706,6 +707,8 @@ int nix_aq_context_read(struct rvu *rvu, struct nix_hw *nix_hw,
			struct nix_cn10k_aq_enq_rsp *aq_rsp,
			u16 pcifunc, u8 ctype, u32 qidx);
int rvu_get_nix_blkaddr(struct rvu *rvu, u16 pcifunc);
u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu);
u32 convert_bytes_to_dwrr_mtu(u32 bytes);

/* NPC APIs */
int rvu_npc_init(struct rvu *rvu);
+109 −1
Original line number Diff line number Diff line
@@ -1364,6 +1364,89 @@ static void rvu_health_reporters_destroy(struct rvu *rvu)
	rvu_nix_health_reporters_destroy(rvu_dl);
}

/* Devlink Params APIs */
static int rvu_af_dl_dwrr_mtu_validate(struct devlink *devlink, u32 id,
				       union devlink_param_value val,
				       struct netlink_ext_ack *extack)
{
	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
	struct rvu *rvu = rvu_dl->rvu;
	int dwrr_mtu = val.vu32;
	struct nix_txsch *txsch;
	struct nix_hw *nix_hw;

	if (!rvu->hw->cap.nix_common_dwrr_mtu) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Setting DWRR_MTU is not supported on this silicon");
		return -EOPNOTSUPP;
	}

	if ((dwrr_mtu > 65536 || !is_power_of_2(dwrr_mtu)) &&
	    (dwrr_mtu != 9728 && dwrr_mtu != 10240)) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Invalid, supported MTUs are 0,2,4,8.16,32,64....4K,8K,32K,64K and 9728, 10240");
		return -EINVAL;
	}

	nix_hw = get_nix_hw(rvu->hw, BLKADDR_NIX0);
	if (!nix_hw)
		return -ENODEV;

	txsch = &nix_hw->txsch[NIX_TXSCH_LVL_SMQ];
	if (rvu_rsrc_free_count(&txsch->schq) != txsch->schq.max) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Changing DWRR MTU is not supported when there are active NIXLFs");
		NL_SET_ERR_MSG_MOD(extack,
				   "Makesure none of the PF/VF interfaces are initialized and retry");
		return -EOPNOTSUPP;
	}

	return 0;
}

static int rvu_af_dl_dwrr_mtu_set(struct devlink *devlink, u32 id,
				  struct devlink_param_gset_ctx *ctx)
{
	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
	struct rvu *rvu = rvu_dl->rvu;
	u64 dwrr_mtu;

	dwrr_mtu = convert_bytes_to_dwrr_mtu(ctx->val.vu32);
	rvu_write64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_RPM_MTU, dwrr_mtu);

	return 0;
}

static int rvu_af_dl_dwrr_mtu_get(struct devlink *devlink, u32 id,
				  struct devlink_param_gset_ctx *ctx)
{
	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
	struct rvu *rvu = rvu_dl->rvu;
	u64 dwrr_mtu;

	if (!rvu->hw->cap.nix_common_dwrr_mtu)
		return -EOPNOTSUPP;

	dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_RPM_MTU);
	ctx->val.vu32 = convert_dwrr_mtu_to_bytes(dwrr_mtu);

	return 0;
}

enum rvu_af_dl_param_id {
	RVU_AF_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
	RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU,
};

static const struct devlink_param rvu_af_dl_params[] = {
	DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU,
			     "dwrr_mtu", DEVLINK_PARAM_TYPE_U32,
			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
			     rvu_af_dl_dwrr_mtu_get, rvu_af_dl_dwrr_mtu_set,
			     rvu_af_dl_dwrr_mtu_validate),
};

/* Devlink switch mode */
static int rvu_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
{
	struct rvu_devlink *rvu_dl = devlink_priv(devlink);
@@ -1438,7 +1521,30 @@ int rvu_register_dl(struct rvu *rvu)
	rvu_dl->rvu = rvu;
	rvu->rvu_dl = rvu_dl;

	return rvu_health_reporters_create(rvu);
	err = rvu_health_reporters_create(rvu);
	if (err) {
		dev_err(rvu->dev,
			"devlink health reporter creation failed with error %d\n", err);
		goto err_dl_health;
	}

	err = devlink_params_register(dl, rvu_af_dl_params,
				      ARRAY_SIZE(rvu_af_dl_params));
	if (err) {
		dev_err(rvu->dev,
			"devlink params register failed with error %d", err);
		goto err_dl_health;
	}

	devlink_params_publish(dl);

	return 0;

err_dl_health:
	rvu_health_reporters_destroy(rvu);
	devlink_unregister(dl);
	devlink_free(dl);
	return err;
}

void rvu_unregister_dl(struct rvu *rvu)
@@ -1449,6 +1555,8 @@ void rvu_unregister_dl(struct rvu *rvu)
	if (!dl)
		return;

	devlink_params_unregister(dl, rvu_af_dl_params,
				  ARRAY_SIZE(rvu_af_dl_params));
	rvu_health_reporters_destroy(rvu);
	devlink_unregister(dl);
	devlink_free(dl);
+101 −2
Original line number Diff line number Diff line
@@ -192,6 +192,47 @@ struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr)
	return NULL;
}

u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu)
{
	dwrr_mtu &= 0x1FULL;

	/* MTU used for DWRR calculation is in power of 2 up until 64K bytes.
	 * Value of 4 is reserved for MTU value of 9728 bytes.
	 * Value of 5 is reserved for MTU value of 10240 bytes.
	 */
	switch (dwrr_mtu) {
	case 4:
		return 9728;
	case 5:
		return 10240;
	default:
		return BIT_ULL(dwrr_mtu);
	}

	return 0;
}

u32 convert_bytes_to_dwrr_mtu(u32 bytes)
{
	/* MTU used for DWRR calculation is in power of 2 up until 64K bytes.
	 * Value of 4 is reserved for MTU value of 9728 bytes.
	 * Value of 5 is reserved for MTU value of 10240 bytes.
	 */
	if (bytes > BIT_ULL(16))
		return 0;

	switch (bytes) {
	case 9728:
		return 4;
	case 10240:
		return 5;
	default:
		return ilog2(bytes);
	}

	return 0;
}

static void nix_rx_sync(struct rvu *rvu, int blkaddr)
{
	int err;
@@ -1958,8 +1999,17 @@ static void nix_tl1_default_cfg(struct rvu *rvu, struct nix_hw *nix_hw,
		return;
	rvu_write64(rvu, blkaddr, NIX_AF_TL1X_TOPOLOGY(schq),
		    (TXSCH_TL1_DFLT_RR_PRIO << 1));

	/* On OcteonTx2 the config was in bytes and newer silcons
	 * it's changed to weight.
	 */
	if (!rvu->hw->cap.nix_common_dwrr_mtu)
		rvu_write64(rvu, blkaddr, NIX_AF_TL1X_SCHEDULE(schq),
			    TXSCH_TL1_DFLT_RR_QTM);
	else
		rvu_write64(rvu, blkaddr, NIX_AF_TL1X_SCHEDULE(schq),
			    CN10K_MAX_DWRR_WEIGHT);

	rvu_write64(rvu, blkaddr, NIX_AF_TL1X_CIR(schq), 0x00);
	pfvf_map[schq] = TXSCH_SET_FLAG(pfvf_map[schq], NIX_TXSCHQ_CFG_DONE);
}
@@ -2667,6 +2717,15 @@ static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
		for (schq = 0; schq < txsch->schq.max; schq++)
			txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE);
	}

	/* Setup a default value of 8192 as DWRR MTU */
	if (rvu->hw->cap.nix_common_dwrr_mtu) {
		rvu_write64(rvu, blkaddr, NIX_AF_DWRR_RPM_MTU,
			    convert_bytes_to_dwrr_mtu(8192));
		rvu_write64(rvu, blkaddr, NIX_AF_DWRR_SDP_MTU,
			    convert_bytes_to_dwrr_mtu(8192));
	}

	return 0;
}

@@ -2743,6 +2802,7 @@ int rvu_mbox_handler_nix_get_hw_info(struct rvu *rvu, struct msg_req *req,
				     struct nix_hw_info *rsp)
{
	u16 pcifunc = req->hdr.pcifunc;
	u64 dwrr_mtu;
	int blkaddr;

	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
@@ -2755,6 +2815,20 @@ int rvu_mbox_handler_nix_get_hw_info(struct rvu *rvu, struct msg_req *req,
		rvu_get_lmac_link_max_frs(rvu, &rsp->max_mtu);

	rsp->min_mtu = NIC_HW_MIN_FRS;

	if (!rvu->hw->cap.nix_common_dwrr_mtu) {
		/* Return '1' on OTx2 */
		rsp->rpm_dwrr_mtu = 1;
		rsp->sdp_dwrr_mtu = 1;
		return 0;
	}

	dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_RPM_MTU);
	rsp->rpm_dwrr_mtu = convert_dwrr_mtu_to_bytes(dwrr_mtu);

	dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_SDP_MTU);
	rsp->sdp_dwrr_mtu = convert_dwrr_mtu_to_bytes(dwrr_mtu);

	return 0;
}

@@ -3647,6 +3721,28 @@ static int nix_aq_init(struct rvu *rvu, struct rvu_block *block)
	return 0;
}

static void rvu_nix_setup_capabilities(struct rvu *rvu, int blkaddr)
{
	struct rvu_hwinfo *hw = rvu->hw;
	u64 hw_const;

	hw_const = rvu_read64(rvu, blkaddr, NIX_AF_CONST1);

	/* On OcteonTx2 DWRR quantum is directly configured into each of
	 * the transmit scheduler queues. And PF/VF drivers were free to
	 * config any value upto 2^24.
	 * On CN10K, HW is modified, the quantum configuration at scheduler
	 * queues is in terms of weight. And SW needs to setup a base DWRR MTU
	 * at NIX_AF_DWRR_RPM_MTU / NIX_AF_DWRR_SDP_MTU. HW will do
	 * 'DWRR MTU * weight' to get the quantum.
	 *
	 * Check if HW uses a common MTU for all DWRR quantum configs.
	 * On OcteonTx2 this register field is '0'.
	 */
	if (((hw_const >> 56) & 0x10) == 0x10)
		hw->cap.nix_common_dwrr_mtu = true;
}

static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw)
{
	const struct npc_lt_def_cfg *ltdefs;
@@ -3684,6 +3780,9 @@ static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw)
	if (err)
		return err;

	/* Setup capabilities of the NIX block */
	rvu_nix_setup_capabilities(rvu, blkaddr);

	/* Initialize admin queue */
	err = nix_aq_init(rvu, block);
	if (err)
Loading