Commit f7d29571 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'add-kernel-tc-mqprio-and-tc-taprio-support-for-preemptible-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: default avatarJakub Kicinski <kuba@kernel.org>
parents 85a4abed 01e23b2b
Loading
Loading
Loading
Loading
+27 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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);
@@ -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:
+1 −0
Original line number Diff line number Diff line
@@ -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);
+4 −0
Original line number Diff line number Diff line
@@ -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)
+6 −0
Original line number Diff line number Diff line
@@ -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)
@@ -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 −0
Original line number Diff line number Diff line
@@ -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 {
@@ -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;
Loading