|
|
|
@ -19,6 +19,9 @@
|
|
|
|
|
#define OTX2_QOS_CLASS_NONE 0
|
|
|
|
|
#define OTX2_QOS_DEFAULT_PRIO 0xF
|
|
|
|
|
#define OTX2_QOS_INVALID_SQ 0xFFFF
|
|
|
|
|
#define OTX2_QOS_INVALID_TXSCHQ_IDX 0xFFFF
|
|
|
|
|
#define CN10K_MAX_RR_WEIGHT GENMASK_ULL(13, 0)
|
|
|
|
|
#define OTX2_MAX_RR_QUANTUM GENMASK_ULL(23, 0)
|
|
|
|
|
|
|
|
|
|
static void otx2_qos_update_tx_netdev_queues(struct otx2_nic *pfvf)
|
|
|
|
|
{
|
|
|
|
@ -65,11 +68,24 @@ static void otx2_qos_get_regaddr(struct otx2_qos_node *node,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_quantum_to_dwrr_weight(struct otx2_nic *pfvf, u32 quantum)
|
|
|
|
|
{
|
|
|
|
|
u32 weight;
|
|
|
|
|
|
|
|
|
|
weight = quantum / pfvf->hw.dwrr_mtu;
|
|
|
|
|
if (quantum % pfvf->hw.dwrr_mtu)
|
|
|
|
|
weight += 1;
|
|
|
|
|
|
|
|
|
|
return weight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void otx2_config_sched_shaping(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *node,
|
|
|
|
|
struct nix_txschq_config *cfg,
|
|
|
|
|
int *num_regs)
|
|
|
|
|
{
|
|
|
|
|
u32 rr_weight;
|
|
|
|
|
u32 quantum;
|
|
|
|
|
u64 maxrate;
|
|
|
|
|
|
|
|
|
|
otx2_qos_get_regaddr(node, cfg, *num_regs);
|
|
|
|
@ -86,8 +102,17 @@ static void otx2_config_sched_shaping(struct otx2_nic *pfvf,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* configure priority */
|
|
|
|
|
cfg->regval[*num_regs] = (node->schq - node->parent->prio_anchor) << 24;
|
|
|
|
|
/* configure priority/quantum */
|
|
|
|
|
if (node->is_static) {
|
|
|
|
|
cfg->regval[*num_regs] =
|
|
|
|
|
(node->schq - node->parent->prio_anchor) << 24;
|
|
|
|
|
} else {
|
|
|
|
|
quantum = node->quantum ?
|
|
|
|
|
node->quantum : pfvf->tx_max_pktlen;
|
|
|
|
|
rr_weight = otx2_qos_quantum_to_dwrr_weight(pfvf, quantum);
|
|
|
|
|
cfg->regval[*num_regs] = node->parent->child_dwrr_prio << 24 |
|
|
|
|
|
rr_weight;
|
|
|
|
|
}
|
|
|
|
|
(*num_regs)++;
|
|
|
|
|
|
|
|
|
|
/* configure PIR */
|
|
|
|
@ -195,9 +220,8 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf,
|
|
|
|
|
cfg->reg[0] = NIX_AF_TL1X_TOPOLOGY(parent->schq);
|
|
|
|
|
|
|
|
|
|
cfg->regval[0] = (u64)parent->prio_anchor << 32;
|
|
|
|
|
if (parent->level == NIX_TXSCH_LVL_TL1)
|
|
|
|
|
cfg->regval[0] |= (u64)TXSCH_TL1_DFLT_RR_PRIO << 1;
|
|
|
|
|
|
|
|
|
|
cfg->regval[0] |= ((parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO) ?
|
|
|
|
|
parent->child_dwrr_prio : 0) << 1;
|
|
|
|
|
cfg->num_regs++;
|
|
|
|
|
|
|
|
|
|
rc = otx2_sync_mbox_msg(&pfvf->mbox);
|
|
|
|
@ -315,9 +339,14 @@ static void otx2_qos_fill_cfg_tl(struct otx2_qos_node *parent,
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(node, &parent->child_list, list) {
|
|
|
|
|
otx2_qos_fill_cfg_tl(node, cfg);
|
|
|
|
|
cfg->schq_contig[node->level]++;
|
|
|
|
|
otx2_qos_fill_cfg_schq(node, cfg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Assign the required number of transmit schedular queues under the
|
|
|
|
|
* given class
|
|
|
|
|
*/
|
|
|
|
|
cfg->schq_contig[parent->level - 1] += parent->child_dwrr_cnt +
|
|
|
|
|
parent->max_static_prio + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void otx2_qos_prepare_txschq_cfg(struct otx2_nic *pfvf,
|
|
|
|
@ -378,10 +407,12 @@ otx2_qos_alloc_root(struct otx2_nic *pfvf)
|
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
|
|
node->parent = NULL;
|
|
|
|
|
if (!is_otx2_vf(pfvf->pcifunc))
|
|
|
|
|
if (!is_otx2_vf(pfvf->pcifunc)) {
|
|
|
|
|
node->level = NIX_TXSCH_LVL_TL1;
|
|
|
|
|
else
|
|
|
|
|
} else {
|
|
|
|
|
node->level = NIX_TXSCH_LVL_TL2;
|
|
|
|
|
node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER);
|
|
|
|
|
node->classid = OTX2_QOS_ROOT_CLASSID;
|
|
|
|
@ -401,9 +432,13 @@ static int otx2_qos_add_child_node(struct otx2_qos_node *parent,
|
|
|
|
|
struct otx2_qos_node *tmp_node;
|
|
|
|
|
struct list_head *tmp;
|
|
|
|
|
|
|
|
|
|
if (node->prio > parent->max_static_prio)
|
|
|
|
|
parent->max_static_prio = node->prio;
|
|
|
|
|
|
|
|
|
|
for (tmp = head->next; tmp != head; tmp = tmp->next) {
|
|
|
|
|
tmp_node = list_entry(tmp, struct otx2_qos_node, list);
|
|
|
|
|
if (tmp_node->prio == node->prio)
|
|
|
|
|
if (tmp_node->prio == node->prio &&
|
|
|
|
|
tmp_node->is_static)
|
|
|
|
|
return -EEXIST;
|
|
|
|
|
if (tmp_node->prio > node->prio) {
|
|
|
|
|
list_add_tail(&node->list, tmp);
|
|
|
|
@ -434,6 +469,10 @@ static int otx2_qos_alloc_txschq_node(struct otx2_nic *pfvf,
|
|
|
|
|
txschq_node->rate = 0;
|
|
|
|
|
txschq_node->ceil = 0;
|
|
|
|
|
txschq_node->prio = 0;
|
|
|
|
|
txschq_node->quantum = 0;
|
|
|
|
|
txschq_node->is_static = true;
|
|
|
|
|
txschq_node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
|
|
|
|
|
txschq_node->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&pfvf->qos.qos_lock);
|
|
|
|
|
list_add_tail(&txschq_node->list, &node->child_schq_list);
|
|
|
|
@ -459,7 +498,7 @@ static struct otx2_qos_node *
|
|
|
|
|
otx2_qos_sw_create_leaf_node(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *parent,
|
|
|
|
|
u16 classid, u32 prio, u64 rate, u64 ceil,
|
|
|
|
|
u16 qid)
|
|
|
|
|
u32 quantum, u16 qid, bool static_cfg)
|
|
|
|
|
{
|
|
|
|
|
struct otx2_qos_node *node;
|
|
|
|
|
int err;
|
|
|
|
@ -476,6 +515,10 @@ otx2_qos_sw_create_leaf_node(struct otx2_nic *pfvf,
|
|
|
|
|
node->rate = otx2_convert_rate(rate);
|
|
|
|
|
node->ceil = otx2_convert_rate(ceil);
|
|
|
|
|
node->prio = prio;
|
|
|
|
|
node->quantum = quantum;
|
|
|
|
|
node->is_static = static_cfg;
|
|
|
|
|
node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
|
|
|
|
|
node->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX;
|
|
|
|
|
|
|
|
|
|
__set_bit(qid, pfvf->qos.qos_sq_bmap);
|
|
|
|
|
|
|
|
|
@ -622,12 +665,28 @@ static int otx2_qos_txschq_alloc(struct otx2_nic *pfvf,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pfvf->qos.link_cfg_lvl = rsp->link_cfg_lvl;
|
|
|
|
|
pfvf->hw.txschq_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
mutex_unlock(&mbox->lock);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void otx2_qos_free_unused_txschq(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_cfg *cfg)
|
|
|
|
|
{
|
|
|
|
|
int lvl, idx, schq;
|
|
|
|
|
|
|
|
|
|
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
|
|
|
|
|
for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) {
|
|
|
|
|
if (!cfg->schq_index_used[lvl][idx]) {
|
|
|
|
|
schq = cfg->schq_contig_list[lvl][idx];
|
|
|
|
|
otx2_txschq_free_one(pfvf, lvl, schq);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void otx2_qos_txschq_fill_cfg_schq(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *node,
|
|
|
|
|
struct otx2_qos_cfg *cfg)
|
|
|
|
@ -652,9 +711,11 @@ static void otx2_qos_txschq_fill_cfg_tl(struct otx2_nic *pfvf,
|
|
|
|
|
list_for_each_entry(tmp, &node->child_list, list) {
|
|
|
|
|
otx2_qos_txschq_fill_cfg_tl(pfvf, tmp, cfg);
|
|
|
|
|
cnt = cfg->static_node_pos[tmp->level];
|
|
|
|
|
tmp->schq = cfg->schq_contig_list[tmp->level][cnt];
|
|
|
|
|
tmp->schq = cfg->schq_contig_list[tmp->level][tmp->txschq_idx];
|
|
|
|
|
cfg->schq_index_used[tmp->level][tmp->txschq_idx] = true;
|
|
|
|
|
if (cnt == 0)
|
|
|
|
|
node->prio_anchor = tmp->schq;
|
|
|
|
|
node->prio_anchor =
|
|
|
|
|
cfg->schq_contig_list[tmp->level][0];
|
|
|
|
|
cfg->static_node_pos[tmp->level]++;
|
|
|
|
|
otx2_qos_txschq_fill_cfg_schq(pfvf, tmp, cfg);
|
|
|
|
|
}
|
|
|
|
@ -667,9 +728,87 @@ static void otx2_qos_txschq_fill_cfg(struct otx2_nic *pfvf,
|
|
|
|
|
mutex_lock(&pfvf->qos.qos_lock);
|
|
|
|
|
otx2_qos_txschq_fill_cfg_tl(pfvf, node, cfg);
|
|
|
|
|
otx2_qos_txschq_fill_cfg_schq(pfvf, node, cfg);
|
|
|
|
|
otx2_qos_free_unused_txschq(pfvf, cfg);
|
|
|
|
|
mutex_unlock(&pfvf->qos.qos_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __otx2_qos_assign_base_idx_tl(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *tmp,
|
|
|
|
|
unsigned long *child_idx_bmap,
|
|
|
|
|
int child_cnt)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
if (tmp->txschq_idx != OTX2_QOS_INVALID_TXSCHQ_IDX)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* assign static nodes 1:1 prio mapping first, then remaining nodes */
|
|
|
|
|
for (idx = 0; idx < child_cnt; idx++) {
|
|
|
|
|
if (tmp->is_static && tmp->prio == idx &&
|
|
|
|
|
!test_bit(idx, child_idx_bmap)) {
|
|
|
|
|
tmp->txschq_idx = idx;
|
|
|
|
|
set_bit(idx, child_idx_bmap);
|
|
|
|
|
return;
|
|
|
|
|
} else if (!tmp->is_static && idx >= tmp->prio &&
|
|
|
|
|
!test_bit(idx, child_idx_bmap)) {
|
|
|
|
|
tmp->txschq_idx = idx;
|
|
|
|
|
set_bit(idx, child_idx_bmap);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_assign_base_idx_tl(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *node)
|
|
|
|
|
{
|
|
|
|
|
unsigned long *child_idx_bmap;
|
|
|
|
|
struct otx2_qos_node *tmp;
|
|
|
|
|
int child_cnt;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(tmp, &node->child_list, list)
|
|
|
|
|
tmp->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX;
|
|
|
|
|
|
|
|
|
|
/* allocate child index array */
|
|
|
|
|
child_cnt = node->child_dwrr_cnt + node->max_static_prio + 1;
|
|
|
|
|
child_idx_bmap = kcalloc(BITS_TO_LONGS(child_cnt),
|
|
|
|
|
sizeof(unsigned long),
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!child_idx_bmap)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
list_for_each_entry(tmp, &node->child_list, list)
|
|
|
|
|
otx2_qos_assign_base_idx_tl(pfvf, tmp);
|
|
|
|
|
|
|
|
|
|
/* assign base index of static priority children first */
|
|
|
|
|
list_for_each_entry(tmp, &node->child_list, list) {
|
|
|
|
|
if (!tmp->is_static)
|
|
|
|
|
continue;
|
|
|
|
|
__otx2_qos_assign_base_idx_tl(pfvf, tmp, child_idx_bmap,
|
|
|
|
|
child_cnt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* assign base index of dwrr priority children */
|
|
|
|
|
list_for_each_entry(tmp, &node->child_list, list)
|
|
|
|
|
__otx2_qos_assign_base_idx_tl(pfvf, tmp, child_idx_bmap,
|
|
|
|
|
child_cnt);
|
|
|
|
|
|
|
|
|
|
kfree(child_idx_bmap);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_assign_base_idx(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *node)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&pfvf->qos.qos_lock);
|
|
|
|
|
ret = otx2_qos_assign_base_idx_tl(pfvf, node);
|
|
|
|
|
mutex_unlock(&pfvf->qos.qos_lock);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_txschq_push_cfg_schq(struct otx2_nic *pfvf,
|
|
|
|
|
struct otx2_qos_node *node,
|
|
|
|
|
struct otx2_qos_cfg *cfg)
|
|
|
|
@ -761,8 +900,10 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)
|
|
|
|
|
|
|
|
|
|
for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
|
|
|
|
|
for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) {
|
|
|
|
|
schq = cfg->schq_contig_list[lvl][idx];
|
|
|
|
|
otx2_txschq_free_one(pfvf, lvl, schq);
|
|
|
|
|
if (cfg->schq_index_used[lvl][idx]) {
|
|
|
|
|
schq = cfg->schq_contig_list[lvl][idx];
|
|
|
|
|
otx2_txschq_free_one(pfvf, lvl, schq);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -838,6 +979,10 @@ static int otx2_qos_push_txschq_cfg(struct otx2_nic *pfvf,
|
|
|
|
|
if (ret)
|
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
|
|
ret = otx2_qos_assign_base_idx(pfvf, node);
|
|
|
|
|
if (ret)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
if (!(pfvf->netdev->flags & IFF_UP)) {
|
|
|
|
|
otx2_qos_txschq_fill_cfg(pfvf, node, cfg);
|
|
|
|
|
return 0;
|
|
|
|
@ -894,6 +1039,13 @@ static int otx2_qos_root_add(struct otx2_nic *pfvf, u16 htb_maj_id, u16 htb_defc
|
|
|
|
|
goto free_root_node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update TL1 RR PRIO */
|
|
|
|
|
if (root->level == NIX_TXSCH_LVL_TL1) {
|
|
|
|
|
root->child_dwrr_prio = pfvf->hw.txschq_aggr_lvl_rr_prio;
|
|
|
|
|
netdev_dbg(pfvf->netdev,
|
|
|
|
|
"TL1 DWRR Priority %d\n", root->child_dwrr_prio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(pfvf->netdev->flags & IFF_UP) ||
|
|
|
|
|
root->level == NIX_TXSCH_LVL_TL1) {
|
|
|
|
|
root->schq = new_cfg->schq_list[root->level][0];
|
|
|
|
@ -940,37 +1092,126 @@ static int otx2_qos_root_destroy(struct otx2_nic *pfvf)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_validate_configuration(struct otx2_qos_node *parent,
|
|
|
|
|
struct netlink_ext_ack *extack,
|
|
|
|
|
struct otx2_nic *pfvf,
|
|
|
|
|
u64 prio)
|
|
|
|
|
static int otx2_qos_validate_quantum(struct otx2_nic *pfvf, u32 quantum)
|
|
|
|
|
{
|
|
|
|
|
if (test_bit(prio, parent->prio_bmap)) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
|
|
|
"Static priority child with same priority exists");
|
|
|
|
|
return -EEXIST;
|
|
|
|
|
u32 rr_weight = otx2_qos_quantum_to_dwrr_weight(pfvf, quantum);
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
/* Max Round robin weight supported by octeontx2 and CN10K
|
|
|
|
|
* is different. Validate accordingly
|
|
|
|
|
*/
|
|
|
|
|
if (is_dev_otx2(pfvf->pdev))
|
|
|
|
|
err = (rr_weight > OTX2_MAX_RR_QUANTUM) ? -EINVAL : 0;
|
|
|
|
|
else if (rr_weight > CN10K_MAX_RR_WEIGHT)
|
|
|
|
|
err = -EINVAL;
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_validate_dwrr_cfg(struct otx2_qos_node *parent,
|
|
|
|
|
struct netlink_ext_ack *extack,
|
|
|
|
|
struct otx2_nic *pfvf,
|
|
|
|
|
u64 prio, u64 quantum)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
err = otx2_qos_validate_quantum(pfvf, quantum);
|
|
|
|
|
if (err) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Unsupported quantum value");
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prio == TXSCH_TL1_DFLT_RR_PRIO) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
|
|
|
"Priority is reserved for Round Robin");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
if (parent->child_dwrr_prio == OTX2_QOS_DEFAULT_PRIO) {
|
|
|
|
|
parent->child_dwrr_prio = prio;
|
|
|
|
|
} else if (prio != parent->child_dwrr_prio) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Only one DWRR group is allowed");
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_validate_configuration(struct otx2_qos_node *parent,
|
|
|
|
|
struct netlink_ext_ack *extack,
|
|
|
|
|
struct otx2_nic *pfvf,
|
|
|
|
|
u64 prio, bool static_cfg)
|
|
|
|
|
{
|
|
|
|
|
if (prio == parent->child_dwrr_prio && static_cfg) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "DWRR child group with same priority exists");
|
|
|
|
|
return -EEXIST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (static_cfg && test_bit(prio, parent->prio_bmap)) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
|
|
|
"Static priority child with same priority exists");
|
|
|
|
|
return -EEXIST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void otx2_reset_dwrr_prio(struct otx2_qos_node *parent, u64 prio)
|
|
|
|
|
{
|
|
|
|
|
/* For PF, root node dwrr priority is static */
|
|
|
|
|
if (parent->level == NIX_TXSCH_LVL_TL1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO) {
|
|
|
|
|
parent->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO;
|
|
|
|
|
clear_bit(prio, parent->prio_bmap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_qos_node_dwrr(struct otx2_qos_node *parent,
|
|
|
|
|
struct otx2_nic *pfvf,
|
|
|
|
|
u64 prio)
|
|
|
|
|
{
|
|
|
|
|
struct otx2_qos_node *node;
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
if (parent->child_dwrr_prio == prio)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&pfvf->qos.qos_lock);
|
|
|
|
|
list_for_each_entry(node, &parent->child_list, list) {
|
|
|
|
|
if (prio == node->prio) {
|
|
|
|
|
if (parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO &&
|
|
|
|
|
parent->child_dwrr_prio != prio)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (otx2_qos_validate_quantum(pfvf, node->quantum)) {
|
|
|
|
|
netdev_err(pfvf->netdev,
|
|
|
|
|
"Unsupported quantum value for existing classid=0x%x quantum=%d prio=%d",
|
|
|
|
|
node->classid, node->quantum,
|
|
|
|
|
node->prio);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* mark old node as dwrr */
|
|
|
|
|
node->is_static = false;
|
|
|
|
|
parent->child_dwrr_cnt++;
|
|
|
|
|
parent->child_static_cnt--;
|
|
|
|
|
ret = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mutex_unlock(&pfvf->qos.qos_lock);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
u32 parent_classid, u64 rate, u64 ceil,
|
|
|
|
|
u64 prio, struct netlink_ext_ack *extack)
|
|
|
|
|
u64 prio, u32 quantum,
|
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
|
{
|
|
|
|
|
struct otx2_qos_cfg *old_cfg, *new_cfg;
|
|
|
|
|
struct otx2_qos_node *node, *parent;
|
|
|
|
|
int qid, ret, err;
|
|
|
|
|
bool static_cfg;
|
|
|
|
|
|
|
|
|
|
netdev_dbg(pfvf->netdev,
|
|
|
|
|
"TC_HTB_LEAF_ALLOC_QUEUE: classid=0x%x parent_classid=0x%x rate=%lld ceil=%lld prio=%lld\n",
|
|
|
|
|
classid, parent_classid, rate, ceil, prio);
|
|
|
|
|
"TC_HTB_LEAF_ALLOC_QUEUE: classid=0x%x parent_classid=0x%x rate=%lld ceil=%lld prio=%lld quantum=%d\n",
|
|
|
|
|
classid, parent_classid, rate, ceil, prio, quantum);
|
|
|
|
|
|
|
|
|
|
if (prio > OTX2_QOS_MAX_PRIO) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Valid priority range 0 to 7");
|
|
|
|
@ -978,6 +1219,12 @@ static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!quantum || quantum > INT_MAX) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Invalid quantum, range 1 - 2147483647 bytes");
|
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get parent node */
|
|
|
|
|
parent = otx2_sw_node_find(pfvf, parent_classid);
|
|
|
|
|
if (!parent) {
|
|
|
|
@ -991,10 +1238,24 @@ static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = otx2_qos_validate_configuration(parent, extack, pfvf, prio);
|
|
|
|
|
static_cfg = !is_qos_node_dwrr(parent, pfvf, prio);
|
|
|
|
|
ret = otx2_qos_validate_configuration(parent, extack, pfvf, prio,
|
|
|
|
|
static_cfg);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (!static_cfg) {
|
|
|
|
|
ret = otx2_qos_validate_dwrr_cfg(parent, extack, pfvf, prio,
|
|
|
|
|
quantum);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (static_cfg)
|
|
|
|
|
parent->child_static_cnt++;
|
|
|
|
|
else
|
|
|
|
|
parent->child_dwrr_cnt++;
|
|
|
|
|
|
|
|
|
|
set_bit(prio, parent->prio_bmap);
|
|
|
|
|
|
|
|
|
|
/* read current txschq configuration */
|
|
|
|
@ -1019,7 +1280,7 @@ static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
|
|
|
|
|
/* allocate and initialize a new child node */
|
|
|
|
|
node = otx2_qos_sw_create_leaf_node(pfvf, parent, classid, prio, rate,
|
|
|
|
|
ceil, qid);
|
|
|
|
|
ceil, quantum, qid, static_cfg);
|
|
|
|
|
if (IS_ERR(node)) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node");
|
|
|
|
|
ret = PTR_ERR(node);
|
|
|
|
@ -1067,6 +1328,11 @@ free_node:
|
|
|
|
|
free_old_cfg:
|
|
|
|
|
kfree(old_cfg);
|
|
|
|
|
reset_prio:
|
|
|
|
|
if (static_cfg)
|
|
|
|
|
parent->child_static_cnt--;
|
|
|
|
|
else
|
|
|
|
|
parent->child_dwrr_cnt--;
|
|
|
|
|
|
|
|
|
|
clear_bit(prio, parent->prio_bmap);
|
|
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
@ -1074,10 +1340,11 @@ out:
|
|
|
|
|
|
|
|
|
|
static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
u16 child_classid, u64 rate, u64 ceil, u64 prio,
|
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
|
u32 quantum, struct netlink_ext_ack *extack)
|
|
|
|
|
{
|
|
|
|
|
struct otx2_qos_cfg *old_cfg, *new_cfg;
|
|
|
|
|
struct otx2_qos_node *node, *child;
|
|
|
|
|
bool static_cfg;
|
|
|
|
|
int ret, err;
|
|
|
|
|
u16 qid;
|
|
|
|
|
|
|
|
|
@ -1091,6 +1358,12 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!quantum || quantum > INT_MAX) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Invalid quantum, range 1 - 2147483647 bytes");
|
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find node related to classid */
|
|
|
|
|
node = otx2_sw_node_find(pfvf, classid);
|
|
|
|
|
if (!node) {
|
|
|
|
@ -1105,6 +1378,19 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static_cfg = !is_qos_node_dwrr(node, pfvf, prio);
|
|
|
|
|
if (!static_cfg) {
|
|
|
|
|
ret = otx2_qos_validate_dwrr_cfg(node, extack, pfvf, prio,
|
|
|
|
|
quantum);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (static_cfg)
|
|
|
|
|
node->child_static_cnt++;
|
|
|
|
|
else
|
|
|
|
|
node->child_dwrr_cnt++;
|
|
|
|
|
|
|
|
|
|
set_bit(prio, node->prio_bmap);
|
|
|
|
|
|
|
|
|
|
/* store the qid to assign to leaf node */
|
|
|
|
@ -1127,7 +1413,8 @@ static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid,
|
|
|
|
|
|
|
|
|
|
/* allocate and initialize a new child node */
|
|
|
|
|
child = otx2_qos_sw_create_leaf_node(pfvf, node, child_classid,
|
|
|
|
|
prio, rate, ceil, qid);
|
|
|
|
|
prio, rate, ceil, quantum,
|
|
|
|
|
qid, static_cfg);
|
|
|
|
|
if (IS_ERR(child)) {
|
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node");
|
|
|
|
|
ret = PTR_ERR(child);
|
|
|
|
@ -1178,6 +1465,10 @@ free_node:
|
|
|
|
|
free_old_cfg:
|
|
|
|
|
kfree(old_cfg);
|
|
|
|
|
reset_prio:
|
|
|
|
|
if (static_cfg)
|
|
|
|
|
node->child_static_cnt--;
|
|
|
|
|
else
|
|
|
|
|
node->child_dwrr_cnt--;
|
|
|
|
|
clear_bit(prio, node->prio_bmap);
|
|
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
@ -1187,6 +1478,7 @@ static int otx2_qos_leaf_del(struct otx2_nic *pfvf, u16 *classid,
|
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
|
{
|
|
|
|
|
struct otx2_qos_node *node, *parent;
|
|
|
|
|
int dwrr_del_node = false;
|
|
|
|
|
u64 prio;
|
|
|
|
|
u16 qid;
|
|
|
|
|
|
|
|
|
@ -1202,12 +1494,27 @@ static int otx2_qos_leaf_del(struct otx2_nic *pfvf, u16 *classid,
|
|
|
|
|
prio = node->prio;
|
|
|
|
|
qid = node->qid;
|
|
|
|
|
|
|
|
|
|
if (!node->is_static)
|
|
|
|
|
dwrr_del_node = true;
|
|
|
|
|
|
|
|
|
|
otx2_qos_disable_sq(pfvf, node->qid);
|
|
|
|
|
|
|
|
|
|
otx2_qos_destroy_node(pfvf, node);
|
|
|
|
|
pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ;
|
|
|
|
|
|
|
|
|
|
clear_bit(prio, parent->prio_bmap);
|
|
|
|
|
if (dwrr_del_node) {
|
|
|
|
|
parent->child_dwrr_cnt--;
|
|
|
|
|
} else {
|
|
|
|
|
parent->child_static_cnt--;
|
|
|
|
|
clear_bit(prio, parent->prio_bmap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset DWRR priority if all dwrr nodes are deleted */
|
|
|
|
|
if (!parent->child_dwrr_cnt)
|
|
|
|
|
otx2_reset_dwrr_prio(parent, prio);
|
|
|
|
|
|
|
|
|
|
if (!parent->child_static_cnt)
|
|
|
|
|
parent->max_static_prio = 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -1217,6 +1524,7 @@ static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force
|
|
|
|
|
{
|
|
|
|
|
struct otx2_qos_node *node, *parent;
|
|
|
|
|
struct otx2_qos_cfg *new_cfg;
|
|
|
|
|
int dwrr_del_node = false;
|
|
|
|
|
u64 prio;
|
|
|
|
|
int err;
|
|
|
|
|
u16 qid;
|
|
|
|
@ -1241,11 +1549,26 @@ static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!node->is_static)
|
|
|
|
|
dwrr_del_node = true;
|
|
|
|
|
|
|
|
|
|
/* destroy the leaf node */
|
|
|
|
|
otx2_qos_destroy_node(pfvf, node);
|
|
|
|
|
pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ;
|
|
|
|
|
|
|
|
|
|
clear_bit(prio, parent->prio_bmap);
|
|
|
|
|
if (dwrr_del_node) {
|
|
|
|
|
parent->child_dwrr_cnt--;
|
|
|
|
|
} else {
|
|
|
|
|
parent->child_static_cnt--;
|
|
|
|
|
clear_bit(prio, parent->prio_bmap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset DWRR priority if all dwrr nodes are deleted */
|
|
|
|
|
if (!parent->child_dwrr_cnt)
|
|
|
|
|
otx2_reset_dwrr_prio(parent, prio);
|
|
|
|
|
|
|
|
|
|
if (!parent->child_static_cnt)
|
|
|
|
|
parent->max_static_prio = 0;
|
|
|
|
|
|
|
|
|
|
/* create downstream txschq entries to parent */
|
|
|
|
|
err = otx2_qos_alloc_txschq_node(pfvf, parent);
|
|
|
|
@ -1298,10 +1621,12 @@ void otx2_qos_config_txschq(struct otx2_nic *pfvf)
|
|
|
|
|
if (!root)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
err = otx2_qos_txschq_config(pfvf, root);
|
|
|
|
|
if (err) {
|
|
|
|
|
netdev_err(pfvf->netdev, "Error update txschq configuration\n");
|
|
|
|
|
goto root_destroy;
|
|
|
|
|
if (root->level != NIX_TXSCH_LVL_TL1) {
|
|
|
|
|
err = otx2_qos_txschq_config(pfvf, root);
|
|
|
|
|
if (err) {
|
|
|
|
|
netdev_err(pfvf->netdev, "Error update txschq configuration\n");
|
|
|
|
|
goto root_destroy;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = otx2_qos_txschq_push_cfg_tl(pfvf, root, NULL);
|
|
|
|
@ -1334,7 +1659,8 @@ int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb)
|
|
|
|
|
res = otx2_qos_leaf_alloc_queue(pfvf, htb->classid,
|
|
|
|
|
htb->parent_classid,
|
|
|
|
|
htb->rate, htb->ceil,
|
|
|
|
|
htb->prio, htb->extack);
|
|
|
|
|
htb->prio, htb->quantum,
|
|
|
|
|
htb->extack);
|
|
|
|
|
if (res < 0)
|
|
|
|
|
return res;
|
|
|
|
|
htb->qid = res;
|
|
|
|
@ -1343,7 +1669,7 @@ int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb)
|
|
|
|
|
return otx2_qos_leaf_to_inner(pfvf, htb->parent_classid,
|
|
|
|
|
htb->classid, htb->rate,
|
|
|
|
|
htb->ceil, htb->prio,
|
|
|
|
|
htb->extack);
|
|
|
|
|
htb->quantum, htb->extack);
|
|
|
|
|
case TC_HTB_LEAF_DEL:
|
|
|
|
|
return otx2_qos_leaf_del(pfvf, &htb->classid, htb->extack);
|
|
|
|
|
case TC_HTB_LEAF_DEL_LAST:
|
|
|
|
|