// SPDX-License-Identifier: GPL-2.0+ /* Microchip Sparx5 Switch driver * * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
*/
#include <net/pkt_cls.h>
#include"sparx5_main.h" #include"sparx5_qos.h"
/* Calculate new base_time based on cycle_time. * * The hardware requires a base_time that is always in the future. * We define threshold_time as current_time + (2 * cycle_time). * If base_time is below threshold_time this function recalculates it to be in * the interval: * threshold_time <= base_time < (threshold_time + cycle_time) * * A very simple algorithm could be like this: * new_base_time = org_base_time + N * cycle_time * using the lowest N so (new_base_time >= threshold_time
*/ void sparx5_new_base_time(struct sparx5 *sparx5, const u32 cycle_time, const ktime_t org_base_time, ktime_t *new_base_time)
{
ktime_t current_time, threshold_time, new_time; struct timespec64 ts;
u64 nr_of_cycles_p2;
u64 nr_of_cycles;
u64 diff_time;
if (new_time >= threshold_time) {
*new_base_time = new_time; return;
}
/* Calculate the smallest power of 2 (nr_of_cycles_p2) * that is larger than nr_of_cycles.
*/ while (nr_of_cycles_p2 < nr_of_cycles)
nr_of_cycles_p2 <<= 1; /* Next (higher) power of 2 */
/* Add as big chunks (power of 2 * cycle_time) * as possible for each power of 2
*/ while (nr_of_cycles_p2) { if (new_time < threshold_time) {
new_time += cycle_time * nr_of_cycles_p2; while (new_time < threshold_time)
new_time += cycle_time * nr_of_cycles_p2;
new_time -= cycle_time * nr_of_cycles_p2;
}
nr_of_cycles_p2 >>= 1; /* Next (lower) power of 2 */
}
new_time += cycle_time;
*new_base_time = new_time;
}
/* Link elements */
spx5_wr(HSCH_SE_CONNECT_SE_LEAK_LINK_SET(idx_next), sparx5,
HSCH_SE_CONNECT(idx));
/* Set the first element. */
spx5_rmw(HSCH_HSCH_LEAK_CFG_LEAK_FIRST_SET(se_first),
HSCH_HSCH_LEAK_CFG_LEAK_FIRST, sparx5,
HSCH_HSCH_LEAK_CFG(layer, group));
/* idx *must* be present in the leak group */
WARN_ON(sparx5_lg_get_adjacent(sparx5, layer, group, idx, &prev, &next,
&first) < 0);
if (sparx5_lg_is_singular(sparx5, layer, group)) {
empty = true;
} elseif (sparx5_lg_is_last(sparx5, layer, group, idx)) { /* idx is removed, prev is now last */
idx = prev;
next = prev;
} elseif (sparx5_lg_is_first(sparx5, layer, group, idx)) { /* idx is removed and points to itself, first is next */
first = next;
next = idx;
} else { /* Next is not touched */
idx = prev;
}
/* Is this SE already shaping ? */ if (sparx5_lg_get_group_by_index(sparx5, layer, idx, &old_group) >= 0) { if (old_group != new_group) { /* Delete from old group */
sparx5_lg_del(sparx5, layer, old_group, idx);
} else { /* Nothing to do here */ return 0;
}
}
/* We always add to head of the list */
first = idx;
if (sparx5_lg_is_empty(sparx5, layer, new_group))
next = idx; else
next = sparx5_lg_get_first(sparx5, layer, new_group);
/* Number of *lower* indexes that are arbitrated dwrr */
spx5_rmw(HSCH_SE_CFG_SE_DWRR_CNT_SET(dwrr->count),
HSCH_SE_CFG_SE_DWRR_CNT, port->sparx5,
HSCH_SE_CFG(port->portno));
for (i = 0; i < dwrr->count; i++) {
spx5_rmw(HSCH_DWRR_ENTRY_DWRR_COST_SET(dwrr->cost[i]),
HSCH_DWRR_ENTRY_DWRR_COST, port->sparx5,
HSCH_DWRR_ENTRY(i));
}
for (i = 0; i < SPX5_HSCH_LAYER_CNT; i++) {
layer = &layers[i]; for (ii = 0; ii < SPX5_HSCH_LEAK_GRP_CNT; ii++) {
lg = &layer->leak_groups[ii];
lg->max_rate = ops->get_hsch_max_group_rate(i);
/* Calculate the leak time in us, to serve a maximum * rate of 'max_rate' for this group
*/
leak_time_us = (SPX5_SE_RATE_MAX * 1000) / lg->max_rate;
/* Hardware wants leak time in ns */
lg->leak_time = 1000 * leak_time_us;
/* Find suitable group for this se */ if (sparx5_lg_get_group_by_rate(layer, sh.rate, &group) < 0) {
pr_debug("Could not find leak group for se with rate: %d",
sh.rate); return -EINVAL;
}
lg = &layers[layer].leak_groups[group];
pr_debug("Found matching group (speed: %d)\n", lg->max_rate);
if (sh.rate < SPX5_SE_RATE_MIN || sh.burst < SPX5_SE_BURST_MIN) return -EINVAL;
int sparx5_tc_ets_add(struct sparx5_port *port, struct tc_ets_qopt_offload_replace_params *params)
{ struct sparx5_dwrr dwrr = {0}; /* Minimum weight for each iteration */ unsignedint w_min = 100; int i;
/* Find minimum weight for all dwrr bands */ for (i = 0; i < SPX5_PRIOS; i++) { if (params->quanta[i] == 0) continue;
w_min = min(w_min, params->weights[i]);
}
for (i = 0; i < SPX5_PRIOS; i++) { /* Strict band; skip */ if (params->quanta[i] == 0) continue;
dwrr.count++;
/* On the sparx5, bands with higher indexes are preferred and * arbitrated strict. Strict bands are put in the lower indexes, * by tc, so we reverse the bands here. * * Also convert the weight to something the hardware * understands.
*/
dwrr.cost[SPX5_PRIOS - i - 1] =
sparx5_weight_to_hw_cost(w_min, params->weights[i]);
}
return sparx5_dwrr_conf_set(port, &dwrr);
}
int sparx5_tc_ets_del(struct sparx5_port *port)
{ struct sparx5_dwrr dwrr = {0};
return sparx5_dwrr_conf_set(port, &dwrr);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.