Skip to content

Commit

Permalink
Merge branch 'add-kernel-tc-mqprio-and-tc-taprio-support-for-preempti…
Browse files Browse the repository at this point in the history
…ble-traffic-classes'

Vladimir Oltean says:

====================
Add kernel tc-mqprio and tc-taprio support for preemptible traffic classes

The last RFC in August 2022 contained a proposal for the UAPI of both
TSN standards which together form Frame Preemption (802.1Q and 802.3):
https://lore.kernel.org/netdev/20220816222920.1952936-1-vladimir.oltean@nxp.com/

It wasn't clear at the time whether the 802.1Q portion of Frame Preemption
should be exposed via the tc qdisc (mqprio, taprio) or via some other
layer (perhaps also ethtool like the 802.3 portion, or dcbnl), even
though the options were discussed extensively, with pros and cons:
https://lore.kernel.org/netdev/20220816222920.1952936-3-vladimir.oltean@nxp.com/

So the 802.3 portion got submitted separately and finally was accepted:
https://lore.kernel.org/netdev/20230119122705.73054-1-vladimir.oltean@nxp.com/

leaving the only remaining question: how do we expose the 802.1Q bits?

This series proposes that we use the Qdisc layer, through separate
(albeit very similar) UAPI in mqprio and taprio, and that both these
Qdiscs pass the information down to the offloading device driver through
the common mqprio offload structure (which taprio also passes).

An implementation is provided for the NXP LS1028A on-board Ethernet
endpoint (enetc). Previous versions also contained support for its
embedded switch (felix), but this needs more work and will be submitted
separately.

v4: https://lore.kernel.org/netdev/20230403103440.2895683-1-vladimir.oltean@nxp.com/
v2: https://lore.kernel.org/netdev/20230219135309.594188-1-vladimir.oltean@nxp.com/
v1: https://lore.kernel.org/netdev/20230216232126.3402975-1-vladimir.oltean@nxp.com/
====================

Link: https://lore.kernel.org/r/20230411180157.1850527-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Apr 14, 2023
2 parents 85a4abe + 01e23b2 commit f7d2957
Show file tree
Hide file tree
Showing 11 changed files with 324 additions and 42 deletions.
31 changes: 27 additions & 4 deletions drivers/net/ethernet/freescale/enetc/enetc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val)
}
EXPORT_SYMBOL_GPL(enetc_port_mac_wr);

void enetc_set_ptcfpr(struct enetc_hw *hw, unsigned long preemptible_tcs)
{
u32 val;
int tc;

for (tc = 0; tc < 8; tc++) {
val = enetc_port_rd(hw, ENETC_PTCFPR(tc));

if (preemptible_tcs & BIT(tc))
val |= ENETC_PTCFPR_FPE;
else
val &= ~ENETC_PTCFPR_FPE;

enetc_port_wr(hw, ENETC_PTCFPR(tc), val);
}
}
EXPORT_SYMBOL_GPL(enetc_set_ptcfpr);

static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv)
{
int num_tx_rings = priv->num_tx_rings;
Expand Down Expand Up @@ -2640,16 +2658,19 @@ static void enetc_reset_tc_mqprio(struct net_device *ndev)
}

enetc_debug_tx_ring_prios(priv);

enetc_set_ptcfpr(hw, 0);
}

