octeontx2-pf: Add support for HTB offload

This patch registers callbacks to support HTB offload.

Below are features supported,

- supports traffic shaping on the given class by honoring rate and ceil
configuration.

- supports traffic scheduling,  which prioritizes different types of
traffic based on strict priority values.

- supports the creation of leaf to inner classes such that parent node
rate limits apply to all child nodes.

Signed-off-by: Naveen Mamindlapalli <naveenm@marvell.com>
Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
Signed-off-by: Sunil Kovvuri Goutham <sgoutham@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Naveen Mamindlapalli 2023-05-13 14:21:41 +05:30 committed by David S. Miller
parent cb748a7eba
commit 5e6808b4c6
10 changed files with 1507 additions and 14 deletions

View file

@ -142,7 +142,7 @@ enum nix_scheduler {
#define TXSCH_RR_QTM_MAX ((1 << 24) - 1)
#define TXSCH_TL1_DFLT_RR_QTM TXSCH_RR_QTM_MAX
#define TXSCH_TL1_DFLT_RR_PRIO (0x1ull)
#define TXSCH_TL1_DFLT_RR_PRIO (0x7ull)
#define CN10K_MAX_DWRR_WEIGHT 16384 /* Weight is 14bit on CN10K */
/* Min/Max packet sizes, excluding FCS */

View file

@ -8,7 +8,7 @@ obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o otx2_ptp.o
rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \
otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o \
otx2_devlink.o qos_sq.o
otx2_devlink.o qos_sq.o qos.o
rvu_nicvf-y := otx2_vf.o otx2_devlink.o
rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o

View file

@ -89,6 +89,11 @@ int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx)
if (!pfvf->qset.sq)
return 0;
if (qidx >= pfvf->hw.non_qos_queues) {
if (!test_bit(qidx - pfvf->hw.non_qos_queues, pfvf->qos.qos_sq_bmap))
return 0;
}
otx2_nix_sq_op_stats(&sq->stats, pfvf, qidx);
return 1;
}

View file

@ -1099,8 +1099,18 @@ static inline void otx2_qos_init(struct otx2_nic *pfvf, int qos_txqs)
struct otx2_hw *hw = &pfvf->hw;
hw->tc_tx_queues = qos_txqs;
INIT_LIST_HEAD(&pfvf->qos.qos_tree);
mutex_init(&pfvf->qos.qos_lock);
}
static inline void otx2_shutdown_qos(struct otx2_nic *pfvf)
{
mutex_destroy(&pfvf->qos.qos_lock);
}
u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
struct net_device *sb_dev);
int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid);
void otx2_qos_config_txschq(struct otx2_nic *pfvf);
void otx2_clean_qos_queues(struct otx2_nic *pfvf);
#endif /* OTX2_COMMON_H */

View file

@ -1387,6 +1387,9 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
otx2_sq_free_sqbs(pf);
for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
sq = &qset->sq[qidx];
/* Skip freeing Qos queues if they are not initialized */
if (!sq->sqe)
continue;
qmem_free(pf->dev, sq->sqe);
qmem_free(pf->dev, sq->tso_hdrs);
kfree(sq->sg);
@ -1566,6 +1569,8 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
otx2_pfc_txschq_stop(pf);
#endif
otx2_clean_qos_queues(pf);
mutex_lock(&mbox->lock);
/* Disable backpressure */
if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK))
@ -1710,7 +1715,7 @@ int otx2_open(struct net_device *netdev)
if (!qset->cq)
goto err_free_mem;
qset->sq = kcalloc(pf->hw.non_qos_queues,
qset->sq = kcalloc(otx2_get_total_tx_queues(pf),
sizeof(struct otx2_snd_queue), GFP_KERNEL);
if (!qset->sq)
goto err_free_mem;
@ -1833,6 +1838,9 @@ int otx2_open(struct net_device *netdev)
/* 'intf_down' may be checked on any cpu */
smp_wmb();
/* Enable QoS configuration before starting tx queues */
otx2_qos_config_txschq(pf);
/* we have already received link status notification */
if (pf->linfo.link_up && !(pf->pcifunc & RVU_PFVF_FUNC_MASK))
otx2_handle_link_event(pf);
@ -1986,14 +1994,48 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
static int otx2_qos_select_htb_queue(struct otx2_nic *pf, struct sk_buff *skb,
u16 htb_maj_id)
{
u16 classid;
if ((TC_H_MAJ(skb->priority) >> 16) == htb_maj_id)
classid = TC_H_MIN(skb->priority);
else
classid = READ_ONCE(pf->qos.defcls);
if (!classid)
return 0;
return otx2_get_txq_by_classid(pf, classid);
}
u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
struct net_device *sb_dev)
{
#ifdef CONFIG_DCB
struct otx2_nic *pf = netdev_priv(netdev);
bool qos_enabled;
#ifdef CONFIG_DCB
u8 vlan_prio;
#endif
int txq;
qos_enabled = (netdev->real_num_tx_queues > pf->hw.tx_queues) ? true : false;
if (unlikely(qos_enabled)) {
/* This smp_load_acquire() pairs with smp_store_release() in
* otx2_qos_root_add() called from htb offload root creation
*/
u16 htb_maj_id = smp_load_acquire(&pf->qos.maj_id);
if (unlikely(htb_maj_id)) {
txq = otx2_qos_select_htb_queue(pf, skb, htb_maj_id);
if (txq > 0)
return txq;
goto process_pfc;
}
}
process_pfc:
#ifdef CONFIG_DCB
if (!skb_vlan_tag_present(skb))
goto pick_tx;
@ -2007,7 +2049,11 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
pick_tx:
#endif
return netdev_pick_tx(netdev, skb, NULL);
txq = netdev_pick_tx(netdev, skb, NULL);
if (unlikely(qos_enabled))
return txq % pf->hw.tx_queues;
return txq;
}
EXPORT_SYMBOL(otx2_select_queue);
@ -3121,6 +3167,7 @@ static void otx2_remove(struct pci_dev *pdev)
otx2_ptp_destroy(pf);
otx2_mcam_flow_del(pf);
otx2_shutdown_tc(pf);
otx2_shutdown_qos(pf);
otx2_detach_resources(&pf->mbox);
if (pf->hw.lmt_info)
free_percpu(pf->hw.lmt_info);

