Commit eb55d7b6 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tc-gate-offload-for-SJA1105-DSA-switch'

Vladimir Oltean says:

====================
tc-gate offload for SJA1105 DSA switch

Expose the TTEthernet hardware features of the switch using standard
tc-flower actions: trap, drop, redirect and gate.

v1 was submitted at:
https://patchwork.ozlabs.org/project/netdev/cover/20200503211035.19363-1-olteanv@gmail.com/

v2 was submitted at:
https://patchwork.ozlabs.org/project/netdev/cover/20200503211035.19363-1-olteanv@gmail.com/



Changes in v3:
Made sure there are no compilation warnings when
CONFIG_NET_DSA_SJA1105_TAS or CONFIG_NET_DSA_SJA1105_VL are disabled.

Changes in v2:
Using a newly introduced dsa_port_from_netdev public helper.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bb206a08 47cfa3af
Loading
Loading
Loading
Loading
+116 −0
Original line number Diff line number Diff line
@@ -230,6 +230,122 @@ simultaneously on two ports. The driver checks the consistency of the schedules
against this restriction and errors out when appropriate. Schedule analysis is
needed to avoid this, which is outside the scope of the document.

Routing actions (redirect, trap, drop)
--------------------------------------

The switch is able to offload flow-based redirection of packets to a set of
destination ports specified by the user. Internally, this is implemented by
making use of Virtual Links, a TTEthernet concept.

The driver supports 2 types of keys for Virtual Links:

- VLAN-aware virtual links: these match on destination MAC address, VLAN ID and
  VLAN PCP.
- VLAN-unaware virtual links: these match on destination MAC address only.

The VLAN awareness state of the bridge (vlan_filtering) cannot be changed while
there are virtual link rules installed.

Composing multiple actions inside the same rule is supported. When only routing
actions are requested, the driver creates a "non-critical" virtual link. When
the action list also contains tc-gate (more details below), the virtual link
becomes "time-critical" (draws frame buffers from a reserved memory partition,
etc).

The 3 routing actions that are supported are "trap", "drop" and "redirect".

Example 1: send frames received on swp2 with a DA of 42:be:24:9b:76:20 to the
CPU and to swp3. This type of key (DA only) when the port's VLAN awareness
state is off::

  tc qdisc add dev swp2 clsact
  tc filter add dev swp2 ingress flower skip_sw dst_mac 42:be:24:9b:76:20 \
          action mirred egress redirect dev swp3 \
          action trap

Example 2: drop frames received on swp2 with a DA of 42:be:24:9b:76:20, a VID
of 100 and a PCP of 0::

  tc filter add dev swp2 ingress protocol 802.1Q flower skip_sw \
          dst_mac 42:be:24:9b:76:20 vlan_id 100 vlan_prio 0 action drop

Time-based ingress policing
---------------------------

The TTEthernet hardware abilities of the switch can be constrained to act
similarly to the Per-Stream Filtering and Policing (PSFP) clause specified in
IEEE 802.1Q-2018 (formerly 802.1Qci). This means it can be used to perform
tight timing-based admission control for up to 1024 flows (identified by a
tuple composed of destination MAC address, VLAN ID and VLAN PCP). Packets which
are received outside their expected reception window are dropped.

This capability can be managed through the offload of the tc-gate action. As
routing actions are intrinsic to virtual links in TTEthernet (which performs
explicit routing of time-critical traffic and does not leave that in the hands
of the FDB, flooding etc), the tc-gate action may never appear alone when
asking sja1105 to offload it. One (or more) redirect or trap actions must also
follow along.

Example: create a tc-taprio schedule that is phase-aligned with a tc-gate
schedule (the clocks must be synchronized by a 1588 application stack, which is
outside the scope of this document). No packet delivered by the sender will be
dropped. Note that the reception window is larger than the transmission window
(and much more so, in this example) to compensate for the packet propagation
delay of the link (which can be determined by the 1588 application stack).

Receiver (sja1105)::

  tc qdisc add dev swp2 clsact
  now=$(phc_ctl /dev/ptp1 get | awk '/clock time is/ {print $5}') && \
          sec=$(echo $now | awk -F. '{print $1}') && \
          base_time="$(((sec + 2) * 1000000000))" && \
          echo "base time ${base_time}"
  tc filter add dev swp2 ingress flower skip_sw \
          dst_mac 42:be:24:9b:76:20 \
          action gate base-time ${base_time} \
          sched-entry OPEN  60000 -1 -1 \
          sched-entry CLOSE 40000 -1 -1 \
          action trap

Sender::

  now=$(phc_ctl /dev/ptp0 get | awk '/clock time is/ {print $5}') && \
          sec=$(echo $now | awk -F. '{print $1}') && \
          base_time="$(((sec + 2) * 1000000000))" && \
          echo "base time ${base_time}"
  tc qdisc add dev eno0 parent root taprio \
          num_tc 8 \
          map 0 1 2 3 4 5 6 7 \
          queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
          base-time ${base_time} \
          sched-entry S 01  50000 \
          sched-entry S 00  50000 \
          flags 2

