From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from dpdk.org (dpdk.org [92.243.14.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 84E1AA0549;
	Thu, 16 Jul 2020 10:14:37 +0200 (CEST)
Received: from [92.243.14.124] (localhost [127.0.0.1])
	by dpdk.org (Postfix) with ESMTP id 5D6CC1BEB1;
	Thu, 16 Jul 2020 10:14:37 +0200 (CEST)
Received: from mga11.intel.com (mga11.intel.com [192.55.52.93])
 by dpdk.org (Postfix) with ESMTP id CB0384F9A
 for <dev@dpdk.org>; Thu, 16 Jul 2020 10:14:34 +0200 (CEST)
IronPort-SDR: oMSRtX9QYTiu1DsrFLuUU2o9O98O0ZVddvtkBZ9t7YetWsW5BhELALI0olgtuDISktx3cwAw/y
 6gRl7SL+XwgQ==
X-IronPort-AV: E=McAfee;i="6000,8403,9683"; a="147333547"
X-IronPort-AV: E=Sophos;i="5.75,358,1589266800"; d="scan'208";a="147333547"
X-Amp-Result: SKIPPED(no attachment in message)
X-Amp-File-Uploaded: False
Received: from fmsmga007.fm.intel.com ([10.253.24.52])
 by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
 16 Jul 2020 01:14:33 -0700
IronPort-SDR: i7ZpEOWRZGOl+gEAxuUo5Tga3SYIrz6yxFetiwwuJOihkJoeD6tP2nYfxOkGQo0RKJAhmcj27K
 pzBn2pMBNfOA==
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.75,358,1589266800"; d="scan'208";a="269189942"
Received: from orsmsx105.amr.corp.intel.com ([10.22.225.132])
 by fmsmga007.fm.intel.com with ESMTP; 16 Jul 2020 01:14:33 -0700
Received: from orsmsx612.amr.corp.intel.com (10.22.229.25) by
 ORSMSX105.amr.corp.intel.com (10.22.225.132) with Microsoft SMTP Server (TLS)
 id 14.3.439.0; Thu, 16 Jul 2020 01:14:33 -0700
Received: from orsmsx603.amr.corp.intel.com (10.22.229.16) by
 ORSMSX612.amr.corp.intel.com (10.22.229.25) with Microsoft SMTP Server
 (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id
 15.1.1713.5; Thu, 16 Jul 2020 01:14:33 -0700
Received: from ORSEDG001.ED.cps.intel.com (10.7.248.4) by
 orsmsx603.amr.corp.intel.com (10.22.229.16) with Microsoft SMTP Server
 (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.1.1713.5
 via Frontend Transport; Thu, 16 Jul 2020 01:14:33 -0700
Received: from NAM11-DM6-obe.outbound.protection.outlook.com (104.47.57.170)
 by edgegateway.intel.com (134.134.137.100) with Microsoft SMTP Server (TLS)
 id 14.3.439.0; Thu, 16 Jul 2020 01:14:31 -0700
ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;
 b=Yg+ydzh++WsCHYWUdqojFd5hltT1vWg/at8SkkwN8IxkbreqMKDa6eZcI88WkOdn65lbgP/1weXDpnzG08OAafF1gS1rVZbK05kcz9w3PMZ9n1mHP0I3pIWKZW+aPGx7W4GYE/GTGvLNPHIqvUv80VBWQiHxXtTql/MYeU2A/3OvoAzNu6pVacjStMdUWmH8AHU975Cfj4LPwRTczCbAZBz1QPKva2pb0N0odzAM4ifMrFCZ1BJ/n5W0m9aJ/q+ChkuTc4Qswrcr4Dyks+KkOutkmo/UMdE9ZVpd4Z6tHH2oY86+rBK7dpzs6A/3VFsoL+S39C3vy1m16EQ3G7vLcQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; 
 s=arcselector9901;
 h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
 bh=UMPJCupNyRsnArkd9OMQ0kjgsU7oTe7eNR5lq+u9h5E=;
 b=RPjtuEFdhL9hfIw815RpI5J4J4GGzrVHuJiXTSSWudPdZvyd19gvPCfLJ5wHet8u+mkIjp00OOator3MDvmH0dIoalmeBMBDSC4L/yQxpPGjqBLrjcaZjAMg3Ik9OMHraZ3QQrBfRtlCTG51CoHCbV5sSCTyrEM5kOSAqSAlx5VLA8h2Q7OBnCW444bODOx9kHZDYekDITG45DawozF6iEPacrf4djCY86MfE2OvHFUtncEq4fCCdfRGCW3pwhx1gbNL5yTeR8oi5XbvsgFAQbbbBRU4oe9d58haGC0g+zX8ZGUfZLf3XlzclA1OAuyKGAoamE7jA9oqc4zoGIo32Q==
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass
 smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com;
 dkim=pass header.d=intel.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=intel.onmicrosoft.com; 
 s=selector2-intel-onmicrosoft-com;
 h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
 bh=UMPJCupNyRsnArkd9OMQ0kjgsU7oTe7eNR5lq+u9h5E=;
 b=Y9RmpqjbLLRhCBu6UMlKM58Pe+x/SBlws3qKobKW6ua+sg87xX7FN0WuVzstM/RoWYIfTkuJGUOqnmyF75qZ5ZIbHwJrznhqnhdVdCx8FXnsTmSLUR4mmtM3zPjqzTNqqgO8eABrx9g34YJxnXhNHhK1FiG/IEungHp/19V/36M=
Received: from CY4PR11MB0072.namprd11.prod.outlook.com (2603:10b6:910:76::27)
 by CY4PR11MB1526.namprd11.prod.outlook.com (2603:10b6:910:7::10) with
 Microsoft SMTP Server (version=TLS1_2,
 cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3174.21; Thu, 16 Jul
 2020 08:14:28 +0000
Received: from CY4PR11MB0072.namprd11.prod.outlook.com
 ([fe80::e979:a537:4a97:afd5]) by CY4PR11MB0072.namprd11.prod.outlook.com
 ([fe80::e979:a537:4a97:afd5%5]) with mapi id 15.20.3195.018; Thu, 16 Jul 2020
 08:14:28 +0000
From: "Singh, Jasvinder" <jasvinder.singh@intel.com>
To: "Dharmappa, Savinay" <savinay.dharmappa@intel.com>, "dev@dpdk.org"
 <dev@dpdk.org>, "Dumitrescu, Cristian" <cristian.dumitrescu@intel.com>
Thread-Topic: [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth
 profile
Thread-Index: AQHWWtXEe7Ur2pGIWEqsw/hyR54MhqkJ3H0w
Date: Thu, 16 Jul 2020 08:14:28 +0000
Message-ID: <CY4PR11MB0072890D5551264112ADEC5DE07F0@CY4PR11MB0072.namprd11.prod.outlook.com>
References: <1594837677-313175-1-git-send-email-savinay.dharmappa@intel.com>
 <1594837677-313175-2-git-send-email-savinay.dharmappa@intel.com>
In-Reply-To: <1594837677-313175-2-git-send-email-savinay.dharmappa@intel.com>
Accept-Language: en-GB, en-US
Content-Language: en-US
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
dlp-version: 11.5.1.3
dlp-reaction: no-action
dlp-product: dlpe-windows
authentication-results: intel.com; dkim=none (message not signed)
 header.d=none;intel.com; dmarc=none action=none header.from=intel.com;
x-originating-ip: [51.37.210.122]
x-ms-publictraffictype: Email
x-ms-office365-filtering-correlation-id: 83789662-780d-453c-7070-08d8296042e7
x-ms-traffictypediagnostic: CY4PR11MB1526:
x-ms-exchange-transport-forked: True
x-microsoft-antispam-prvs: <CY4PR11MB1526B80ADDE330F920196184E07F0@CY4PR11MB1526.namprd11.prod.outlook.com>
x-ms-oob-tlc-oobclassifiers: OLM:110;
x-ms-exchange-senderadcheck: 1
x-microsoft-antispam: BCL:0;
x-microsoft-antispam-message-info: J/Px3r7lt0UMl/AUuIws2p0PsrWfZvpQX/Zyz7B3J8oAaFH13eqK9XDvy9K8g/evvanN7pNMw6yot4+0oeToPpvTmi//aU406+LrQBfiC6O/KwHVkQe2I4ESwjywjWt52pImaLVBqDbf2VvnwAkCWGQ8GVRa9TUsyNRusAtAlYIYQ9+M40LVFUaiSwWYZewUN+tJNPz1nb7d+5CmlmgFdixD2EBGtcXEbPYGFkLSwmzb5IoAfCG2LUCmL47b1YT4QJlNXvY8lFIJNnFa8lCZ2waUCqEikLNs+SAyWsvQy77HPU8j4ZQ6swk33M46RXbK
x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;
 IPV:NLI; SFV:NSPM; H:CY4PR11MB0072.namprd11.prod.outlook.com; PTR:; CAT:NONE;
 SFTY:;
 SFS:(4636009)(396003)(366004)(136003)(39860400002)(376002)(346002)(86362001)(53546011)(6636002)(6506007)(30864003)(64756008)(71200400001)(66946007)(66446008)(66556008)(316002)(478600001)(186003)(2906002)(7696005)(9686003)(66476007)(8676002)(55016002)(26005)(8936002)(33656002)(76116006)(110136005)(83380400001)(5660300002)(52536014)(559001)(579004);
 DIR:OUT; SFP:1102; 
x-ms-exchange-antispam-messagedata: 99j58qCUZBUK/H/yh51xY2b6VbcNRdUfeAU9jsDRkkI8Nqof924pQV+lluKUVL7l8mBciueHGqC0PjVsVbReT9/CLkZIsVj7YTSHOBK4z8Thr3McX+pBb5ED1gAgjU2INyBMePEEMpuxwG/pe6uqVS8jf0r5L/N4xAm/8JZTAHfYYbD0luuTJ28iJUU1F8hyC/3k6wCV2/DFsEC70SuW4RReq8AqkePdcQ4vkZGe882ozIVrHH7MoudZeftFznm/knN+EUY04CHL+qCu+j/PiLsgeGZWav+0RicLFqlRUZmvDCsNhKjIN4QgcL9ZybfyxszSFNyeqEeTCglqumuxJG3ODcicpUPtaS8tlW5WefCmJQ+2OzVANq4Ajjd/bzmJAWrfXdfAE9VGn/vTlsv/QVxTu4h7BUuOetEYUlMcHtQ56yk0wTd3UiLfq4ZLyWUvNBPxmIb+IgwQYE7mW354Rd1xDSpvuS/3ccIIAchuKf4=
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
X-MS-Exchange-CrossTenant-AuthAs: Internal
X-MS-Exchange-CrossTenant-AuthSource: CY4PR11MB0072.namprd11.prod.outlook.com
X-MS-Exchange-CrossTenant-Network-Message-Id: 83789662-780d-453c-7070-08d8296042e7
X-MS-Exchange-CrossTenant-originalarrivaltime: 16 Jul 2020 08:14:28.7908 (UTC)
X-MS-Exchange-CrossTenant-fromentityheader: Hosted
X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d
X-MS-Exchange-CrossTenant-mailboxtype: HOSTED
X-MS-Exchange-CrossTenant-userprincipalname: Luf82YSq3YGAmtrD4BbTfCFihb9V7NJruopnJIlbATNFOoNSZHLcgqEyWcf3DzkQccHnZNdKaxsoDtesQ1tGW7G+3X1+NTJ13aTmGBw3NCo=
X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR11MB1526
X-OriginatorOrg: intel.com
Subject: Re: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport
 bandwidth profile
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org
Sender: "dev" <dev-bounces@dpdk.org>



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Wednesday, July 15, 2020 7:28 PM
> To: Dharmappa, Savinay <savinay.dharmappa@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth
> profile
>=20
> This patch modifies the subport level data structures and add new API to
> allow dynamic configuration of the subport bandwidth profile.
>=20
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++---=
------
>  lib/librte_sched/rte_sched.h           |  82 +++++-
>  lib/librte_sched/rte_sched_version.map |   2 +
>  3 files changed, 424 insertions(+), 146 deletions(-)
>=20
> diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c =
index
> c0983dd..5bb0d2b 100644
> --- a/lib/librte_sched/rte_sched.c
> +++ b/lib/librte_sched/rte_sched.c
> @@ -2,6 +2,7 @@
>   * Copyright(c) 2010-2014 Intel Corporation
>   */
>=20
> +#include <stdint.h>
>  #include <stdio.h>
>  #include <string.h>
>=20
> @@ -101,6 +102,16 @@ enum grinder_state {
>  	e_GRINDER_READ_MBUF
>  };
>=20
> +struct rte_sched_subport_profile {
> +	/* Token bucket (TB) */
> +	uint64_t tb_period;
> +	uint64_t tb_credits_per_period;
> +	uint64_t tb_size;
> +
> +	uint64_t
> tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> +	uint64_t tc_period;
> +};
> +
>  struct rte_sched_grinder {
>  	/* Pipe cache */
>  	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
> @@ -113,6 +124,7 @@ struct rte_sched_grinder {
>  	uint32_t productive;
>  	uint32_t pindex;
>  	struct rte_sched_subport *subport;
> +	struct rte_sched_subport_profile *subport_params;
>  	struct rte_sched_pipe *pipe;
>  	struct rte_sched_pipe_profile *pipe_params;
>=20
> @@ -139,18 +151,13 @@ struct rte_sched_grinder {  };
>=20
>  struct rte_sched_subport {
> -	/* Token bucket (TB) */
> +
>  	uint64_t tb_time; /* time of last update */
> -	uint64_t tb_period;
> -	uint64_t tb_credits_per_period;
> -	uint64_t tb_size;
>  	uint64_t tb_credits;
>=20
>  	/* Traffic classes (TCs) */
>  	uint64_t tc_time; /* time of next update */
> -	uint64_t
> tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
>  	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> -	uint64_t tc_period;
>=20
>  	/* TC oversubscription */
>  	uint64_t tc_ov_wm;
> @@ -164,6 +171,8 @@ struct rte_sched_subport {
>  	/* Statistics */
>  	struct rte_sched_subport_stats stats __rte_cache_aligned;
>=20
> +	/* subport profile flag */
> +	uint32_t profile;
>  	/* Subport pipes */
>  	uint32_t n_pipes_per_subport_enabled;
>  	uint32_t n_pipe_profiles;
> @@ -212,6 +221,8 @@ struct rte_sched_port {
>  	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
>  	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
>  	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
> +	uint32_t n_subport_profiles;
> +	uint32_t n_max_subport_profiles;
>  	uint64_t rate;
>  	uint32_t mtu;
>  	uint32_t frame_overhead;
> @@ -229,6 +240,7 @@ struct rte_sched_port {
>  	uint32_t subport_id;
>=20
>  	/* Large data structures */
> +	struct rte_sched_subport_profile *subport_profiles;
>  	struct rte_sched_subport *subports[0] __rte_cache_aligned;  }
> __rte_cache_aligned;
>=20
> @@ -375,8 +387,60 @@ pipe_profile_check(struct rte_sched_pipe_params
> *params,  }
>=20
>  static int
> +subport_profile_check(struct rte_sched_subport_profile_params *params,
> +	uint64_t rate)
> +{
> +	uint32_t i;
> +
> +	/* Check user parameters */
> +	if (params =3D=3D NULL) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter params\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params->tb_rate =3D=3D 0 || params->tb_rate > rate) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for tb rate\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params->tb_size =3D=3D 0) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for tb size\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
> +		uint64_t tc_rate =3D params->tc_rate[i];
> +
> +		if (tc_rate =3D=3D 0 || (tc_rate > params->tb_rate)) {
> +			RTE_LOG(ERR, SCHED,
> +				"%s: Incorrect value for tc rate\n", __func__);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] =3D=3D 0) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect tc rate(best effort)\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params->tc_period =3D=3D 0) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for tc period\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
>  rte_sched_port_check_params(struct rte_sched_port_params *params)  {
> +	uint32_t i;
> +
>  	if (params =3D=3D NULL) {
>  		RTE_LOG(ERR, SCHED,
>  			"%s: Incorrect value for parameter params\n",
> __func__); @@ -413,6 +477,29 @@ rte_sched_port_check_params(struct
> rte_sched_port_params *params)
>  		return -EINVAL;
>  	}
>=20
> +	if (params->subport_profiles =3D=3D NULL ||
> +		params->n_subport_profiles =3D=3D 0 ||
> +		params->n_max_subport_profiles =3D=3D 0 ||
> +		params->n_subport_profiles > params-
> >n_max_subport_profiles) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for subport profiles\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i =3D 0; i < params->n_subport_profiles; i++) {
> +		struct rte_sched_subport_profile_params *p =3D
> +						params->subport_profiles + i;
> +		int status;
> +
> +		status =3D subport_profile_check(p, params->rate);
> +		if (status !=3D 0) {
> +			RTE_LOG(ERR, SCHED,
> +			"%s: subport profile check failed(%d)\n",
> +			__func__, status);
> +			return -EINVAL;
> +		}
> +	}
> +
>  	/* n_pipes_per_subport: non-zero, power of 2 */
>  	if (params->n_pipes_per_subport =3D=3D 0 ||
>  	    !rte_is_power_of_2(params->n_pipes_per_subport)) { @@ -554,6
> +641,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport
> *subport, uint32_t i)
>  		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p-
> >wrr_cost[3]);  }
>=20
> +static void
> +rte_sched_port_log_subport_profile(struct rte_sched_port *port,
> +uint32_t i) {
> +	struct rte_sched_subport_profile *p =3D port->subport_profiles + i;
> +
> +	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile
> %u:\n"
> +	"Token bucket: period =3D %"PRIu64", credits per period =3D %"PRIu64",\
> +	size =3D %"PRIu64"\n"
> +	"Traffic classes: period =3D %"PRIu64",\n"
> +	"credits per period =3D [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
> +	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64",
> %"PRIu64
> +	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
> +	i,
> +
> +	/* Token bucket */
> +	p->tb_period,
> +	p->tb_credits_per_period,
> +	p->tb_size,
> +
> +	/* Traffic classes */
> +	p->tc_period,
> +	p->tc_credits_per_period[0],
> +	p->tc_credits_per_period[1],
> +	p->tc_credits_per_period[2],
> +	p->tc_credits_per_period[3],
> +	p->tc_credits_per_period[4],
> +	p->tc_credits_per_period[5],
> +	p->tc_credits_per_period[6],
> +	p->tc_credits_per_period[7],
> +	p->tc_credits_per_period[8],
> +	p->tc_credits_per_period[9],
> +	p->tc_credits_per_period[10],
> +	p->tc_credits_per_period[11],
> +	p->tc_credits_per_period[12]);
> +}
> +
>  static inline uint64_t
>  rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)  { @@ -623,6
> +746,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport
> *subport,  }
>=20
>  static void
> +rte_sched_subport_profile_convert(struct
> rte_sched_subport_profile_params *src,
> +	struct rte_sched_subport_profile *dst,
> +	uint64_t rate)
> +{
> +	uint32_t i;
> +
> +	/* Token Bucket */
> +	if (src->tb_rate =3D=3D rate) {
> +		dst->tb_credits_per_period =3D 1;
> +		dst->tb_period =3D 1;
> +	} else {
> +		double tb_rate =3D (double) src->tb_rate
> +				/ (double) rate;
> +		double d =3D RTE_SCHED_TB_RATE_CONFIG_ERR;
> +
> +		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
> +			&dst->tb_period);
> +	}
> +
> +	dst->tb_size =3D src->tb_size;
> +
> +	/* Traffic Classes */
> +	dst->tc_period =3D rte_sched_time_ms_to_bytes(src->tc_period, rate);
> +
> +	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> +		dst->tc_credits_per_period[i]
> +			=3D rte_sched_time_ms_to_bytes(src->tc_period,
> +				src->tc_rate[i]);
> +}
> +
> +static void
>  rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport
> *subport,
>  	struct rte_sched_subport_params *params, uint32_t rate)  { @@ -
> 646,6 +800,24 @@ rte_sched_subport_config_pipe_profile_table(struct
> rte_sched_subport *subport,
>  	}
>  }
>=20
> +static void
> +rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
> +	struct rte_sched_port_params *params,
> +	uint64_t rate)
> +{
> +	uint32_t i;
> +
> +	for (i =3D 0; i < port->n_subport_profiles; i++) {
> +		struct rte_sched_subport_profile_params *src
> +				=3D params->subport_profiles + i;
> +		struct rte_sched_subport_profile *dst
> +				=3D port->subport_profiles + i;
> +
> +		rte_sched_subport_profile_convert(src, dst, rate);
> +		rte_sched_port_log_subport_profile(port, i);
> +	}
> +}
> +
>  static int
>  rte_sched_subport_check_params(struct rte_sched_subport_params
> *params,
>  	uint32_t n_max_pipes_per_subport,
> @@ -660,18 +832,6 @@ rte_sched_subport_check_params(struct
> rte_sched_subport_params *params,
>  		return -EINVAL;
>  	}
>=20
> -	if (params->tb_rate =3D=3D 0 || params->tb_rate > rate) {
> -		RTE_LOG(ERR, SCHED,
> -			"%s: Incorrect value for tb rate\n", __func__);
> -		return -EINVAL;
> -	}
> -
> -	if (params->tb_size =3D=3D 0) {
> -		RTE_LOG(ERR, SCHED,
> -			"%s: Incorrect value for tb size\n", __func__);
> -		return -EINVAL;
> -	}
> -
>  	/* qsize: if non-zero, power of 2,
>  	 * no bigger than 32K (due to 16-bit read/write pointers)
>  	 */
> @@ -685,32 +845,12 @@ rte_sched_subport_check_params(struct
> rte_sched_subport_params *params,
>  		}
>  	}
>=20
> -	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
> -		uint64_t tc_rate =3D params->tc_rate[i];
> -		uint16_t qsize =3D params->qsize[i];
> -
> -		if ((qsize =3D=3D 0 && tc_rate !=3D 0) ||
> -			(qsize !=3D 0 && tc_rate =3D=3D 0) ||
> -			(tc_rate > params->tb_rate)) {
> -			RTE_LOG(ERR, SCHED,
> -				"%s: Incorrect value for tc rate\n", __func__);
> -			return -EINVAL;
> -		}
> -	}
> -
> -	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] =3D=3D 0 ||
> -		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] =3D=3D 0) {
> +	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] =3D=3D 0) {
>  		RTE_LOG(ERR, SCHED,
>  			"%s: Incorrect qsize or tc rate(best effort)\n",
> __func__);
>  		return -EINVAL;
>  	}
>=20
> -	if (params->tc_period =3D=3D 0) {
> -		RTE_LOG(ERR, SCHED,
> -			"%s: Incorrect value for tc period\n", __func__);
> -		return -EINVAL;
> -	}
> -
>  	/* n_pipes_per_subport: non-zero, power of 2 */
>  	if (params->n_pipes_per_subport_enabled =3D=3D 0 ||
>  		params->n_pipes_per_subport_enabled >
> n_max_pipes_per_subport || @@ -792,7 +932,7 @@ struct rte_sched_port
> *  rte_sched_port_config(struct rte_sched_port_params *params)  {
>  	struct rte_sched_port *port =3D NULL;
> -	uint32_t size0, size1;
> +	uint32_t size0, size1, size2;
>  	uint32_t cycles_per_byte;
>  	uint32_t i, j;
>  	int status;
> @@ -807,10 +947,21 @@ rte_sched_port_config(struct
> rte_sched_port_params *params)
>=20
>  	size0 =3D sizeof(struct rte_sched_port);
>  	size1 =3D params->n_subports_per_port * sizeof(struct
> rte_sched_subport *);
> +	size2 =3D params->n_max_subport_profiles *
> +		sizeof(struct rte_sched_subport_profile);
>=20
>  	/* Allocate memory to store the data structures */
> -	port =3D rte_zmalloc_socket("qos_params", size0 + size1,
> RTE_CACHE_LINE_SIZE,
> -		params->socket);
> +	port =3D rte_zmalloc_socket("qos_params", size0 + size1,
> +				 RTE_CACHE_LINE_SIZE, params->socket);
> +	if (port =3D=3D NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n",
> __func__);
> +
> +		return NULL;
> +	}
> +
> +	/* Allocate memory to store the subport profile */
> +	port->subport_profiles  =3D rte_zmalloc_socket("subport_profile",
> size2,
> +					RTE_CACHE_LINE_SIZE, params-
> >socket);
>  	if (port =3D=3D NULL) {
>  		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n",
> __func__);
>=20
> @@ -819,6 +970,8 @@ rte_sched_port_config(struct
> rte_sched_port_params *params)
>=20
>  	/* User parameters */
>  	port->n_subports_per_port =3D params->n_subports_per_port;
> +	port->n_subport_profiles =3D params->n_subport_profiles;
> +	port->n_max_subport_profiles =3D params->n_max_subport_profiles;
>  	port->n_pipes_per_subport =3D params->n_pipes_per_subport;
>  	port->n_pipes_per_subport_log2 =3D
>  			__builtin_ctz(params->n_pipes_per_subport);
> @@ -849,6 +1002,9 @@ rte_sched_port_config(struct
> rte_sched_port_params *params)
>  	port->time_cpu_bytes =3D 0;
>  	port->time =3D 0;
>=20
> +	/* Subport profile table */
> +	rte_sched_port_config_subport_profile_table(port, params, port-
> >rate);
> +
>  	cycles_per_byte =3D (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
>  		/ params->rate;
>  	port->inv_cycles_per_byte =3D rte_reciprocal_value(cycles_per_byte);
> @@ -907,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
> }
>=20
>  static void
> -rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t =
i)
> -{
> -	struct rte_sched_subport *s =3D port->subports[i];
> -
> -	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
> -		"	Token bucket: period =3D %"PRIu64", credits per period
> =3D %"PRIu64
> -		", size =3D %"PRIu64"\n"
> -		"	Traffic classes: period =3D %"PRIu64"\n"
> -		"	credits per period =3D [%"PRIu64", %"PRIu64",
> %"PRIu64", %"PRIu64
> -		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64",
> %"PRIu64
> -		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
> -		"	Best effort traffic class oversubscription: wm min =3D
> %"PRIu64
> -		", wm max =3D %"PRIu64"\n",
> -		i,
> -
> -		/* Token bucket */
> -		s->tb_period,
> -		s->tb_credits_per_period,
> -		s->tb_size,
> -
> -		/* Traffic classes */
> -		s->tc_period,
> -		s->tc_credits_per_period[0],
> -		s->tc_credits_per_period[1],
> -		s->tc_credits_per_period[2],
> -		s->tc_credits_per_period[3],
> -		s->tc_credits_per_period[4],
> -		s->tc_credits_per_period[5],
> -		s->tc_credits_per_period[6],
> -		s->tc_credits_per_period[7],
> -		s->tc_credits_per_period[8],
> -		s->tc_credits_per_period[9],
> -		s->tc_credits_per_period[10],
> -		s->tc_credits_per_period[11],
> -		s->tc_credits_per_period[12],
> -
> -		/* Best effort traffic class oversubscription */
> -		s->tc_ov_wm_min,
> -		s->tc_ov_wm_max);
> -}
> -
> -static void
>  rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
> {
>  	uint32_t i;
> @@ -1021,33 +1135,7 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	/* Port */
>  	port->subports[subport_id] =3D s;
>=20
> -	/* Token Bucket (TB) */
> -	if (params->tb_rate =3D=3D port->rate) {
> -		s->tb_credits_per_period =3D 1;
> -		s->tb_period =3D 1;
> -	} else {
> -		double tb_rate =3D ((double) params->tb_rate) / ((double)
> port->rate);
> -		double d =3D RTE_SCHED_TB_RATE_CONFIG_ERR;
> -
> -		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s-
> >tb_period);
> -	}
> -
> -	s->tb_size =3D params->tb_size;
>  	s->tb_time =3D port->time;
> -	s->tb_credits =3D s->tb_size / 2;
> -
> -	/* Traffic Classes (TCs) */
> -	s->tc_period =3D rte_sched_time_ms_to_bytes(params->tc_period,
> port->rate);
> -	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
> -		if (params->qsize[i])
> -			s->tc_credits_per_period[i]
> -				=3D rte_sched_time_ms_to_bytes(params-
> >tc_period,
> -					params->tc_rate[i]);
> -	}
> -	s->tc_time =3D port->time + s->tc_period;
> -	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -		if (params->qsize[i])
> -			s->tc_credits[i] =3D s->tc_credits_per_period[i];
>=20
>  	/* compile time checks */
>  	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS =3D=3D 0); @@ -
> 1137,8 +1225,6 @@ rte_sched_subport_config(struct rte_sched_port *port,
> #ifdef RTE_SCHED_SUBPORT_TC_OV
>  	/* TC oversubscription */
>  	s->tc_ov_wm_min =3D port->mtu;
> -	s->tc_ov_wm_max =3D rte_sched_time_ms_to_bytes(params-
> >tc_period,
> -						     s->pipe_tc_be_rate_max);
>  	s->tc_ov_wm =3D s->tc_ov_wm_max;
>  	s->tc_ov_period_id =3D 0;
>  	s->tc_ov =3D 0;
> @@ -1146,7 +1232,54 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	s->tc_ov_rate =3D 0;
>  #endif
>=20
> -	rte_sched_port_log_subport_config(port, subport_id);
> +	return 0;
> +}
> +
> +int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id)
> +{
> +	int i;
> +	struct rte_sched_subport_profile *params;
> +	uint32_t n_subports =3D subport_id + 1;
> +	struct rte_sched_subport *s;
> +
> +	if (port =3D=3D NULL) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter port\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_id >=3D port->n_subports_per_port) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter subport id\n",
> __func__);
> +
> +		rte_sched_free_memory(port, n_subports);
> +		return -EINVAL;
> +	}
> +
> +	params =3D  port->subport_profiles + profile_id;
> +
> +	s =3D port->subports[subport_id];
> +
> +	s->tb_credits =3D params->tb_size / 2;
> +
> +	s->tc_time =3D port->time + params->tc_period;
> +
> +	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> +		if (s->qsize[i])
> +			s->tc_credits[i] =3D params->tc_credits_per_period[i];
> +		else
> +			params->tc_credits_per_period[i] =3D 0;
> +
> +#ifdef RTE_SCHED_SUBPORT_TC_OV
> +	s->tc_ov_wm_max =3D rte_sched_time_ms_to_bytes(params-
> >tc_period,
> +						     s->pipe_tc_be_rate_max);
> +#endif
> +	s->profile =3D profile_id;
> +
> +	rte_sched_port_log_subport_profile(port, profile_id);
>=20
>  	return 0;
>  }
> @@ -1158,6 +1291,7 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  	int32_t pipe_profile)
>  {
>  	struct rte_sched_subport *s;
> +	struct rte_sched_subport_profile *sp;
>  	struct rte_sched_pipe *p;
>  	struct rte_sched_pipe_profile *params;
>  	uint32_t n_subports =3D subport_id + 1;
> @@ -1198,14 +1332,16 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  		return -EINVAL;
>  	}
>=20
> +	sp =3D port->subport_profiles + s->profile;
> +
>  	/* Handle the case when pipe already has a valid configuration */
>  	p =3D s->pipe + pipe_id;
>  	if (p->tb_time) {
>  		params =3D s->pipe_profiles + p->profile;
>=20
>  		double subport_tc_be_rate =3D
> -			(double) s-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -			/ (double) s->tc_period;
> +		(double) sp-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> +		/ (double) sp->tc_period;
>  		double pipe_tc_be_rate =3D
>  			(double) params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
>  			/ (double) params->tc_period;
> @@ -1247,8 +1383,8 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  	{
>  		/* Subport best effort tc oversubscription */
>  		double subport_tc_be_rate =3D
> -			(double) s-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -			/ (double) s->tc_period;
> +		(double) sp-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> +			/ (double) sp->tc_period;
>  		double pipe_tc_be_rate =3D
>  			(double) params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
>  			/ (double) params->tc_period;
> @@ -1260,8 +1396,9 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>=20
>  		if (s->tc_ov !=3D tc_be_ov) {
>  			RTE_LOG(DEBUG, SCHED,
> -				"Subport %u Best effort TC oversubscription
> is ON (%.4lf < %.4lf)\n",
> -				subport_id, subport_tc_be_rate, s-
> >tc_ov_rate);
> +			"Subport %u Best effort TC oversubscription is ON \
> +			(%.4lf < %.4lf)\n",
> +			subport_id, subport_tc_be_rate, s->tc_ov_rate);
>  		}
>  		p->tc_ov_period_id =3D s->tc_ov_period_id;
>  		p->tc_ov_credits =3D s->tc_ov_wm;
> @@ -1335,6 +1472,72 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	return 0;
>  }
>=20
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *params,
> +	uint32_t *subport_profile_id)
> +{
> +	int status;
> +	uint32_t i;
> +	struct rte_sched_subport_profile *dst;
> +
> +	/* Port */
> +	if (port =3D=3D NULL) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for parameter port\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params =3D=3D NULL) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for parameter profile\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_profile_id =3D=3D NULL) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for parameter \
> +		subport_profile_id\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	dst =3D port->subport_profiles + port->n_subport_profiles;
> +
> +	/* Subport profiles exceeds the max limit */
> +	if (port->n_subport_profiles >=3D port->n_max_subport_profiles) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Number of subport profiles exceeds \
> +		the max limit\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	status =3D subport_profile_check(params, port->rate);
> +	if (status !=3D 0) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: subport profile check failed(%d)\n", __func__, status);
> +		return -EINVAL;
> +	}
> +
> +	rte_sched_subport_profile_convert(params, dst, port->rate);
> +
> +	/* Subport profile should not exists */
> +	for (i =3D 0; i < port->n_subport_profiles; i++)
> +		if (memcmp(port->subport_profiles + i,
> +		    params, sizeof(*params)) =3D=3D 0) {
> +			RTE_LOG(ERR, SCHED,
> +			"%s: subport profile exists\n", __func__);
> +			return -EINVAL;
> +		}
> +
> +	/* Subport profile commit */
> +	*subport_profile_id =3D port->n_subport_profiles;
> +	port->n_subport_profiles++;
> +
> +	rte_sched_port_log_subport_profile(port, *subport_profile_id);
> +
> +	return 0;
> +}
> +
>  static inline uint32_t
>  rte_sched_port_qindex(struct rte_sched_port *port,
>  	uint32_t subport,
> @@ -1970,14 +2173,18 @@ grinder_credits_update(struct rte_sched_port
> *port,
>  	struct rte_sched_grinder *grinder =3D subport->grinder + pos;
>  	struct rte_sched_pipe *pipe =3D grinder->pipe;
>  	struct rte_sched_pipe_profile *params =3D grinder->pipe_params;
> +	struct rte_sched_subport_profile *subport_params =3D
> +						grinder->subport_params;
>  	uint64_t n_periods;
>  	uint32_t i;
>=20
>  	/* Subport TB */
> -	n_periods =3D (port->time - subport->tb_time) / subport->tb_period;
> -	subport->tb_credits +=3D n_periods * subport->tb_credits_per_period;
> -	subport->tb_credits =3D RTE_MIN(subport->tb_credits, subport-
> >tb_size);
> -	subport->tb_time +=3D n_periods * subport->tb_period;
> +	n_periods =3D (port->time - subport->tb_time) / subport_params-
> >tb_period;
> +	subport->tb_credits +=3D n_periods *
> +			       subport_params->tb_credits_per_period;
> +	subport->tb_credits =3D RTE_MIN(subport->tb_credits,
> +				      subport_params->tb_size);
> +	subport->tb_time +=3D n_periods * subport_params->tb_period;
>=20
>  	/* Pipe TB */
>  	n_periods =3D (port->time - pipe->tb_time) / params->tb_period; @@ -
> 1988,9 +2195,10 @@ grinder_credits_update(struct rte_sched_port *port,
>  	/* Subport TCs */
>  	if (unlikely(port->time >=3D subport->tc_time)) {
>  		for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -			subport->tc_credits[i] =3D subport-
> >tc_credits_per_period[i];
> +			subport->tc_credits[i] =3D
> +				subport_params->tc_credits_per_period[i];
>=20
> -		subport->tc_time =3D port->time + subport->tc_period;
> +		subport->tc_time =3D port->time + subport_params->tc_period;
>  	}
>=20
>  	/* Pipe TCs */
> @@ -2008,6 +2216,8 @@ static inline uint64_t
> grinder_tc_ov_credits_update(struct rte_sched_port *port,
>  	struct rte_sched_subport *subport)
>  {
> +	struct rte_sched_subport_profile *subport_params =3D
> +						grinder->subport_params;
>  	uint64_t
> tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
>  	uint64_t tc_consumption =3D 0, tc_ov_consumption_max;
>  	uint64_t tc_ov_wm =3D subport->tc_ov_wm; @@ -2018,16 +2228,17
> @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
>=20
>  	for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
>  		tc_ov_consumption[i] =3D
> -			subport->tc_credits_per_period[i] - subport-
> >tc_credits[i];
> +			subport_params->tc_credits_per_period[i] -
> +						subport->tc_credits[i];
>  		tc_consumption +=3D tc_ov_consumption[i];
>  	}
>=20
>  	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =3D
> -		subport-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
> +	subport_params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
>  		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
>=20
>  	tc_ov_consumption_max =3D
> -		subport-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
> +	subport_params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
>  			tc_consumption;
>=20
>  	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] > @@ -
> 2053,14 +2264,18 @@ grinder_credits_update(struct rte_sched_port *port,
>  	struct rte_sched_grinder *grinder =3D subport->grinder + pos;
>  	struct rte_sched_pipe *pipe =3D grinder->pipe;
>  	struct rte_sched_pipe_profile *params =3D grinder->pipe_params;
> +	struct rte_sched_subport_profile *subport_params =3D
> +						grinder->subport_params;
>  	uint64_t n_periods;
>  	uint32_t i;
>=20
>  	/* Subport TB */
> -	n_periods =3D (port->time - subport->tb_time) / subport->tb_period;
> -	subport->tb_credits +=3D n_periods * subport->tb_credits_per_period;
> -	subport->tb_credits =3D RTE_MIN(subport->tb_credits, subport-
> >tb_size);
> -	subport->tb_time +=3D n_periods * subport->tb_period;
> +	n_periods =3D (port->time - subport->tb_time) / subport_params-
> >tb_period;
> +	subport->tb_credits +=3D n_periods *
> +				subport_params->tb_credits_per_period;
> +	subport->tb_credits =3D RTE_MIN(subport->tb_credits,
> +				subport_params->tb_size);
> +	subport->tb_time +=3D n_periods * subport_params->tb_period;
>=20
>  	/* Pipe TB */
>  	n_periods =3D (port->time - pipe->tb_time) / params->tb_period; @@ -
> 2073,9 +2288,10 @@ grinder_credits_update(struct rte_sched_port *port,
>  		subport->tc_ov_wm =3D grinder_tc_ov_credits_update(port,
> subport);
>=20
>  		for (i =3D 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -			subport->tc_credits[i] =3D subport-
> >tc_credits_per_period[i];
> +			subport->tc_credits[i] =3D
> +				subport_params->tc_credits_per_period[i];
>=20
> -		subport->tc_time =3D port->time + subport->tc_period;
> +		subport->tc_time =3D port->time + subport_params->tc_period;
>  		subport->tc_ov_period_id++;
>  	}
>=20
> @@ -2598,6 +2814,8 @@ grinder_handle(struct rte_sched_port *port,
>  		struct rte_sched_pipe *pipe =3D grinder->pipe;
>=20
>  		grinder->pipe_params =3D subport->pipe_profiles + pipe-
> >profile;
> +		grinder->subport_params =3D port->subport_profiles +
> +					  subport->profile;
>  		grinder_prefetch_tc_queue_arrays(subport, pos);
>  		grinder_credits_update(port, subport, pos);
>=20
> diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h =
index
> 8a5a93c..7623919 100644
> --- a/lib/librte_sched/rte_sched.h
> +++ b/lib/librte_sched/rte_sched.h
> @@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
>   * byte.
>   */
>  struct rte_sched_subport_params {
> -	/** Token bucket rate (measured in bytes per second) */
> -	uint64_t tb_rate;
> -
> -	/** Token bucket size (measured in credits) */
> -	uint64_t tb_size;
> -
> -	/** Traffic class rates (measured in bytes per second) */
> -	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> -
> -	/** Enforcement period for rates (measured in milliseconds) */
> -	uint64_t tc_period;
> -
>  	/** Number of subport pipes.
>  	 * The subport can enable/allocate fewer pipes than the maximum
>  	 * number set through struct
> port_params::n_max_pipes_per_subport,
> @@ -192,6 +180,20 @@ struct rte_sched_subport_params {  #endif  };
>=20
> +struct rte_sched_subport_profile_params {
> +	/** Token bucket rate (measured in bytes per second) */
> +	uint64_t tb_rate;
> +
> +	/** Token bucket size (measured in credits) */
> +	uint64_t tb_size;
> +
> +	/** Traffic class rates (measured in bytes per second) */
> +	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> +
> +	/** Enforcement period for rates (measured in milliseconds) */
> +	uint64_t tc_period;
> +};
> +
>  /** Subport statistics */
>  struct rte_sched_subport_stats {
>  	/** Number of packets successfully written */ @@ -254,6 +256,17
> @@ struct rte_sched_port_params {
>  	/** Number of subports */
>  	uint32_t n_subports_per_port;
>=20
> +	/** subport profile table.
> +	 * Every pipe is configured using one of the profiles from this table.
> +	 */
> +	struct rte_sched_subport_profile_params *subport_profiles;
> +
> +	/** Profiles in the pipe profile table */
> +	uint32_t n_subport_profiles;
> +
> +	/** Max allowed profiles in the pipe profile table */
> +	uint32_t n_max_subport_profiles;
> +
>  	/** Maximum number of subport pipes.
>  	 * This parameter is used to reserve a fixed number of bits
>  	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all @@ -
> 312,6 +325,29 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	uint32_t *pipe_profile_id);
>=20
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport bandwidth profile add
> + * Note that this function is safe to use in runtime for adding new
> + * subport bandwidth profile as it doesn't have any impact on
> +hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param struct rte_sched_subport_profile
> + *   Subport bandwidth profile
> + * @param subport_profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *profile,
> +	uint32_t *subport_profile_id);
> +
> +/**
>   * Hierarchical scheduler subport configuration
>   *
>   * @param port
> @@ -329,6 +365,28 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	struct rte_sched_subport_params *params);
>=20
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport profile configuration
> + * Note that this function is safe to use in runtime for applying any
> +specific
> + * subport bandwidth profile as it doesn't have any impact on
> +hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param subport_id
> + *   Subport ID
> + * @param profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id);
> +/**
>   * Hierarchical scheduler pipe configuration
>   *
>   * @param port
> diff --git a/lib/librte_sched/rte_sched_version.map
> b/lib/librte_sched/rte_sched_version.map
> index cefd990..c02a223 100644
> --- a/lib/librte_sched/rte_sched_version.map
> +++ b/lib/librte_sched/rte_sched_version.map
> @@ -28,4 +28,6 @@ EXPERIMENTAL {
>  	global:
>=20
>  	rte_sched_subport_pipe_profile_add;
> +	rte_sched_port_subport_profile_add;
> +	rte_sched_subport_profile_config;
>  };
> --
> 2.7.4

+ Cristian