View file

@ -19,6 +19,7 @@
#include "cn10k.h"
#include "otx2_common.h"
#include "qos.h"
#define CN10K_MAX_BURST_MANTISSA 0x7FFFULL
#define CN10K_MAX_BURST_SIZE 8453888ULL
@ -132,8 +133,8 @@ static void otx2_get_egress_rate_cfg(u64 maxrate, u32 *exp,
}
}
static u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic,
u64 maxrate, u32 burst)
u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic,
u64 maxrate, u32 burst)
{
u32 burst_exp, burst_mantissa;
u32 exp, mantissa, div_exp;
@ -1109,6 +1110,8 @@ int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
return otx2_setup_tc_block(netdev, type_data);
case TC_SETUP_QDISC_HTB:
return otx2_setup_tc_htb(netdev, type_data);
default:
return -EOPNOTSUPP;
}

View file

@ -760,6 +760,7 @@ static void otx2vf_remove(struct pci_dev *pdev)
otx2_ptp_destroy(vf);
otx2_mcam_flow_del(vf);
otx2_shutdown_tc(vf);
otx2_shutdown_qos(vf);
otx2vf_disable_mbox_intr(vf);
otx2_detach_resources(&vf->mbox);
free_percpu(vf->hw.lmt_info);

File diff suppressed because it is too large Load diff

View file

@ -7,13 +7,63 @@
#ifndef OTX2_QOS_H
#define OTX2_QOS_H
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/rhashtable.h>
#define OTX2_QOS_MAX_LVL 4
#define OTX2_QOS_MAX_PRIO 7
#define OTX2_QOS_MAX_LEAF_NODES 16
int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq);
void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq);
enum qos_smq_operations {
QOS_CFG_SQ,
QOS_SMQ_FLUSH,
};
u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic, u64 maxrate, u32 burst);
int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb);
int otx2_qos_get_qid(struct otx2_nic *pfvf);
void otx2_qos_free_qid(struct otx2_nic *pfvf, int qidx);
int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx);
void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx);
struct otx2_qos_cfg {
u16 schq[NIX_TXSCH_LVL_CNT];
u16 schq_contig[NIX_TXSCH_LVL_CNT];
int static_node_pos[NIX_TXSCH_LVL_CNT];
int dwrr_node_pos[NIX_TXSCH_LVL_CNT];
u16 schq_contig_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
u16 schq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC];
};
struct otx2_qos {
u16 qid_to_sqmap[OTX2_QOS_MAX_LEAF_NODES];
};
DECLARE_HASHTABLE(qos_hlist, order_base_2(OTX2_QOS_MAX_LEAF_NODES));
struct mutex qos_lock; /* child list lock */
u16 qid_to_sqmap[OTX2_QOS_MAX_LEAF_NODES];
struct list_head qos_tree;
DECLARE_BITMAP(qos_sq_bmap, OTX2_QOS_MAX_LEAF_NODES);
u16 maj_id;
u16 defcls;
u8 link_cfg_lvl; /* LINKX_CFG CSRs mapped to TL3 or TL2's index ? */
};
struct otx2_qos_node {
struct list_head list; /* list management */
struct list_head child_list;
struct list_head child_schq_list;
struct hlist_node hlist;
DECLARE_BITMAP(prio_bmap, OTX2_QOS_MAX_PRIO + 1);
struct otx2_qos_node *parent; /* parent qos node */
u64 rate; /* htb params */
u64 ceil;
u32 classid;
u32 prio;
u16 schq; /* hw txschq */
u16 qid;
u16 prio_anchor;
u8 level;
};
#endif

View file

@ -217,7 +217,22 @@ static int otx2_qos_ctx_disable(struct otx2_nic *pfvf, u16 qidx, int aura_id)
return otx2_sync_mbox_msg(&pfvf->mbox);
}
int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq)
int otx2_qos_get_qid(struct otx2_nic *pfvf)
{
int qidx;
qidx = find_first_zero_bit(pfvf->qos.qos_sq_bmap,
pfvf->hw.tc_tx_queues);
return qidx == pfvf->hw.tc_tx_queues ? -ENOSPC : qidx;
}
void otx2_qos_free_qid(struct otx2_nic *pfvf, int qidx)
{
clear_bit(qidx, pfvf->qos.qos_sq_bmap);
}
int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx)
{
struct otx2_hw *hw = &pfvf->hw;
int pool_id, sq_idx, err;
@ -233,7 +248,6 @@ int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq)
goto out;
pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx);
pfvf->qos.qid_to_sqmap[qidx] = smq;
err = otx2_sq_init(pfvf, sq_idx, pool_id);
if (err)
goto out;
@ -242,7 +256,7 @@ int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq)
return err;
}
void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq)
void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx)
{
struct otx2_qset *qset = &pfvf->qset;
struct otx2_hw *hw = &pfvf->hw;