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;
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;
/* 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;
/* TC oversubscription */
uint64_t tc_ov_wm;
/* Statistics */
struct rte_sched_subport_stats stats __rte_cache_aligned;
+ /* subport profile */
+ uint32_t profile;
/* Subport pipes */
uint32_t n_pipes_per_subport_enabled;
uint32_t n_pipe_profiles;
return -EINVAL;
}
- if (params->tb_rate == 0 || params->tb_rate > rate) {
- RTE_LOG(ERR, SCHED,
- "%s: Incorrect value for tb rate\n", __func__);
- return -EINVAL;
- }
-
- if (params->tb_size == 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)
*/
}
}
- for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
- uint64_t tc_rate = params->tc_rate[i];
- uint16_t qsize = params->qsize[i];
-
- if ((qsize == 0 && tc_rate != 0) ||
- (qsize != 0 && tc_rate == 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] == 0 ||
- params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
- RTE_LOG(ERR, SCHED,
- "%s: Incorrect qsize or tc rate(best effort)\n", __func__);
- return -EINVAL;
- }
-
- if (params->tc_period == 0) {
- RTE_LOG(ERR, SCHED,
- "%s: Incorrect value for tc period\n", __func__);
+ if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+ RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
return -EINVAL;
}
rte_free(port);
}
-static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
- struct rte_sched_subport *s = port->subports[i];
-
- RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
- " Token bucket: period = %"PRIu64", credits per period = %"PRIu64
- ", size = %"PRIu64"\n"
- " Traffic classes: period = %"PRIu64"\n"
- " credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
- ", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
- ", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
- " Best effort traffic class oversubscription: wm min = %"PRIu64
- ", wm max = %"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)
{
int
rte_sched_subport_config(struct rte_sched_port *port,
uint32_t subport_id,
- struct rte_sched_subport_params *params)
+ struct rte_sched_subport_params *params,
+ uint32_t subport_profile_id)
{
struct rte_sched_subport *s = NULL;
uint32_t n_subports = subport_id;
+ struct rte_sched_subport_profile *profile;
uint32_t n_subport_pipe_queues, i;
uint32_t size0, size1, bmp_mem_size;
int status;
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);
-
+ if (subport_profile_id >= port->n_max_subport_profiles) {
+ RTE_LOG(ERR, SCHED, "%s: "
+ "Number of subport profile exceeds the max limit\n",
+ __func__);
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);
+ /** Memory is allocated only on first invocation of the api for a
+ * given subport. Subsequent invocation on same subport will just
+ * update subport bandwidth parameter.
+ **/
+ if (port->subports[subport_id] == NULL) {
- /* 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__);
+ 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 -ENOMEM;
- }
+ rte_sched_free_memory(port, n_subports);
+ return -EINVAL;
+ }
- n_subports++;
+ /* 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);
- /* Port */
- port->subports[subport_id] = s;
+ /* 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__);
- /* 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_sched_free_memory(port, n_subports);
+ return -ENOMEM;
+ }
- rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
- }
+ n_subports++;
- s->tb_size = params->tb_size;
- s->tb_time = port->time;
- s->tb_credits = s->tb_size / 2;
+ subport_profile_id = 0;
- /* 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];
+ /* Port */
+ port->subports[subport_id] = s;
- /* 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));
+ s->tb_time = port->time;
- /* 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;
+ /* 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 (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+ uint32_t j;
- for (j = 0; j < RTE_COLORS; 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;
+ if ((params->red_params[i][j].min_th |
+ params->red_params[i][j].max_th) == 0) {
+ continue;
+ }
+
+ if (rte_red_config_init(&s->red_config[i][j],
+ params->red_params[i][j].wq_log2,
+ params->red_params[i][j].min_th,
+ params->red_params[i][j].max_th,
+ params->red_params[i][j].maxp_inv) != 0) {
+ rte_sched_free_memory(port, n_subports);
+
+ RTE_LOG(NOTICE, SCHED,
+ "%s: RED configuration init fails\n",
+ __func__);
+ return -EINVAL;
+ }
}
+ }
+#endif
- if (rte_red_config_init(&s->red_config[i][j],
- params->red_params[i][j].wq_log2,
- params->red_params[i][j].min_th,
- params->red_params[i][j].max_th,
- params->red_params[i][j].maxp_inv) != 0) {
- rte_sched_free_memory(port, n_subports);
+ /* Scheduling loop detection */
+ s->pipe_loop = RTE_SCHED_PIPE_INVALID;
+ s->pipe_exhaustion = 0;
+
+ /* Grinders */
+ s->busy_grinders = 0;
+
+ /* Queue base calculation */
+ rte_sched_subport_config_qsize(s);
+
+ /* Large data structures */
+ s->pipe = (struct rte_sched_pipe *)
+ (s->memory + rte_sched_subport_get_array_base(params,
+ e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
+ s->queue = (struct rte_sched_queue *)
+ (s->memory + rte_sched_subport_get_array_base(params,
+ e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
+ s->queue_extra = (struct rte_sched_queue_extra *)
+ (s->memory + rte_sched_subport_get_array_base(params,
+ e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
+ s->pipe_profiles = (struct rte_sched_pipe_profile *)
+ (s->memory + rte_sched_subport_get_array_base(params,
+ e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
+ s->bmp_array = s->memory + rte_sched_subport_get_array_base(
+ params, e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
+ s->queue_array = (struct rte_mbuf **)
+ (s->memory + rte_sched_subport_get_array_base(params,
+ e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
+
+ /* Pipe profile table */
+ rte_sched_subport_config_pipe_profile_table(s, params,
+ port->rate);
+
+ /* Bitmap */
+ n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
+ bmp_mem_size = rte_bitmap_get_memory_footprint(
+ n_subport_pipe_queues);
+ s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
+ bmp_mem_size);
+ if (s->bmp == NULL) {
+ RTE_LOG(ERR, SCHED,
+ "%s: Subport bitmap init error\n", __func__);
- RTE_LOG(NOTICE, SCHED,
- "%s: RED configuration init fails\n", __func__);
- return -EINVAL;
- }
+ rte_sched_free_memory(port, n_subports);
+ return -EINVAL;
}
- }
-#endif
- /* Scheduling loop detection */
- s->pipe_loop = RTE_SCHED_PIPE_INVALID;
- s->pipe_exhaustion = 0;
+ for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
+ s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
- /* Grinders */
- s->busy_grinders = 0;
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+ /* TC oversubscription */
+ s->tc_ov_wm_min = port->mtu;
+ s->tc_ov_wm = s->tc_ov_wm_max;
+ s->tc_ov_period_id = 0;
+ s->tc_ov = 0;
+ s->tc_ov_n = 0;
+ s->tc_ov_rate = 0;
+#endif
+ }
- /* Queue base calculation */
- rte_sched_subport_config_qsize(s);
+ {
+ /* update subport parameters from subport profile table*/
+ profile = port->subport_profiles + subport_profile_id;
- /* Large data structures */
- s->pipe = (struct rte_sched_pipe *)
- (s->memory + rte_sched_subport_get_array_base(params,
- e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
- s->queue = (struct rte_sched_queue *)
- (s->memory + rte_sched_subport_get_array_base(params,
- e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
- s->queue_extra = (struct rte_sched_queue_extra *)
- (s->memory + rte_sched_subport_get_array_base(params,
- e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
- s->pipe_profiles = (struct rte_sched_pipe_profile *)
- (s->memory + rte_sched_subport_get_array_base(params,
- e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
- s->bmp_array = s->memory + rte_sched_subport_get_array_base(params,
- e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
- s->queue_array = (struct rte_mbuf **)
- (s->memory + rte_sched_subport_get_array_base(params,
- e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
-
- /* Pipe profile table */
- rte_sched_subport_config_pipe_profile_table(s, params, port->rate);
+ s = port->subports[subport_id];
- /* Bitmap */
- n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
- bmp_mem_size = rte_bitmap_get_memory_footprint(n_subport_pipe_queues);
- s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
- bmp_mem_size);
- if (s->bmp == NULL) {
- RTE_LOG(ERR, SCHED,
- "%s: Subport bitmap init error\n", __func__);
+ s->tb_credits = profile->tb_size / 2;
- rte_sched_free_memory(port, n_subports);
- return -EINVAL;
- }
+ s->tc_time = port->time + profile->tc_period;
- for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
- s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
+ for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+ if (s->qsize[i])
+ s->tc_credits[i] =
+ profile->tc_credits_per_period[i];
+ else
+ profile->tc_credits_per_period[i] = 0;
#ifdef RTE_SCHED_SUBPORT_TC_OV
- /* TC oversubscription */
- s->tc_ov_wm_min = port->mtu;
- s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
- s->pipe_tc_be_rate_max);
- s->tc_ov_wm = s->tc_ov_wm_max;
- s->tc_ov_period_id = 0;
- s->tc_ov = 0;
- s->tc_ov_n = 0;
- s->tc_ov_rate = 0;
+ s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(profile->tc_period,
+ s->pipe_tc_be_rate_max);
#endif
+ s->profile = subport_profile_id;
- rte_sched_port_log_subport_config(port, subport_id);
+ }
+
+ rte_sched_port_log_subport_profile(port, subport_profile_id);
return 0;
}
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 = subport_id + 1;
return -EINVAL;
}
+ sp = port->subport_profiles + s->profile;
/* Handle the case when pipe already has a valid configuration */
p = s->pipe + pipe_id;
if (p->tb_time) {
params = s->pipe_profiles + p->profile;
double subport_tc_be_rate =
- (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 =
(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
/ (double) params->tc_period;
{
/* Subport best effort tc oversubscription */
double subport_tc_be_rate =
- (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 =
(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
/ (double) params->tc_period;
struct rte_sched_grinder *grinder = subport->grinder + pos;
struct rte_sched_pipe *pipe = grinder->pipe;
struct rte_sched_pipe_profile *params = grinder->pipe_params;
+ struct rte_sched_subport_profile *sp = grinder->subport_params;
uint64_t n_periods;
uint32_t i;
/* Subport TB */
- n_periods = (port->time - subport->tb_time) / subport->tb_period;
- subport->tb_credits += n_periods * subport->tb_credits_per_period;
- subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
- subport->tb_time += n_periods * subport->tb_period;
+ n_periods = (port->time - subport->tb_time) / sp->tb_period;
+ subport->tb_credits += n_periods * sp->tb_credits_per_period;
+ subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+ subport->tb_time += n_periods * sp->tb_period;
/* Pipe TB */
n_periods = (port->time - pipe->tb_time) / params->tb_period;
/* Subport TCs */
if (unlikely(port->time >= subport->tc_time)) {
for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
- subport->tc_credits[i] = subport->tc_credits_per_period[i];
+ subport->tc_credits[i] = sp->tc_credits_per_period[i];
- subport->tc_time = port->time + subport->tc_period;
+ subport->tc_time = port->time + sp->tc_period;
}
/* Pipe TCs */
static inline uint64_t
grinder_tc_ov_credits_update(struct rte_sched_port *port,
- struct rte_sched_subport *subport)
+ struct rte_sched_subport *subport, uint32_t pos)
{
+ struct rte_sched_grinder *grinder = subport->grinder + pos;
+ struct rte_sched_subport_profile *sp = grinder->subport_params;
uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
uint64_t tc_consumption = 0, tc_ov_consumption_max;
uint64_t tc_ov_wm = subport->tc_ov_wm;
return subport->tc_ov_wm_max;
for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
- tc_ov_consumption[i] =
- subport->tc_credits_per_period[i] - subport->tc_credits[i];
+ tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+ - subport->tc_credits[i];
tc_consumption += tc_ov_consumption[i];
}
tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
- subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+ sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
tc_ov_consumption_max =
- subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+ sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
tc_consumption;
if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
struct rte_sched_grinder *grinder = subport->grinder + pos;
struct rte_sched_pipe *pipe = grinder->pipe;
struct rte_sched_pipe_profile *params = grinder->pipe_params;
+ struct rte_sched_subport_profile *sp = grinder->subport_params;
uint64_t n_periods;
uint32_t i;
/* Subport TB */
- n_periods = (port->time - subport->tb_time) / subport->tb_period;
- subport->tb_credits += n_periods * subport->tb_credits_per_period;
- subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
- subport->tb_time += n_periods * subport->tb_period;
+ n_periods = (port->time - subport->tb_time) / sp->tb_period;
+ subport->tb_credits += n_periods * sp->tb_credits_per_period;
+ subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+ subport->tb_time += n_periods * sp->tb_period;
/* Pipe TB */
n_periods = (port->time - pipe->tb_time) / params->tb_period;
/* Subport TCs */
if (unlikely(port->time >= subport->tc_time)) {
- subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+ subport->tc_ov_wm =
+ grinder_tc_ov_credits_update(port, subport, pos);
for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
- subport->tc_credits[i] = subport->tc_credits_per_period[i];
+ subport->tc_credits[i] = sp->tc_credits_per_period[i];
- subport->tc_time = port->time + subport->tc_period;
+ subport->tc_time = port->time + sp->tc_period;
subport->tc_ov_period_id++;
}
struct rte_sched_pipe *pipe = grinder->pipe;
grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+ grinder->subport_params = port->subport_profiles +
+ subport->profile;
+
grinder_prefetch_tc_queue_arrays(subport, pos);
grinder_credits_update(port, subport, pos);