The engine used to schedule the ingress gate operations is the same that the
one used for the tc-taprio offload. Therefore, the restrictions regarding the
fact that no two gate actions (either tc-gate or tc-taprio gates) may fire at
the same time (during the same 200 ns slot) still apply.

To come in handy, it is possible to share time-triggered virtual links across
more than 1 ingress port, via flow blocks. In this case, the restriction of
firing at the same time does not apply because there is a single schedule in
the system, that of the shared virtual link::

  tc qdisc add dev swp2 ingress_block 1 clsact
  tc qdisc add dev swp3 ingress_block 1 clsact
  tc filter add block 1 flower skip_sw dst_mac 42:be:24:9b:76:20 \
          action gate index 2 \
          base-time 0 \
          sched-entry OPEN 50000000 -1 -1 \
          sched-entry CLOSE 50000000 -1 -1 \
          action trap

Hardware statistics for each flow are also available ("pkts" counts the number
of dropped frames, which is a sum of frames dropped due to timing violations,
lack of destination ports and MTU enforcement checks). Byte-level counters are
not available.

Device Tree bindings and board design
=====================================

+9 −0
Original line number Diff line number Diff line
@@ -34,3 +34,12 @@ config NET_DSA_SJA1105_TAS
	  This enables support for the TTEthernet-based egress scheduling
	  engine in the SJA1105 DSA driver, which is controlled using a
	  hardware offload of the tc-tqprio qdisc.

config NET_DSA_SJA1105_VL
	bool "Support for Virtual Links on NXP SJA1105"
	depends on NET_DSA_SJA1105_TAS
	help
	  This enables support for flow classification using capable devices
	  (SJA1105T, SJA1105Q, SJA1105S). The following actions are supported:
	  - redirect, trap, drop
	  - time-based ingress policing, via the tc-gate action
+4 −0
Original line number Diff line number Diff line
@@ -17,3 +17,7 @@ endif
ifdef CONFIG_NET_DSA_SJA1105_TAS
sja1105-objs += sja1105_tas.o
endif

ifdef CONFIG_NET_DSA_SJA1105_VL
sja1105-objs += sja1105_vl.o
endif
+58 −1
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct sja1105_regs {
	u64 status;
	u64 port_control;
	u64 rgu;
	u64 vl_status;
	u64 config;
	u64 sgmii;
	u64 rmii_pll1;
@@ -97,17 +98,52 @@ struct sja1105_info {
	const char *name;
};

enum sja1105_key_type {
	SJA1105_KEY_BCAST,
	SJA1105_KEY_TC,
	SJA1105_KEY_VLAN_UNAWARE_VL,
	SJA1105_KEY_VLAN_AWARE_VL,
};

struct sja1105_key {
	enum sja1105_key_type type;

	union {
		/* SJA1105_KEY_TC */
		struct {
			int pcp;
		} tc;

		/* SJA1105_KEY_VLAN_UNAWARE_VL */
		/* SJA1105_KEY_VLAN_AWARE_VL */
		struct {
			u64 dmac;
			u16 vid;
			u16 pcp;
		} vl;
	};
};

enum sja1105_rule_type {
	SJA1105_RULE_BCAST_POLICER,
	SJA1105_RULE_TC_POLICER,
	SJA1105_RULE_VL,
};

enum sja1105_vl_type {
	SJA1105_VL_NONCRITICAL,
	SJA1105_VL_RATE_CONSTRAINED,
	SJA1105_VL_TIME_TRIGGERED,
};

struct sja1105_rule {
	struct list_head list;
	unsigned long cookie;
	unsigned long port_mask;
	struct sja1105_key key;
	enum sja1105_rule_type type;

	/* Action */
	union {
		/* SJA1105_RULE_BCAST_POLICER */
		struct {
@@ -117,14 +153,28 @@ struct sja1105_rule {
		/* SJA1105_RULE_TC_POLICER */
		struct {
			int sharindx;
			int tc;
		} tc_pol;

		/* SJA1105_RULE_VL */
		struct {
			enum sja1105_vl_type type;
			unsigned long destports;
			int sharindx;
			int maxlen;
			int ipv;
			u64 base_time;
			u64 cycle_time;
			int num_entries;
			struct action_gate_entry *entries;
			struct flow_stats stats;
		} vl;
	};
};

struct sja1105_flow_block {
	struct list_head rules;
	bool l2_policer_used[SJA1105_NUM_L2_POLICERS];
	int num_virtual_links;
};

struct sja1105_private {
@@ -161,6 +211,7 @@ enum sja1105_reset_reason {
	SJA1105_AGEING_TIME,
	SJA1105_SCHEDULING,
	SJA1105_BEST_EFFORT_POLICING,
	SJA1105_VIRTUAL_LINKS,
};

int sja1105_static_config_reload(struct sja1105_private *priv,
@@ -254,13 +305,19 @@ size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
					    enum packing_op op);
size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
					    enum packing_op op);
size_t sja1105_vl_lookup_entry_packing(void *buf, void *entry_ptr,
				       enum packing_op op);

/* From sja1105_flower.c */
int sja1105_cls_flower_del(struct dsa_switch *ds, int port,
			   struct flow_cls_offload *cls, bool ingress);
int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
			   struct flow_cls_offload *cls, bool ingress);
int sja1105_cls_flower_stats(struct dsa_switch *ds, int port,
			     struct flow_cls_offload *cls, bool ingress);
void sja1105_flower_setup(struct dsa_switch *ds);
void sja1105_flower_teardown(struct dsa_switch *ds);
struct sja1105_rule *sja1105_rule_find(struct sja1105_private *priv,
				       unsigned long cookie);

#endif
+51 −0
Original line number Diff line number Diff line
@@ -97,6 +97,12 @@

#define SJA1105_SIZE_DYN_CMD					4

#define SJA1105ET_SJA1105_SIZE_VL_LOOKUP_DYN_CMD		\
	SJA1105_SIZE_DYN_CMD

#define SJA1105PQRS_SJA1105_SIZE_VL_LOOKUP_DYN_CMD		\
	(SJA1105_SIZE_DYN_CMD + SJA1105_SIZE_VL_LOOKUP_ENTRY)

#define SJA1105ET_SIZE_MAC_CONFIG_DYN_ENTRY			\
	SJA1105_SIZE_DYN_CMD

@@ -146,6 +152,29 @@ enum sja1105_hostcmd {
	SJA1105_HOSTCMD_INVALIDATE = 4,
};

static void
sja1105_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
			      enum packing_op op)
{
	const int size = SJA1105_SIZE_DYN_CMD;

	sja1105_packing(buf, &cmd->valid,   31, 31, size, op);
	sja1105_packing(buf, &cmd->errors,  30, 30, size, op);
	sja1105_packing(buf, &cmd->rdwrset, 29, 29, size, op);
	sja1105_packing(buf, &cmd->index,    9,  0, size, op);
}

static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
						enum packing_op op)
{
	struct sja1105_vl_lookup_entry *entry = entry_ptr;
	const int size = SJA1105ET_SJA1105_SIZE_VL_LOOKUP_DYN_CMD;

