diff --git a/drivers/net/octeontx2/otx2_tm.c b/drivers/net/octeontx2/otx2_tm.c
index f94618d..fa7d21b 100644
--- a/drivers/net/octeontx2/otx2_tm.c
+++ b/drivers/net/octeontx2/otx2_tm.c
@@ -336,18 +336,25 @@ prepare_tm_shaper_reg(struct otx2_nix_tm_node *tm_node,
 {
 	struct shaper_params cir, pir;
 	uint32_t schq = tm_node->hw_id;
+	uint64_t adjust = 0;
 	uint8_t k = 0;
 
 	memset(&cir, 0, sizeof(cir));
 	memset(&pir, 0, sizeof(pir));
 	shaper_config_to_nix(profile, &cir, &pir);
 
-	otx2_tm_dbg("Shaper config node %s(%u) lvl %u id %u, "
-		    "pir %" PRIu64 "(%" PRIu64 "B),"
-		     " cir %" PRIu64 "(%" PRIu64 "B) (%p)",
-		     nix_hwlvl2str(tm_node->hw_lvl), schq, tm_node->lvl,
-		     tm_node->id, pir.rate, pir.burst,
-		     cir.rate, cir.burst, tm_node);
+	/* Packet length adjust */
+	if (tm_node->pkt_mode)
+		adjust = 1;
+	else if (profile)
+		adjust = profile->params.pkt_length_adjust & 0x1FF;
+
+	otx2_tm_dbg("Shaper config node %s(%u) lvl %u id %u, pir %" PRIu64
+		    "(%" PRIu64 "B), cir %" PRIu64 "(%" PRIu64 "B)"
+		    "adjust 0x%" PRIx64 "(pktmode %u) (%p)",
+		    nix_hwlvl2str(tm_node->hw_lvl), schq, tm_node->lvl,
+		    tm_node->id, pir.rate, pir.burst, cir.rate, cir.burst,
+		    adjust, tm_node->pkt_mode, tm_node);
 
 	switch (tm_node->hw_lvl) {
 	case NIX_TXSCH_LVL_SMQ:
@@ -364,7 +371,9 @@ prepare_tm_shaper_reg(struct otx2_nix_tm_node *tm_node,
 
 		/* Configure RED ALG */
 		reg[k] = NIX_AF_MDQX_SHAPE(schq);
-		regval[k] = ((uint64_t)tm_node->red_algo << 9);
+		regval[k] = (adjust |
+			     (uint64_t)tm_node->red_algo << 9 |
+			     (uint64_t)tm_node->pkt_mode << 24);
 		k++;
 		break;
 	case NIX_TXSCH_LVL_TL4:
@@ -381,7 +390,9 @@ prepare_tm_shaper_reg(struct otx2_nix_tm_node *tm_node,
 
 		/* Configure RED algo */
 		reg[k] = NIX_AF_TL4X_SHAPE(schq);
-		regval[k] = ((uint64_t)tm_node->red_algo << 9);
+		regval[k] = (adjust |
+			     (uint64_t)tm_node->red_algo << 9 |
+			     (uint64_t)tm_node->pkt_mode << 24);
 		k++;
 		break;
 	case NIX_TXSCH_LVL_TL3:
@@ -398,7 +409,9 @@ prepare_tm_shaper_reg(struct otx2_nix_tm_node *tm_node,
 
 		/* Configure RED algo */
 		reg[k] = NIX_AF_TL3X_SHAPE(schq);
-		regval[k] = ((uint64_t)tm_node->red_algo << 9);
+		regval[k] = (adjust |
+			     (uint64_t)tm_node->red_algo << 9 |
+			     (uint64_t)tm_node->pkt_mode << 24);
 		k++;
 
 		break;
@@ -416,7 +429,9 @@ prepare_tm_shaper_reg(struct otx2_nix_tm_node *tm_node,
 
 		/* Configure RED algo */
 		reg[k] = NIX_AF_TL2X_SHAPE(schq);
-		regval[k] = ((uint64_t)tm_node->red_algo << 9);
+		regval[k] = (adjust |
+			     (uint64_t)tm_node->red_algo << 9 |
+			     (uint64_t)tm_node->pkt_mode << 24);
 		k++;
 
 		break;
@@ -426,6 +441,12 @@ prepare_tm_shaper_reg(struct otx2_nix_tm_node *tm_node,
 		regval[k] = (cir.rate && cir.burst) ?
 				(shaper2regval(&cir) | 1) : 0;
 		k++;
+
+		/* Configure length disable and adjust */
+		reg[k] = NIX_AF_TL1X_SHAPE(schq);
+		regval[k] = (adjust |
+			     (uint64_t)tm_node->pkt_mode << 24);
+		k++;
 		break;
 	}
 
@@ -773,6 +794,15 @@ nix_tm_node_add_to_list(struct otx2_eth_dev *dev, uint32_t node_id,
 	tm_node->flags = 0;
 	if (user)
 		tm_node->flags = NIX_TM_NODE_USER;
+
+	/* Packet mode */
+	if (!nix_tm_is_leaf(dev, lvl) &&
+	    ((profile && profile->params.packet_mode) ||
+	     (params->nonleaf.wfq_weight_mode &&
+	      params->nonleaf.n_sp_priorities &&
+	      !params->nonleaf.wfq_weight_mode[0])))
+		tm_node->pkt_mode = 1;
+
 	rte_memcpy(&tm_node->params, params, sizeof(struct rte_tm_node_params));
 
 	if (profile)
@@ -1873,8 +1903,10 @@ otx2_nix_tm_capa_get(struct rte_eth_dev *eth_dev,
 	cap->shaper_private_dual_rate_n_max = max_nr_nodes;
 	cap->shaper_private_rate_min = MIN_SHAPER_RATE / 8;
 	cap->shaper_private_rate_max = MAX_SHAPER_RATE / 8;
-	cap->shaper_pkt_length_adjust_min = 0;
-	cap->shaper_pkt_length_adjust_max = 0;
+	cap->shaper_private_packet_mode_supported = 1;
+	cap->shaper_private_byte_mode_supported = 1;
+	cap->shaper_pkt_length_adjust_min = NIX_LENGTH_ADJUST_MIN;
+	cap->shaper_pkt_length_adjust_max = NIX_LENGTH_ADJUST_MAX;
 
 	/* Schedule Capabilities */
 	cap->sched_n_children_max = rsp->schq[NIX_TXSCH_LVL_MDQ];
@@ -1882,6 +1914,8 @@ otx2_nix_tm_capa_get(struct rte_eth_dev *eth_dev,
 	cap->sched_wfq_n_children_per_group_max = cap->sched_n_children_max;
 	cap->sched_wfq_n_groups_max = 1;
 	cap->sched_wfq_weight_max = MAX_SCHED_WEIGHT;
+	cap->sched_wfq_packet_mode_supported = 1;
+	cap->sched_wfq_byte_mode_supported = 1;
 
 	cap->dynamic_update_mask =
 		RTE_TM_UPDATE_NODE_PARENT_KEEP_LEVEL |
@@ -1944,12 +1978,16 @@ otx2_nix_tm_level_capa_get(struct rte_eth_dev *eth_dev, uint32_t lvl,
 			nix_tm_have_tl1_access(dev) ? false : true;
 		cap->nonleaf.shaper_private_rate_min = MIN_SHAPER_RATE / 8;
 		cap->nonleaf.shaper_private_rate_max = MAX_SHAPER_RATE / 8;
+		cap->nonleaf.shaper_private_packet_mode_supported = 1;
+		cap->nonleaf.shaper_private_byte_mode_supported = 1;
 
 		cap->nonleaf.sched_n_children_max = rsp->schq[hw_lvl - 1];
 		cap->nonleaf.sched_sp_n_priorities_max =
 					nix_max_prio(dev, hw_lvl) + 1;
 		cap->nonleaf.sched_wfq_n_groups_max = 1;
 		cap->nonleaf.sched_wfq_weight_max = MAX_SCHED_WEIGHT;
+		cap->nonleaf.sched_wfq_packet_mode_supported = 1;
+		cap->nonleaf.sched_wfq_byte_mode_supported = 1;
 
 		if (nix_tm_have_tl1_access(dev))
 			cap->nonleaf.stats_mask =
@@ -1966,6 +2004,8 @@ otx2_nix_tm_level_capa_get(struct rte_eth_dev *eth_dev, uint32_t lvl,
 		cap->nonleaf.shaper_private_dual_rate_supported = true;
 		cap->nonleaf.shaper_private_rate_min = MIN_SHAPER_RATE / 8;
 		cap->nonleaf.shaper_private_rate_max = MAX_SHAPER_RATE / 8;
+		cap->nonleaf.shaper_private_packet_mode_supported = 1;
+		cap->nonleaf.shaper_private_byte_mode_supported = 1;
 
 		/* MDQ doesn't support Strict Priority */
 		if (hw_lvl == NIX_TXSCH_LVL_MDQ)
@@ -1977,6 +2017,8 @@ otx2_nix_tm_level_capa_get(struct rte_eth_dev *eth_dev, uint32_t lvl,
 			nix_max_prio(dev, hw_lvl) + 1;
 		cap->nonleaf.sched_wfq_n_groups_max = 1;
 		cap->nonleaf.sched_wfq_weight_max = MAX_SCHED_WEIGHT;
+		cap->nonleaf.sched_wfq_packet_mode_supported = 1;
+		cap->nonleaf.sched_wfq_byte_mode_supported = 1;
 	} else {
 		/* unsupported level */
 		error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
@@ -2029,6 +2071,8 @@ otx2_nix_tm_node_capa_get(struct rte_eth_dev *eth_dev, uint32_t node_id,
 		(hw_lvl == NIX_TXSCH_LVL_TL1) ? false : true;
 	cap->shaper_private_rate_min = MIN_SHAPER_RATE / 8;
 	cap->shaper_private_rate_max = MAX_SHAPER_RATE / 8;
+	cap->shaper_private_packet_mode_supported = 1;
+	cap->shaper_private_byte_mode_supported = 1;
 
 	/* Non Leaf Scheduler */
 	if (hw_lvl == NIX_TXSCH_LVL_MDQ)
@@ -2041,6 +2085,8 @@ otx2_nix_tm_node_capa_get(struct rte_eth_dev *eth_dev, uint32_t node_id,
 		cap->nonleaf.sched_n_children_max;
 	cap->nonleaf.sched_wfq_n_groups_max = 1;
 	cap->nonleaf.sched_wfq_weight_max = MAX_SCHED_WEIGHT;
+	cap->nonleaf.sched_wfq_packet_mode_supported = 1;
+	cap->nonleaf.sched_wfq_byte_mode_supported = 1;
 
 	if (hw_lvl == NIX_TXSCH_LVL_TL1)
 		cap->stats_mask = RTE_TM_STATS_N_PKTS_RED_DROPPED |
@@ -2096,6 +2142,13 @@ otx2_nix_tm_shaper_profile_add(struct rte_eth_dev *eth_dev,
 		}
 	}
 
+	if (params->pkt_length_adjust < NIX_LENGTH_ADJUST_MIN ||
+	    params->pkt_length_adjust > NIX_LENGTH_ADJUST_MAX) {
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;
+		error->message = "length adjust invalid";
+		return -EINVAL;
+	}
+
 	profile = rte_zmalloc("otx2_nix_tm_shaper_profile",
 			      sizeof(struct otx2_nix_tm_shaper_profile), 0);
 	if (!profile)
@@ -2108,13 +2161,14 @@ otx2_nix_tm_shaper_profile_add(struct rte_eth_dev *eth_dev,
 
 	otx2_tm_dbg("Added TM shaper profile %u, "
 		    " pir %" PRIu64 " , pbs %" PRIu64 ", cir %" PRIu64
-		    ", cbs %" PRIu64 " , adj %u",
+		    ", cbs %" PRIu64 " , adj %u, pkt mode %d",
 		    profile_id,
 		    params->peak.rate * 8,
 		    params->peak.size,
 		    params->committed.rate * 8,
 		    params->committed.size,
-		    params->pkt_length_adjust);
+		    params->pkt_length_adjust,
+		    params->packet_mode);
 
 	/* Translate rate as bits per second */
 	profile->params.peak.rate = profile->params.peak.rate * 8;
@@ -2170,9 +2224,11 @@ otx2_nix_tm_node_add(struct rte_eth_dev *eth_dev, uint32_t node_id,
 		     struct rte_tm_error *error)
 {
 	struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev);
+	struct otx2_nix_tm_shaper_profile *profile = NULL;
 	struct otx2_nix_tm_node *parent_node;
-	int rc, clear_on_fail = 0;
-	uint32_t exp_next_lvl;
+	int rc, pkt_mode, clear_on_fail = 0;
+	uint32_t exp_next_lvl, i;
+	uint32_t profile_id;
 	uint16_t hw_lvl;
 
 	/* we don't support dynamic updates */
@@ -2234,13 +2290,45 @@ otx2_nix_tm_node_add(struct rte_eth_dev *eth_dev, uint32_t node_id,
 		return -EINVAL;
 	}
 
-	/* Check if shaper profile exists for non leaf node */
-	if (!nix_tm_is_leaf(dev, lvl) &&
-	    params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE &&
-	    !nix_tm_shaper_profile_search(dev, params->shaper_profile_id)) {
-		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
-		error->message = "invalid shaper profile";
-		return -EINVAL;
+	if (!nix_tm_is_leaf(dev, lvl)) {
+		/* Check if shaper profile exists for non leaf node */
+		profile_id = params->shaper_profile_id;
+		profile = nix_tm_shaper_profile_search(dev, profile_id);
+		if (profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE && !profile) {
+			error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+			error->message = "invalid shaper profile";
+			return -EINVAL;
+		}
+
+		/* Minimum static priority count is 1 */
+		if (!params->nonleaf.n_sp_priorities ||
+		    params->nonleaf.n_sp_priorities > TXSCH_TLX_SP_PRIO_MAX) {
+			error->type =
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;
+			error->message = "invalid sp priorities";
+			return -EINVAL;
+		}
+
+		pkt_mode = 0;
+		/* Validate weight mode */
+		for (i = 0; i < params->nonleaf.n_sp_priorities &&
+		     params->nonleaf.wfq_weight_mode; i++) {
+			pkt_mode = !params->nonleaf.wfq_weight_mode[i];
+			if (pkt_mode == !params->nonleaf.wfq_weight_mode[0])
+				continue;
+
+			error->type =
+				RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
+			error->message = "unsupported weight mode";
+			return -EINVAL;
+		}
+
+		if (profile && params->nonleaf.n_sp_priorities &&
+		    pkt_mode != profile->params.packet_mode) {
+			error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
+			error->message = "shaper wfq packet mode mismatch";
+			return -EINVAL;
+		}
 	}
 
 	/* Check if there is second DWRR already in siblings or holes in prio */
@@ -2482,6 +2570,12 @@ otx2_nix_tm_node_shaper_update(struct rte_eth_dev *eth_dev,
 		}
 	}
 
+	if (profile && profile->params.packet_mode != tm_node->pkt_mode) {
+		error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
+		error->message = "shaper profile pkt mode mismatch";
+		return -EINVAL;
+	}
+
 	tm_node->params.shaper_profile_id = profile_id;
 
 	/* Nothing to do if not yet committed */
diff --git a/drivers/net/octeontx2/otx2_tm.h b/drivers/net/octeontx2/otx2_tm.h
index 9675182..cdca987 100644
--- a/drivers/net/octeontx2/otx2_tm.h
+++ b/drivers/net/octeontx2/otx2_tm.h
@@ -48,6 +48,7 @@ struct otx2_nix_tm_node {
 #define NIX_TM_NODE_USER	BIT_ULL(2)
 	/* Shaper algorithm for RED state @NIX_REDALG_E */
 	uint32_t red_algo:2;
+	uint32_t pkt_mode:1;
 
 	struct otx2_nix_tm_node *parent;
 	struct rte_tm_node_params params;
@@ -114,6 +115,10 @@ TAILQ_HEAD(otx2_nix_tm_shaper_profile_list, otx2_nix_tm_shaper_profile);
 #define MAX_SHAPER_RATE \
 	SHAPER_RATE(MAX_RATE_EXPONENT, MAX_RATE_MANTISSA, 0)
 
+/* Min is limited so that NIX_AF_SMQX_CFG[MINLEN]+ADJUST is not -ve */
+#define NIX_LENGTH_ADJUST_MIN ((int)-NIX_MIN_HW_FRS + 1)
+#define NIX_LENGTH_ADJUST_MAX 255
+
 /** TM Shaper - low level operations */
 
 /** NIX burst limits */
