mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
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:
parent
cb748a7eba
commit
5e6808b4c6
@ -142,7 +142,7 @@ enum nix_scheduler {
|
|||||||
|
|
||||||
#define TXSCH_RR_QTM_MAX ((1 << 24) - 1)
|
#define TXSCH_RR_QTM_MAX ((1 << 24) - 1)
|
||||||
#define TXSCH_TL1_DFLT_RR_QTM TXSCH_RR_QTM_MAX
|
#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 */
|
#define CN10K_MAX_DWRR_WEIGHT 16384 /* Weight is 14bit on CN10K */
|
||||||
|
|
||||||
/* Min/Max packet sizes, excluding FCS */
|
/* Min/Max packet sizes, excluding FCS */
|
||||||
|
@ -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 \
|
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_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_nicvf-y := otx2_vf.o otx2_devlink.o
|
||||||
|
|
||||||
rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o
|
rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o
|
||||||
|
@ -89,6 +89,11 @@ int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx)
|
|||||||
if (!pfvf->qset.sq)
|
if (!pfvf->qset.sq)
|
||||||
return 0;
|
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);
|
otx2_nix_sq_op_stats(&sq->stats, pfvf, qidx);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1099,8 +1099,18 @@ static inline void otx2_qos_init(struct otx2_nic *pfvf, int qos_txqs)
|
|||||||
struct otx2_hw *hw = &pfvf->hw;
|
struct otx2_hw *hw = &pfvf->hw;
|
||||||
|
|
||||||
hw->tc_tx_queues = qos_txqs;
|
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,
|
u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
|
||||||
struct net_device *sb_dev);
|
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 */
|
#endif /* OTX2_COMMON_H */
|
||||||
|
@ -1387,6 +1387,9 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
|
|||||||
otx2_sq_free_sqbs(pf);
|
otx2_sq_free_sqbs(pf);
|
||||||
for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
|
for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
|
||||||
sq = &qset->sq[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->sqe);
|
||||||
qmem_free(pf->dev, sq->tso_hdrs);
|
qmem_free(pf->dev, sq->tso_hdrs);
|
||||||
kfree(sq->sg);
|
kfree(sq->sg);
|
||||||
@ -1566,6 +1569,8 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
|
|||||||
otx2_pfc_txschq_stop(pf);
|
otx2_pfc_txschq_stop(pf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
otx2_clean_qos_queues(pf);
|
||||||
|
|
||||||
mutex_lock(&mbox->lock);
|
mutex_lock(&mbox->lock);
|
||||||
/* Disable backpressure */
|
/* Disable backpressure */
|
||||||
if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK))
|
if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK))
|
||||||
@ -1710,7 +1715,7 @@ int otx2_open(struct net_device *netdev)
|
|||||||
if (!qset->cq)
|
if (!qset->cq)
|
||||||
goto err_free_mem;
|
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);
|
sizeof(struct otx2_snd_queue), GFP_KERNEL);
|
||||||
if (!qset->sq)
|
if (!qset->sq)
|
||||||
goto err_free_mem;
|
goto err_free_mem;
|
||||||
@ -1833,6 +1838,9 @@ int otx2_open(struct net_device *netdev)
|
|||||||
/* 'intf_down' may be checked on any cpu */
|
/* 'intf_down' may be checked on any cpu */
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
|
|
||||||
|
/* Enable QoS configuration before starting tx queues */
|
||||||
|
otx2_qos_config_txschq(pf);
|
||||||
|
|
||||||
/* we have already received link status notification */
|
/* we have already received link status notification */
|
||||||
if (pf->linfo.link_up && !(pf->pcifunc & RVU_PFVF_FUNC_MASK))
|
if (pf->linfo.link_up && !(pf->pcifunc & RVU_PFVF_FUNC_MASK))
|
||||||
otx2_handle_link_event(pf);
|
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;
|
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,
|
u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
|
||||||
struct net_device *sb_dev)
|
struct net_device *sb_dev)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_DCB
|
|
||||||
struct otx2_nic *pf = netdev_priv(netdev);
|
struct otx2_nic *pf = netdev_priv(netdev);
|
||||||
|
bool qos_enabled;
|
||||||
|
#ifdef CONFIG_DCB
|
||||||
u8 vlan_prio;
|
u8 vlan_prio;
|
||||||
#endif
|
#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
|
#ifdef CONFIG_DCB
|
||||||
if (!skb_vlan_tag_present(skb))
|
if (!skb_vlan_tag_present(skb))
|
||||||
goto pick_tx;
|
goto pick_tx;
|
||||||
@ -2007,7 +2049,11 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb,
|
|||||||
|
|
||||||
pick_tx:
|
pick_tx:
|
||||||
#endif
|
#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);
|
EXPORT_SYMBOL(otx2_select_queue);
|
||||||
|
|
||||||
@ -3121,6 +3167,7 @@ static void otx2_remove(struct pci_dev *pdev)
|
|||||||
otx2_ptp_destroy(pf);
|
otx2_ptp_destroy(pf);
|
||||||
otx2_mcam_flow_del(pf);
|
otx2_mcam_flow_del(pf);
|
||||||
otx2_shutdown_tc(pf);
|
otx2_shutdown_tc(pf);
|
||||||
|
otx2_shutdown_qos(pf);
|
||||||
otx2_detach_resources(&pf->mbox);
|
otx2_detach_resources(&pf->mbox);
|
||||||
if (pf->hw.lmt_info)
|
if (pf->hw.lmt_info)
|
||||||
free_percpu(pf->hw.lmt_info);
|
free_percpu(pf->hw.lmt_info);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "cn10k.h"
|
#include "cn10k.h"
|
||||||
#include "otx2_common.h"
|
#include "otx2_common.h"
|
||||||
|
#include "qos.h"
|
||||||
|
|
||||||
#define CN10K_MAX_BURST_MANTISSA 0x7FFFULL
|
#define CN10K_MAX_BURST_MANTISSA 0x7FFFULL
|
||||||
#define CN10K_MAX_BURST_SIZE 8453888ULL
|
#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 otx2_get_txschq_rate_regval(struct otx2_nic *nic,
|
||||||
u64 maxrate, u32 burst)
|
u64 maxrate, u32 burst)
|
||||||
{
|
{
|
||||||
u32 burst_exp, burst_mantissa;
|
u32 burst_exp, burst_mantissa;
|
||||||
u32 exp, mantissa, div_exp;
|
u32 exp, mantissa, div_exp;
|
||||||
@ -1109,6 +1110,8 @@ int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case TC_SETUP_BLOCK:
|
case TC_SETUP_BLOCK:
|
||||||
return otx2_setup_tc_block(netdev, type_data);
|
return otx2_setup_tc_block(netdev, type_data);
|
||||||
|
case TC_SETUP_QDISC_HTB:
|
||||||
|
return otx2_setup_tc_htb(netdev, type_data);
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -760,6 +760,7 @@ static void otx2vf_remove(struct pci_dev *pdev)
|
|||||||
otx2_ptp_destroy(vf);
|
otx2_ptp_destroy(vf);
|
||||||
otx2_mcam_flow_del(vf);
|
otx2_mcam_flow_del(vf);
|
||||||
otx2_shutdown_tc(vf);
|
otx2_shutdown_tc(vf);
|
||||||
|
otx2_shutdown_qos(vf);
|
||||||
otx2vf_disable_mbox_intr(vf);
|
otx2vf_disable_mbox_intr(vf);
|
||||||
otx2_detach_resources(&vf->mbox);
|
otx2_detach_resources(&vf->mbox);
|
||||||
free_percpu(vf->hw.lmt_info);
|
free_percpu(vf->hw.lmt_info);
|
||||||
|
1363
drivers/net/ethernet/marvell/octeontx2/nic/qos.c
Normal file
1363
drivers/net/ethernet/marvell/octeontx2/nic/qos.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,63 @@
|
|||||||
#ifndef OTX2_QOS_H
|
#ifndef OTX2_QOS_H
|
||||||
#define 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
|
#define OTX2_QOS_MAX_LEAF_NODES 16
|
||||||
|
|
||||||
int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq);
|
enum qos_smq_operations {
|
||||||
void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq);
|
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 {
|
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
|
#endif
|
||||||
|
@ -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);
|
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;
|
struct otx2_hw *hw = &pfvf->hw;
|
||||||
int pool_id, sq_idx, err;
|
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;
|
goto out;
|
||||||
|
|
||||||
pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx);
|
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);
|
err = otx2_sq_init(pfvf, sq_idx, pool_id);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
@ -242,7 +256,7 @@ out:
|
|||||||
return err;
|
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_qset *qset = &pfvf->qset;
|
||||||
struct otx2_hw *hw = &pfvf->hw;
|
struct otx2_hw *hw = &pfvf->hw;
|
||||||
|
Loading…
Reference in New Issue
Block a user