mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
net: stmmac: support fp parameter of tc-mqprio
tc-mqprio can select whether traffic classes are express or preemptible.
After some traffic tests, MAC merge layer statistics are all good.
Local device:
ethtool --include-statistics --json --show-mm eth1
[ {
"ifname": "eth1",
"pmac-enabled": true,
"tx-enabled": true,
"tx-active": true,
"tx-min-frag-size": 60,
"rx-min-frag-size": 60,
"verify-enabled": true,
"verify-time": 100,
"max-verify-time": 128,
"verify-status": "SUCCEEDED",
"statistics": {
"MACMergeFrameAssErrorCount": 0,
"MACMergeFrameSmdErrorCount": 0,
"MACMergeFrameAssOkCount": 0,
"MACMergeFragCountRx": 0,
"MACMergeFragCountTx": 35105,
"MACMergeHoldCount": 0
}
} ]
Remote device:
ethtool --include-statistics --json --show-mm end1
[ {
"ifname": "end1",
"pmac-enabled": true,
"tx-enabled": true,
"tx-active": true,
"tx-min-frag-size": 60,
"rx-min-frag-size": 60,
"verify-enabled": true,
"verify-time": 100,
"max-verify-time": 128,
"verify-status": "SUCCEEDED",
"statistics": {
"MACMergeFrameAssErrorCount": 0,
"MACMergeFrameSmdErrorCount": 0,
"MACMergeFrameAssOkCount": 35105,
"MACMergeFragCountRx": 35105,
"MACMergeFragCountTx": 0,
"MACMergeHoldCount": 0
}
} ]
Tested on DWMAC CORE 5.10a
Signed-off-by: Furong Xu <0x1207@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Link: https://patch.msgid.link/592965ea93ed8240f0a1b8f6f8ebb8914f69419b.1725631883.git.0x1207@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
0f156aceee
commit
195e4f409a
|
|
@ -1266,6 +1266,7 @@ const struct stmmac_ops dwmac410_ops = {
|
|||
.fpe_irq_status = dwmac5_fpe_irq_status,
|
||||
.fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
|
||||
.fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
|
||||
.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
|
||||
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
|
||||
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
|
||||
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
|
||||
|
|
@ -1320,6 +1321,7 @@ const struct stmmac_ops dwmac510_ops = {
|
|||
.fpe_irq_status = dwmac5_fpe_irq_status,
|
||||
.fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size,
|
||||
.fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size,
|
||||
.fpe_map_preemption_class = dwmac5_fpe_map_preemption_class,
|
||||
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
|
||||
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
|
||||
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
|
||||
|
|
|
|||
|
|
@ -667,3 +667,58 @@ void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size)
|
|||
writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ),
|
||||
ioaddr + MTL_FPE_CTRL_STS);
|
||||
}
|
||||
|
||||
#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping"
|
||||
#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]"
|
||||
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass)
|
||||
{
|
||||
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
u32 num_tc = ndev->num_tc;
|
||||
|
||||
if (!pclass)
|
||||
goto update_mapping;
|
||||
|
||||
/* DWMAC CORE4+ can not program TC:TXQ mapping to hardware.
|
||||
*
|
||||
* Synopsys Databook:
|
||||
* "The number of Tx DMA channels is equal to the number of Tx queues,
|
||||
* and is direct one-to-one mapping."
|
||||
*/
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
count = ndev->tc_to_txq[tc].count;
|
||||
offset = ndev->tc_to_txq[tc].offset;
|
||||
|
||||
if (pclass & BIT(tc))
|
||||
preemptible_txqs |= GENMASK(offset + count - 1, offset);
|
||||
|
||||
/* This is 1:1 mapping, go to next TC */
|
||||
if (count == 1)
|
||||
continue;
|
||||
|
||||
if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
|
||||
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue_weight = priv->plat->tx_queues_cfg[offset].weight;
|
||||
|
||||
for (u32 i = 1; i < count; i++) {
|
||||
if (priv->plat->tx_queues_cfg[offset + i].weight !=
|
||||
queue_weight) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
|
||||
queue_weight, tc);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_mapping:
|
||||
val = readl(priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS),
|
||||
priv->ioaddr + MTL_FPE_CTRL_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
|
||||
|
||||
#define MTL_FPE_CTRL_STS 0x00000c90
|
||||
/* Preemption Classification */
|
||||
#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8)
|
||||
/* Additional Fragment Size of preempted frames */
|
||||
#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0)
|
||||
|
||||
|
|
@ -115,5 +117,7 @@ void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
|
|||
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev);
|
||||
int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr);
|
||||
void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack, u32 pclass);
|
||||
|
||||
#endif /* __DWMAC5_H__ */
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ static const struct stmmac_hwif_entry {
|
|||
.mac = &dwmac4_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.tc = &dwmac4_tc_ops,
|
||||
.mmc = &dwmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwmac4_setup,
|
||||
|
|
@ -252,7 +252,7 @@ static const struct stmmac_hwif_entry {
|
|||
.mac = &dwxgmac210_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxgmac2_setup,
|
||||
|
|
@ -273,7 +273,7 @@ static const struct stmmac_hwif_entry {
|
|||
.mac = &dwxlgmac2_ops,
|
||||
.hwtimestamp = &stmmac_ptp,
|
||||
.mode = NULL,
|
||||
.tc = &dwmac510_tc_ops,
|
||||
.tc = &dwxgmac_tc_ops,
|
||||
.mmc = &dwxgmac_mmc_ops,
|
||||
.est = &dwmac510_est_ops,
|
||||
.setup = dwxlgmac2_setup,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
#define stmmac_do_void_callback(__priv, __module, __cname, __arg0, __args...) \
|
||||
({ \
|
||||
|
|
@ -428,6 +429,9 @@ struct stmmac_ops {
|
|||
int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev);
|
||||
int (*fpe_get_add_frag_size)(const void __iomem *ioaddr);
|
||||
void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size);
|
||||
int (*fpe_map_preemption_class)(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack,
|
||||
u32 pclass);
|
||||
};
|
||||
|
||||
#define stmmac_core_init(__priv, __args...) \
|
||||
|
|
@ -536,6 +540,8 @@ struct stmmac_ops {
|
|||
stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args)
|
||||
#define stmmac_fpe_set_add_frag_size(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args)
|
||||
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
|
||||
|
||||
/* PTP and HW Timer helpers */
|
||||
struct stmmac_hwtimestamp {
|
||||
|
|
@ -623,6 +629,8 @@ struct stmmac_tc_ops {
|
|||
struct tc_etf_qopt_offload *qopt);
|
||||
int (*query_caps)(struct stmmac_priv *priv,
|
||||
struct tc_query_caps_base *base);
|
||||
int (*setup_mqprio)(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *qopt);
|
||||
};
|
||||
|
||||
#define stmmac_tc_init(__priv, __args...) \
|
||||
|
|
@ -639,6 +647,8 @@ struct stmmac_tc_ops {
|
|||
stmmac_do_callback(__priv, tc, setup_etf, __args)
|
||||
#define stmmac_tc_query_caps(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, query_caps, __args)
|
||||
#define stmmac_tc_setup_mqprio(__priv, __args...) \
|
||||
stmmac_do_callback(__priv, tc, setup_mqprio, __args)
|
||||
|
||||
struct stmmac_counters;
|
||||
|
||||
|
|
@ -682,7 +692,9 @@ extern const struct stmmac_dma_ops dwmac4_dma_ops;
|
|||
extern const struct stmmac_ops dwmac410_ops;
|
||||
extern const struct stmmac_dma_ops dwmac410_dma_ops;
|
||||
extern const struct stmmac_ops dwmac510_ops;
|
||||
extern const struct stmmac_tc_ops dwmac4_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwmac510_tc_ops;
|
||||
extern const struct stmmac_tc_ops dwxgmac_tc_ops;
|
||||
extern const struct stmmac_ops dwxgmac210_ops;
|
||||
extern const struct stmmac_ops dwxlgmac2_ops;
|
||||
extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
|
||||
|
|
|
|||
|
|
@ -6216,6 +6216,8 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
|
|||
switch (type) {
|
||||
case TC_QUERY_CAPS:
|
||||
return stmmac_tc_query_caps(priv, priv, type_data);
|
||||
case TC_SETUP_QDISC_MQPRIO:
|
||||
return stmmac_tc_setup_mqprio(priv, priv, type_data);
|
||||
case TC_SETUP_BLOCK:
|
||||
return flow_block_cb_setup_simple(type_data,
|
||||
&stmmac_block_cb_list,
|
||||
|
|
|
|||
|
|
@ -1174,6 +1174,13 @@ static int tc_query_caps(struct stmmac_priv *priv,
|
|||
struct tc_query_caps_base *base)
|
||||
{
|
||||
switch (base->type) {
|
||||
case TC_SETUP_QDISC_MQPRIO: {
|
||||
struct tc_mqprio_caps *caps = base->caps;
|
||||
|
||||
caps->validate_queue_counts = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case TC_SETUP_QDISC_TAPRIO: {
|
||||
struct tc_taprio_caps *caps = base->caps;
|
||||
|
||||
|
|
@ -1190,6 +1197,81 @@ static int tc_query_caps(struct stmmac_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
static void stmmac_reset_tc_mqprio(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
netdev_reset_tc(ndev);
|
||||
netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
|
||||
stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
|
||||
}
|
||||
|
||||
static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *mqprio)
|
||||
{
|
||||
struct netlink_ext_ack *extack = mqprio->extack;
|
||||
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
|
||||
u32 offset, count, num_stack_tx_queues = 0;
|
||||
struct net_device *ndev = priv->dev;
|
||||
u32 num_tc = qopt->num_tc;
|
||||
int err;
|
||||
|
||||
if (!num_tc) {
|
||||
stmmac_reset_tc_mqprio(ndev, extack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = netdev_set_num_tc(ndev, num_tc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
offset = qopt->offset[tc];
|
||||
count = qopt->count[tc];
|
||||
num_stack_tx_queues += count;
|
||||
|
||||
err = netdev_set_tc_queue(ndev, tc, count, offset);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
}
|
||||
|
||||
err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
|
||||
err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
|
||||
mqprio->preemptible_tcs);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
|
||||
return 0;
|
||||
|
||||
err_reset_tc:
|
||||
stmmac_reset_tc_mqprio(ndev, extack);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tc_setup_mqprio_unimplemented(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *mqprio)
|
||||
{
|
||||
NL_SET_ERR_MSG_MOD(mqprio->extack,
|
||||
"mqprio HW offload is not implemented for this MAC");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
const struct stmmac_tc_ops dwmac4_tc_ops = {
|
||||
.init = tc_init,
|
||||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
.setup_cbs = tc_setup_cbs,
|
||||
.setup_cls = tc_setup_cls,
|
||||
.setup_taprio = tc_setup_taprio,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_mqprio_unimplemented,
|
||||
};
|
||||
|
||||
const struct stmmac_tc_ops dwmac510_tc_ops = {
|
||||
.init = tc_init,
|
||||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
|
|
@ -1198,4 +1280,16 @@ const struct stmmac_tc_ops dwmac510_tc_ops = {
|
|||
.setup_taprio = tc_setup_taprio,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_dwmac510_mqprio,
|
||||
};
|
||||
|
||||
const struct stmmac_tc_ops dwxgmac_tc_ops = {
|
||||
.init = tc_init,
|
||||
.setup_cls_u32 = tc_setup_cls_u32,
|
||||
.setup_cbs = tc_setup_cbs,
|
||||
.setup_cls = tc_setup_cls,
|
||||
.setup_taprio = tc_setup_taprio,
|
||||
.setup_etf = tc_setup_etf,
|
||||
.query_caps = tc_query_caps,
|
||||
.setup_mqprio = tc_setup_mqprio_unimplemented,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user