	sja1105_packing(buf, &entry->egrmirr,  21, 17, size, op);
	sja1105_packing(buf, &entry->ingrmirr, 16, 16, size, op);
	return size;
}

static void
sja1105pqrs_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
				  enum packing_op op)
@@ -505,6 +534,16 @@ sja1105pqrs_avb_params_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_SCHEDULE] = {0},
	[BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0},
	[BLK_IDX_VL_LOOKUP] = {
		.entry_packing = sja1105et_vl_lookup_entry_packing,
		.cmd_packing = sja1105_vl_lookup_cmd_packing,
		.access = OP_WRITE,
		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
		.packed_size = SJA1105ET_SJA1105_SIZE_VL_LOOKUP_DYN_CMD,
		.addr = 0x35,
	},
	[BLK_IDX_VL_POLICING] = {0},
	[BLK_IDX_VL_FORWARDING] = {0},
	[BLK_IDX_L2_LOOKUP] = {
		.entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
		.cmd_packing = sja1105et_l2_lookup_cmd_packing,
@@ -548,6 +587,7 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
	},
	[BLK_IDX_SCHEDULE_PARAMS] = {0},
	[BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0},
	[BLK_IDX_VL_FORWARDING_PARAMS] = {0},
	[BLK_IDX_L2_LOOKUP_PARAMS] = {
		.entry_packing = sja1105et_l2_lookup_params_entry_packing,
		.cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
@@ -573,6 +613,16 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	[BLK_IDX_SCHEDULE] = {0},
	[BLK_IDX_SCHEDULE_ENTRY_POINTS] = {0},
	[BLK_IDX_VL_LOOKUP] = {
		.entry_packing = sja1105_vl_lookup_entry_packing,
		.cmd_packing = sja1105_vl_lookup_cmd_packing,
		.access = (OP_READ | OP_WRITE),
		.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
		.packed_size = SJA1105PQRS_SJA1105_SIZE_VL_LOOKUP_DYN_CMD,
		.addr = 0x47,
	},
	[BLK_IDX_VL_POLICING] = {0},
	[BLK_IDX_VL_FORWARDING] = {0},
	[BLK_IDX_L2_LOOKUP] = {
		.entry_packing = sja1105pqrs_dyn_l2_lookup_entry_packing,
		.cmd_packing = sja1105pqrs_l2_lookup_cmd_packing,
@@ -616,6 +666,7 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
	},
	[BLK_IDX_SCHEDULE_PARAMS] = {0},
	[BLK_IDX_SCHEDULE_ENTRY_POINTS_PARAMS] = {0},
	[BLK_IDX_VL_FORWARDING_PARAMS] = {0},
	[BLK_IDX_L2_LOOKUP_PARAMS] = {
		.entry_packing = sja1105et_l2_lookup_params_entry_packing,
		.cmd_packing = sja1105et_l2_lookup_params_cmd_packing,
Loading