int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
{
struct tc_mqprio_qopt_offload *mqprio = type_data;
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct tc_mqprio_qopt *mqprio = type_data;
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
struct enetc_hw *hw = &priv->si->hw;
int num_stack_tx_queues = 0;
u8 num_tc = mqprio->num_tc;
struct enetc_bdr *tx_ring;
u8 num_tc = qopt->num_tc;
int offset, count;
int err, tc, q;

Expand All @@ -2663,8 +2684,8 @@ int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
return err;

for (tc = 0; tc < num_tc; tc++) {
offset = mqprio->offset[tc];
count = mqprio->count[tc];
offset = qopt->offset[tc];
count = qopt->count[tc];
num_stack_tx_queues += count;

err = netdev_set_tc_queue(ndev, tc, count, offset);
Expand Down Expand Up @@ -2693,6 +2714,8 @@ int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)

enetc_debug_tx_ring_prios(priv);

enetc_set_ptcfpr(hw, mqprio->preemptible_tcs);

return 0;

err_reset_tc:
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/freescale/enetc/enetc.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ static inline void enetc_cbd_free_data_mem(struct enetc_si *si, int size,

void enetc_reset_ptcmsdur(struct enetc_hw *hw);
void enetc_set_ptcmsdur(struct enetc_hw *hw, u32 *queue_max_sdu);
void enetc_set_ptcfpr(struct enetc_hw *hw, unsigned long preemptible_tcs);

#ifdef CONFIG_FSL_ENETC_QOS
int enetc_qos_query_caps(struct net_device *ndev, void *type_data);
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/freescale/enetc/enetc_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,10 @@ static inline u32 enetc_usecs_to_cycles(u32 usecs)
return (u32)div_u64(usecs * ENETC_CLK, 1000000ULL);
}

/* Port traffic class frame preemption register */
#define ENETC_PTCFPR(n) (0x1910 + (n) * 4) /* n = [0 ..7] */
#define ENETC_PTCFPR_FPE BIT(31)

/* port time gating control register */
#define ENETC_PTGCR 0x11a00
#define ENETC_PTGCR_TGE BIT(31)
Expand Down
6 changes: 6 additions & 0 deletions include/linux/ethtool_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void ethtool_aggregate_pause_stats(struct net_device *dev,
struct ethtool_pause_stats *pause_stats);
void ethtool_aggregate_rmon_stats(struct net_device *dev,
struct ethtool_rmon_stats *rmon_stats);
bool ethtool_dev_mm_supported(struct net_device *dev);

#else
static inline int ethnl_cable_test_alloc(struct phy_device *phydev, u8 cmd)
Expand Down Expand Up @@ -112,5 +113,10 @@ ethtool_aggregate_rmon_stats(struct net_device *dev,
{
}

static inline bool ethtool_dev_mm_supported(struct net_device *dev)
{
return false;
}

#endif /* IS_ENABLED(CONFIG_ETHTOOL_NETLINK) */
#endif /* _LINUX_ETHTOOL_NETLINK_H_ */
3 changes: 3 additions & 0 deletions include/net/pkt_sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,13 @@ struct tc_mqprio_caps {
struct tc_mqprio_qopt_offload {
/* struct tc_mqprio_qopt must always be the first element */
struct tc_mqprio_qopt qopt;
struct netlink_ext_ack *extack;
u16 mode;
u16 shaper;
u32 flags;
u64 min_rate[TC_QOPT_MAX_QUEUE];
u64 max_rate[TC_QOPT_MAX_QUEUE];
unsigned long preemptible_tcs;
};

struct tc_taprio_caps {
Expand All @@ -193,6 +195,7 @@ struct tc_taprio_sched_entry {

struct tc_taprio_qopt_offload {
struct tc_mqprio_qopt_offload mqprio;
struct netlink_ext_ack *extack;
u8 enable;
ktime_t base_time;
u64 cycle_time;
Expand Down
17 changes: 17 additions & 0 deletions include/uapi/linux/pkt_sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,11 @@ enum {

#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)

enum {
TC_FP_EXPRESS = 1,
TC_FP_PREEMPTIBLE = 2,
};

struct tc_mqprio_qopt {
__u8 num_tc;
__u8 prio_tc_map[TC_QOPT_BITMASK + 1];
Expand All @@ -732,12 +737,23 @@ struct tc_mqprio_qopt {
#define TC_MQPRIO_F_MIN_RATE 0x4
#define TC_MQPRIO_F_MAX_RATE 0x8

enum {
TCA_MQPRIO_TC_ENTRY_UNSPEC,
TCA_MQPRIO_TC_ENTRY_INDEX, /* u32 */
TCA_MQPRIO_TC_ENTRY_FP, /* u32 */

/* add new constants above here */
__TCA_MQPRIO_TC_ENTRY_CNT,
TCA_MQPRIO_TC_ENTRY_MAX = (__TCA_MQPRIO_TC_ENTRY_CNT - 1)
};

enum {
TCA_MQPRIO_UNSPEC,
TCA_MQPRIO_MODE,
TCA_MQPRIO_SHAPER,
TCA_MQPRIO_MIN_RATE64,
TCA_MQPRIO_MAX_RATE64,
TCA_MQPRIO_TC_ENTRY,
__TCA_MQPRIO_MAX,
};

Expand Down Expand Up @@ -1236,6 +1252,7 @@ enum {
TCA_TAPRIO_TC_ENTRY_UNSPEC,
TCA_TAPRIO_TC_ENTRY_INDEX, /* u32 */
TCA_TAPRIO_TC_ENTRY_MAX_SDU, /* u32 */
TCA_TAPRIO_TC_ENTRY_FP, /* u32 */

/* add new constants above here */
__TCA_TAPRIO_TC_ENTRY_CNT,
Expand Down
23 changes: 23 additions & 0 deletions net/ethtool/mm.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,26 @@ bool __ethtool_dev_mm_supported(struct net_device *dev)

return !ret;
}

bool ethtool_dev_mm_supported(struct net_device *dev)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
bool supported;
int ret;

ASSERT_RTNL();

if (!ops)
return false;

ret = ethnl_ops_begin(dev);
if (ret < 0)
return false;

supported = __ethtool_dev_mm_supported(dev);

ethnl_ops_complete(dev);

return supported;
}
EXPORT_SYMBOL_GPL(ethtool_dev_mm_supported);
Loading

0 comments on commit f7d2957

Please sign in to comment.