+ struct rte_sched_subport *s = NULL;
+ uint32_t n_subports = subport_id;
+ uint32_t n_subport_pipe_queues, i;
+ uint32_t size0, size1, bmp_mem_size;
+ int status;
+
+ /* Check user parameters */
+ if (port == NULL) {
+ RTE_LOG(ERR, SCHED,
+ "%s: Incorrect value for parameter port\n", __func__);
+ return 0;
+ }
+
+ if (subport_id >= port->n_subports_per_port) {
+ RTE_LOG(ERR, SCHED,
+ "%s: Incorrect value for subport id\n", __func__);
+
+ rte_sched_free_memory(port, n_subports);
+ return -EINVAL;
+ }
+
+ status = rte_sched_subport_check_params(params,
+ port->n_pipes_per_subport,
+ port->rate);
+ if (status != 0) {
+ RTE_LOG(NOTICE, SCHED,
+ "%s: Port scheduler params check failed (%d)\n",
+ __func__, status);
+
+ rte_sched_free_memory(port, n_subports);
+ return -EINVAL;
+ }
+
+ /* Determine the amount of memory to allocate */
+ size0 = sizeof(struct rte_sched_subport);
+ size1 = rte_sched_subport_get_array_base(params,
+ e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
+
+ /* Allocate memory to store the data structures */
+ s = rte_zmalloc_socket("subport_params", size0 + size1,
+ RTE_CACHE_LINE_SIZE, port->socket);
+ if (s == NULL) {
+ RTE_LOG(ERR, SCHED,
+ "%s: Memory allocation fails\n", __func__);
+
+ rte_sched_free_memory(port, n_subports);
+ return -ENOMEM;
+ }
+
+ n_subports++;
+
+ /* Port */
+ port->subports[subport_id] = s;
+
+ /* Token Bucket (TB) */
+ if (params->tb_rate == port->rate) {
+ s->tb_credits_per_period = 1;
+ s->tb_period = 1;
+ } else {
+ double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
+ double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+ rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
+ }
+
+ s->tb_size = params->tb_size;
+ s->tb_time = port->time;
+ s->tb_credits = s->tb_size / 2;
+
+ /* Traffic Classes (TCs) */
+ s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
+ for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+ if (params->qsize[i])
+ s->tc_credits_per_period[i]
+ = rte_sched_time_ms_to_bytes(params->tc_period,
+ params->tc_rate[i]);
+ }
+ s->tc_time = port->time + s->tc_period;
+ for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+ if (params->qsize[i])
+ s->tc_credits[i] = s->tc_credits_per_period[i];
+
+ /* compile time checks */
+ RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
+ RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
+ (RTE_SCHED_PORT_N_GRINDERS - 1));
+
+ /* User parameters */
+ s->n_pipes_per_subport_enabled = params->n_pipes_per_subport_enabled;
+ memcpy(s->qsize, params->qsize, sizeof(params->qsize));
+ s->n_pipe_profiles = params->n_pipe_profiles;
+ s->n_max_pipe_profiles = params->n_max_pipe_profiles;
+
+#ifdef RTE_SCHED_RED
+ for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+ uint32_t j;
+
+ for (j = 0; j < RTE_COLORS; j++) {
+ /* if min/max are both zero, then RED is disabled */
+ if ((params->red_params[i][j].min_th |
+ params->red_params[i][j].max_th) == 0) {
+ continue;
+ }