Update driver to be ready for the upcoming firmware release. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
1026 lines
40 KiB
Diff
1026 lines
40 KiB
Diff
From 50a84327282120a51af12da91214ed9e06f585cb Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Tue, 24 Mar 2026 18:51:13 +0000
|
|
Subject: [PATCH 06/19] net: dsa: mxl862xx: trap link-local and multicast
|
|
snooping frames to CPU
|
|
|
|
Install per-CTP PCE rules on each user port that trap IEEE 802.1D
|
|
link-local frames (01:80:c2:00:00:0x) and IP multicast snooping
|
|
frames (IGMP, MLDv1, MLDv2) to the CPU port.
|
|
|
|
All trap rules share a common action helper,
|
|
mxl862xx_fill_cpu_trap_action(), which sets PORTMAP_ALTERNATIVE to
|
|
redirect frames to the CPU and enables cross-state forwarding so
|
|
that frames reach the host even when the bridge port is in BLOCKING
|
|
or LEARNING state.
|
|
|
|
A dedicated bridge FID (cpu_trap_fid) is allocated during setup with
|
|
all flood modes enabled. Each trap rule points the bridge engine at
|
|
this FID via bFidEnable so that IGMP and MLD frames are never
|
|
silently dropped by the ingress port's private flood policy.
|
|
|
|
Rules are written through the firmware's logical-index API,
|
|
GSW_TFLOW_PCERULELOGICWRITE. The firmware translates the logical
|
|
index in @rule->pattern.index into a physical position within the
|
|
per-CTP block selected by @rule->region and @rule->logicalportid,
|
|
and grows the hardware block size on demand as rules are inserted.
|
|
A single dispatch helper, mxl862xx_pce_rule_write(), centralises the
|
|
firmware command so the trap callers do not need to know which API
|
|
variant is used. Four logical indices are consumed in each port's
|
|
per-CTP block (index 0 is reserved by the firmware for its
|
|
flow-control marking rule):
|
|
|
|
index 1 -- IEEE 802.1D link-local (dst 01:80:c2:00:00:0x)
|
|
index 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
|
index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
|
index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
|
|
|
Add the PCE rule firmware API structures, command definitions, and
|
|
the rule block allocation interface.
|
|
|
|
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|
---
|
|
drivers/net/dsa/mxl862xx/mxl862xx-api.h | 684 ++++++++++++++++++++++++
|
|
drivers/net/dsa/mxl862xx/mxl862xx-cmd.h | 6 +
|
|
drivers/net/dsa/mxl862xx/mxl862xx.c | 198 +++++++
|
|
drivers/net/dsa/mxl862xx/mxl862xx.h | 8 +
|
|
4 files changed, 896 insertions(+)
|
|
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-api.h
|
|
@@ -1184,6 +1184,690 @@ struct mxl862xx_ctp_port_assignment {
|
|
__le16 bridge_port_id;
|
|
} __packed;
|
|
|
|
+/* PCE (Packet Classification Engine) rule structures.
|
|
+ *
|
|
+ * Binary layout must exactly match the firmware's GSW_PCE_rule_t
|
|
+ * (gsw_flow.h, packed little-endian). The firmware deserializes
|
|
+ * the structure directly from the MDIO data buffer produced by
|
|
+ * mxl862xx_api_wrap().
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * union mxl862xx_ip - IPv4 or IPv6 address
|
|
+ * @ipv4: IPv4 address in little-endian
|
|
+ * @ipv6: IPv6 address as array of little-endian 16-bit words
|
|
+ */
|
|
+union mxl862xx_ip {
|
|
+ __le32 ipv4;
|
|
+ __le16 ipv6[8];
|
|
+} __packed;
|
|
+
|
|
+/**
|
|
+ * struct mxl862xx_pce_pattern - PCE rule match pattern
|
|
+ *
|
|
+ * Every field must remain in the order shown; the firmware
|
|
+ * interprets the buffer positionally.
|
|
+ *
|
|
+ * @index: PCE rule index (0..511)
|
|
+ * @dst_ip_mask: Destination IP nibble mask (outer)
|
|
+ * @inner_dst_ip_mask: Inner destination IP nibble mask
|
|
+ * @src_ip_mask: Source IP nibble mask (outer)
|
|
+ * @inner_src_ip_mask: Inner source IP nibble mask
|
|
+ * @sub_if_id: Incoming sub-interface ID value
|
|
+ * @pkt_lng: Packet length in bytes
|
|
+ * @pkt_lng_range: Packet length range upper bound
|
|
+ * @mac_dst_mask: Destination MAC nibble mask
|
|
+ * @mac_src_mask: Source MAC nibble mask
|
|
+ * @app_data_msb: MSB application field (first 2 bytes after IP header,
|
|
+ * typically TCP/UDP source port)
|
|
+ * @app_mask_range_msb: MSB application mask or range value
|
|
+ * @ether_type: EtherType value to match
|
|
+ * @ether_type_mask: EtherType nibble mask
|
|
+ * @session_id: PPPoE session ID
|
|
+ * @ppp_protocol: PPP protocol value
|
|
+ * @ppp_protocol_mask: PPP protocol bit mask
|
|
+ * @vid: CTAG VLAN ID (inner VLAN)
|
|
+ * @slan_vid: STAG VLAN ID (outer VLAN)
|
|
+ * @flex_field4_value: Flexible field 4 match value
|
|
+ * @flex_field4_mask_range: Flexible field 4 mask or range
|
|
+ * @flex_field3_value: Flexible field 3 match value
|
|
+ * @flex_field3_mask_range: Flexible field 3 mask or range
|
|
+ * @flex_field1_value: Flexible field 1 match value
|
|
+ * @flex_field1_mask_range: Flexible field 1 mask or range
|
|
+ * @outer_vid_range: Outer VLAN ID range
|
|
+ * @payload1: Payload-1 value (16-bit)
|
|
+ * @payload1_mask: Payload-1 bit mask
|
|
+ * @payload2: Payload-2 value (16-bit)
|
|
+ * @payload2_mask: Payload-2 bit mask
|
|
+ * @parser_flag_lsb: Parser flag LSW value (bits 15:0)
|
|
+ * @parser_flag_lsb_mask: Parser flag LSW mask (1 = masked out)
|
|
+ * @parser_flag_msb: Parser flag MSW value (bits 31:16)
|
|
+ * @parser_flag_msb_mask: Parser flag MSW mask (1 = masked out)
|
|
+ * @parser_flag1_lsb: Parser flag1 LSW value (bits 47:32)
|
|
+ * @parser_flag1_lsb_mask: Parser flag1 LSW mask
|
|
+ * @parser_flag1_msb: Parser flag1 MSW value (bits 63:48)
|
|
+ * @parser_flag1_msb_mask: Parser flag1 MSW mask
|
|
+ * @app_data_lsb: LSB application field (next 2 bytes after @app_data_msb,
|
|
+ * typically TCP/UDP destination port)
|
|
+ * @app_mask_range_lsb: LSB application mask or range value
|
|
+ * @insertion_flag: CPU-inserted packet flag
|
|
+ * @vid_range: CTAG VLAN ID range (used as mask when @vid_range_select is 0)
|
|
+ * @flex_field2_mask_range: Flexible field 2 mask or range
|
|
+ * @flex_field2_value: Flexible field 2 match value
|
|
+ * @port_id: Ingress port ID for classification
|
|
+ * @dscp: Outer DSCP value
|
|
+ * @inner_dscp: Inner DSCP value
|
|
+ * @pcp: CTAG VLAN PCP (bits 2:0) and DEI (bit 3)
|
|
+ * @stag_pcp_dei: STAG VLAN PCP (bits 2:0) and DEI (bit 3)
|
|
+ * @mac_dst: Destination MAC address
|
|
+ * @mac_src: Source MAC address
|
|
+ * @protocol: Outer IP protocol value
|
|
+ * @protocol_mask: Outer IP protocol nibble mask
|
|
+ * @inner_protocol: Inner IP protocol value
|
|
+ * @inner_protocol_mask: Inner IP protocol bit mask
|
|
+ * @flex_field4_parser_index: Flexible field 4 parser output index (0..127)
|
|
+ * @flex_field3_parser_index: Flexible field 3 parser output index (0..127)
|
|
+ * @flex_field1_parser_index: Flexible field 1 parser output index (0..127)
|
|
+ * @flex_field2_parser_index: Flexible field 2 parser output index (0..127)
|
|
+ * @enable: Rule is enabled (used) or disabled (unused)
|
|
+ * @port_id_enable: Enable ingress port ID matching
|
|
+ * @port_id_exclude: Exclude (negate) port ID match
|
|
+ * @sub_if_id_type: Sub-interface ID field mode selector
|
|
+ * @sub_if_id_enable: Enable sub-interface ID matching
|
|
+ * @sub_if_id_exclude: Exclude sub-interface ID match
|
|
+ * @dscp_enable: Enable outer DSCP matching
|
|
+ * @dscp_exclude: Exclude outer DSCP match
|
|
+ * @inner_dscp_enable: Enable inner DSCP matching
|
|
+ * @inner_dscp_exclude: Exclude inner DSCP match
|
|
+ * @pcp_enable: Enable CTAG PCP/DEI matching
|
|
+ * @ctag_pcp_dei_exclude: Exclude CTAG PCP/DEI match
|
|
+ * @stag_pcp_dei_enable: Enable STAG PCP/DEI matching
|
|
+ * @stag_pcp_dei_exclude: Exclude STAG PCP/DEI match
|
|
+ * @pkt_lng_enable: Enable packet length matching
|
|
+ * @pkt_lng_exclude: Exclude packet length match
|
|
+ * @mac_dst_enable: Enable destination MAC matching
|
|
+ * @dst_mac_exclude: Exclude destination MAC match
|
|
+ * @mac_src_enable: Enable source MAC matching
|
|
+ * @src_mac_exclude: Exclude source MAC match
|
|
+ * @app_data_msb_enable: Enable MSB application field matching
|
|
+ * @app_mask_range_msb_select: MSB application mask/range selection
|
|
+ * (0 = nibble mask, 1 = range)
|
|
+ * @app_msb_exclude: Exclude MSB application match
|
|
+ * @app_data_lsb_enable: Enable LSB application field matching
|
|
+ * @app_mask_range_lsb_select: LSB application mask/range selection
|
|
+ * (0 = nibble mask, 1 = range)
|
|
+ * @app_lsb_exclude: Exclude LSB application match
|
|
+ * @dst_ip_select: Outer destination IP selection
|
|
+ * (0 = disabled, 1 = IPv4, 2 = IPv6)
|
|
+ * @dst_ip: Outer destination IP address
|
|
+ * @dst_ip_exclude: Exclude outer destination IP match
|
|
+ * @inner_dst_ip_select: Inner destination IP selection
|
|
+ * @inner_dst_ip: Inner destination IP address
|
|
+ * @inner_dst_ip_exclude: Exclude inner destination IP match
|
|
+ * @src_ip_select: Outer source IP selection
|
|
+ * (0 = disabled, 1 = IPv4, 2 = IPv6)
|
|
+ * @src_ip: Outer source IP address
|
|
+ * @src_ip_exclude: Exclude outer source IP match
|
|
+ * @inner_src_ip_select: Inner source IP selection
|
|
+ * @inner_src_ip: Inner source IP address
|
|
+ * @inner_src_ip_exclude: Exclude inner source IP match
|
|
+ * @ether_type_enable: Enable EtherType matching
|
|
+ * @ether_type_exclude: Exclude EtherType match
|
|
+ * @protocol_enable: Enable outer IP protocol matching
|
|
+ * @protocol_exclude: Exclude outer IP protocol match
|
|
+ * @inner_protocol_enable: Enable inner IP protocol matching
|
|
+ * @inner_protocol_exclude: Exclude inner IP protocol match
|
|
+ * @session_id_enable: Enable PPPoE session ID matching
|
|
+ * @session_id_exclude: Exclude PPPoE session ID match
|
|
+ * @ppp_protocol_enable: Enable PPP protocol matching
|
|
+ * @ppp_protocol_exclude: Exclude PPP protocol match
|
|
+ * @vid_used: Enable CTAG VLAN ID matching
|
|
+ * @vid_range_select: CVLAN mask/range selection (0 = mask, 1 = range)
|
|
+ * @vid_exclude: Exclude CTAG VLAN ID match
|
|
+ * @vid_original: Use original VLAN ID as key even if modified earlier
|
|
+ * @slan_vid_used: Enable STAG VLAN ID matching
|
|
+ * @slan_vid_exclude: Exclude STAG VLAN ID match
|
|
+ * @svid_range_select: SVLAN mask/range selection (0 = mask, 1 = range)
|
|
+ * @outer_vid_original: Use original outer VLAN ID as key even if modified
|
|
+ * @payload1_src_enable: Enable payload-1 matching
|
|
+ * @payload1_mask_range_select: Payload-1 mask/range selection
|
|
+ * (0 = bit mask, 1 = range)
|
|
+ * @payload1_exclude: Exclude payload-1 match
|
|
+ * @payload2_src_enable: Enable payload-2 matching
|
|
+ * @payload2_mask_range_select: Payload-2 mask/range selection
|
|
+ * (0 = bit mask, 1 = range)
|
|
+ * @payload2_exclude: Exclude payload-2 match
|
|
+ * @parser_flag_lsb_enable: Enable parser flag LSW matching
|
|
+ * @parser_flag_lsb_exclude: Exclude parser flag LSW match
|
|
+ * @parser_flag_msb_enable: Enable parser flag MSW matching
|
|
+ * @parser_flag_msb_exclude: Exclude parser flag MSW match
|
|
+ * @parser_flag1_lsb_enable: Enable parser flag1 LSW matching
|
|
+ * @parser_flag1_lsb_exclude: Exclude parser flag1 LSW match
|
|
+ * @parser_flag1_msb_enable: Enable parser flag1 MSW matching
|
|
+ * @parser_flag1_msb_exclude: Exclude parser flag1 MSW match
|
|
+ * @insertion_flag_enable: Enable insertion flag matching
|
|
+ * @flex_field4_enable: Enable flexible field 4 matching
|
|
+ * @flex_field4_exclude_enable: Exclude flexible field 4 match
|
|
+ * @flex_field4_range_enable: Flexible field 4 range mode
|
|
+ * (0 = mask, 1 = range)
|
|
+ * @flex_field3_enable: Enable flexible field 3 matching
|
|
+ * @flex_field3_exclude_enable: Exclude flexible field 3 match
|
|
+ * @flex_field3_range_enable: Flexible field 3 range mode
|
|
+ * @flex_field2_enable: Enable flexible field 2 matching
|
|
+ * @flex_field2_exclude_enable: Exclude flexible field 2 match
|
|
+ * @flex_field2_range_enable: Flexible field 2 range mode
|
|
+ * @flex_field1_enable: Enable flexible field 1 matching
|
|
+ * @flex_field1_exclude_enable: Exclude flexible field 1 match
|
|
+ * @flex_field1_range_enable: Flexible field 1 range mode
|
|
+ */
|
|
+struct mxl862xx_pce_pattern {
|
|
+ __le16 index;
|
|
+ __le32 dst_ip_mask;
|
|
+ __le32 inner_dst_ip_mask;
|
|
+ __le32 src_ip_mask;
|
|
+ __le32 inner_src_ip_mask;
|
|
+ __le16 sub_if_id;
|
|
+ __le16 pkt_lng;
|
|
+ __le16 pkt_lng_range;
|
|
+ __le16 mac_dst_mask;
|
|
+ __le16 mac_src_mask;
|
|
+ __le16 app_data_msb;
|
|
+ __le16 app_mask_range_msb;
|
|
+ __le16 ether_type;
|
|
+ __le16 ether_type_mask;
|
|
+ __le16 session_id;
|
|
+ __le16 ppp_protocol;
|
|
+ __le16 ppp_protocol_mask;
|
|
+ __le16 vid;
|
|
+ __le16 slan_vid;
|
|
+ __le16 flex_field4_value;
|
|
+ __le16 flex_field4_mask_range;
|
|
+ __le16 flex_field3_value;
|
|
+ __le16 flex_field3_mask_range;
|
|
+ __le16 flex_field1_value;
|
|
+ __le16 flex_field1_mask_range;
|
|
+ __le16 outer_vid_range;
|
|
+ __le16 payload1;
|
|
+ __le16 payload1_mask;
|
|
+ __le16 payload2;
|
|
+ __le16 payload2_mask;
|
|
+ __le16 parser_flag_lsb;
|
|
+ __le16 parser_flag_lsb_mask;
|
|
+ __le16 parser_flag_msb;
|
|
+ __le16 parser_flag_msb_mask;
|
|
+ __le16 parser_flag1_lsb;
|
|
+ __le16 parser_flag1_lsb_mask;
|
|
+ __le16 parser_flag1_msb;
|
|
+ __le16 parser_flag1_msb_mask;
|
|
+ __le16 app_data_lsb;
|
|
+ __le16 app_mask_range_lsb;
|
|
+ __le16 insertion_flag;
|
|
+ __le16 vid_range;
|
|
+ __le16 flex_field2_mask_range;
|
|
+ __le16 flex_field2_value;
|
|
+ u8 port_id;
|
|
+ u8 dscp;
|
|
+ u8 inner_dscp;
|
|
+ u8 pcp;
|
|
+ u8 stag_pcp_dei;
|
|
+ u8 mac_dst[ETH_ALEN];
|
|
+ u8 mac_src[ETH_ALEN];
|
|
+ u8 protocol;
|
|
+ u8 protocol_mask;
|
|
+ u8 inner_protocol;
|
|
+ u8 inner_protocol_mask;
|
|
+ u8 flex_field4_parser_index;
|
|
+ u8 flex_field3_parser_index;
|
|
+ u8 flex_field1_parser_index;
|
|
+ u8 flex_field2_parser_index;
|
|
+ u8 enable;
|
|
+ u8 port_id_enable;
|
|
+ u8 port_id_exclude;
|
|
+ __le32 sub_if_id_type;
|
|
+ u8 sub_if_id_enable;
|
|
+ u8 sub_if_id_exclude;
|
|
+ u8 dscp_enable;
|
|
+ u8 dscp_exclude;
|
|
+ u8 inner_dscp_enable;
|
|
+ u8 inner_dscp_exclude;
|
|
+ u8 pcp_enable;
|
|
+ u8 ctag_pcp_dei_exclude;
|
|
+ u8 stag_pcp_dei_enable;
|
|
+ u8 stag_pcp_dei_exclude;
|
|
+ u8 pkt_lng_enable;
|
|
+ u8 pkt_lng_exclude;
|
|
+ u8 mac_dst_enable;
|
|
+ u8 dst_mac_exclude;
|
|
+ u8 mac_src_enable;
|
|
+ u8 src_mac_exclude;
|
|
+ u8 app_data_msb_enable;
|
|
+ u8 app_mask_range_msb_select;
|
|
+ u8 app_msb_exclude;
|
|
+ u8 app_data_lsb_enable;
|
|
+ u8 app_mask_range_lsb_select;
|
|
+ u8 app_lsb_exclude;
|
|
+ __le32 dst_ip_select;
|
|
+ union mxl862xx_ip dst_ip;
|
|
+ u8 dst_ip_exclude;
|
|
+ __le32 inner_dst_ip_select;
|
|
+ union mxl862xx_ip inner_dst_ip;
|
|
+ u8 inner_dst_ip_exclude;
|
|
+ __le32 src_ip_select;
|
|
+ union mxl862xx_ip src_ip;
|
|
+ u8 src_ip_exclude;
|
|
+ __le32 inner_src_ip_select;
|
|
+ union mxl862xx_ip inner_src_ip;
|
|
+ u8 inner_src_ip_exclude;
|
|
+ u8 ether_type_enable;
|
|
+ u8 ether_type_exclude;
|
|
+ u8 protocol_enable;
|
|
+ u8 protocol_exclude;
|
|
+ u8 inner_protocol_enable;
|
|
+ u8 inner_protocol_exclude;
|
|
+ u8 session_id_enable;
|
|
+ u8 session_id_exclude;
|
|
+ u8 ppp_protocol_enable;
|
|
+ u8 ppp_protocol_exclude;
|
|
+ u8 vid_used;
|
|
+ u8 vid_range_select;
|
|
+ u8 vid_exclude;
|
|
+ u8 vid_original;
|
|
+ u8 slan_vid_used;
|
|
+ u8 slan_vid_exclude;
|
|
+ u8 svid_range_select;
|
|
+ u8 outer_vid_original;
|
|
+ u8 payload1_src_enable;
|
|
+ u8 payload1_mask_range_select;
|
|
+ u8 payload1_exclude;
|
|
+ u8 payload2_src_enable;
|
|
+ u8 payload2_mask_range_select;
|
|
+ u8 payload2_exclude;
|
|
+ u8 parser_flag_lsb_enable;
|
|
+ u8 parser_flag_lsb_exclude;
|
|
+ u8 parser_flag_msb_enable;
|
|
+ u8 parser_flag_msb_exclude;
|
|
+ u8 parser_flag1_lsb_enable;
|
|
+ u8 parser_flag1_lsb_exclude;
|
|
+ u8 parser_flag1_msb_enable;
|
|
+ u8 parser_flag1_msb_exclude;
|
|
+ u8 insertion_flag_enable;
|
|
+ u8 flex_field4_enable;
|
|
+ u8 flex_field4_exclude_enable;
|
|
+ u8 flex_field4_range_enable;
|
|
+ u8 flex_field3_enable;
|
|
+ u8 flex_field3_exclude_enable;
|
|
+ u8 flex_field3_range_enable;
|
|
+ u8 flex_field2_enable;
|
|
+ u8 flex_field2_exclude_enable;
|
|
+ u8 flex_field2_range_enable;
|
|
+ u8 flex_field1_enable;
|
|
+ u8 flex_field1_exclude_enable;
|
|
+ u8 flex_field1_range_enable;
|
|
+} __packed;
|
|
+
|
|
+static_assert(sizeof(struct mxl862xx_pce_pattern) == 279);
|
|
+
|
|
+/**
|
|
+ * struct mxl862xx_pce_action_pbb - Provider Backbone Bridging (Mac-in-Mac)
|
|
+ * action configuration
|
|
+ *
|
|
+ * @tunnel_id_known_traffic: Tunnel template index for I-Header known traffic
|
|
+ * @tunnel_id_unknown_traffic: Tunnel template index for I-Header unknown
|
|
+ * traffic
|
|
+ * @process_id_known_traffic: Tunnel template index for B-TAG known traffic
|
|
+ * @process_id_unknown_traffic: Tunnel template index for B-TAG unknown
|
|
+ * traffic
|
|
+ * @iheader_op_mode: I-Header operation mode (0 = no change, 1 = insert,
|
|
+ * 2 = remove, 3 = replace)
|
|
+ * @btag_op_mode: B-TAG operation mode (0 = no change, 1 = insert,
|
|
+ * 2 = remove, 3 = replace)
|
|
+ * @mac_table_macinmac_select: MAC table Mac-in-Mac selection
|
|
+ * (0 = outer MAC, 1 = inner MAC)
|
|
+ * @iheader_action_enable: Enable Mac-in-Mac I-Header action
|
|
+ * @tunnel_id_known_traffic_enable: Enable tunnel ID for known traffic
|
|
+ * @tunnel_id_unknown_traffic_enable: Enable tunnel ID for unknown traffic
|
|
+ * @b_dst_mac_from_mac_table_enable: Use B-DA from MAC table instead of
|
|
+ * tunnel template (I-Header insertion
|
|
+ * mode only)
|
|
+ * @replace_b_src_mac_enable: Replace B-SA from tunnel template
|
|
+ * @replace_b_dst_mac_enable: Replace B-DA from tunnel template
|
|
+ * @replace_i_tag_res_enable: Replace I-Tag Res from tunnel template
|
|
+ * @replace_i_tag_uac_enable: Replace I-Tag UAC from tunnel template
|
|
+ * @replace_i_tag_dei_enable: Replace I-Tag DEI from tunnel template
|
|
+ * @replace_i_tag_pcp_enable: Replace I-Tag PCP from tunnel template
|
|
+ * @replace_i_tag_sid_enable: Replace I-Tag SID from tunnel template
|
|
+ * @replace_i_tag_tpid_enable: Replace I-Tag TPID from tunnel template
|
|
+ * @btag_action_enable: Enable B-TAG action
|
|
+ * @process_id_known_traffic_enable: Enable process ID for B-TAG known
|
|
+ * traffic
|
|
+ * @process_id_unknown_traffic_enable: Enable process ID for B-TAG unknown
|
|
+ * traffic
|
|
+ * @replace_b_tag_dei_enable: Replace B-Tag DEI from tunnel template
|
|
+ * @replace_b_tag_pcp_enable: Replace B-Tag PCP from tunnel template
|
|
+ * @replace_b_tag_vid_enable: Replace B-Tag VID from tunnel template
|
|
+ * @replace_b_tag_tpid_enable: Replace B-Tag TPID from tunnel template
|
|
+ * @mac_table_macinmac_action_enable: Enable MAC table Mac-in-Mac action
|
|
+ */
|
|
+struct mxl862xx_pce_action_pbb {
|
|
+ u8 tunnel_id_known_traffic;
|
|
+ u8 tunnel_id_unknown_traffic;
|
|
+ u8 process_id_known_traffic;
|
|
+ u8 process_id_unknown_traffic;
|
|
+ __le32 iheader_op_mode;
|
|
+ __le32 btag_op_mode;
|
|
+ __le32 mac_table_macinmac_select;
|
|
+ u8 iheader_action_enable;
|
|
+ u8 tunnel_id_known_traffic_enable;
|
|
+ u8 tunnel_id_unknown_traffic_enable;
|
|
+ u8 b_dst_mac_from_mac_table_enable;
|
|
+ u8 replace_b_src_mac_enable;
|
|
+ u8 replace_b_dst_mac_enable;
|
|
+ u8 replace_i_tag_res_enable;
|
|
+ u8 replace_i_tag_uac_enable;
|
|
+ u8 replace_i_tag_dei_enable;
|
|
+ u8 replace_i_tag_pcp_enable;
|
|
+ u8 replace_i_tag_sid_enable;
|
|
+ u8 replace_i_tag_tpid_enable;
|
|
+ u8 btag_action_enable;
|
|
+ u8 process_id_known_traffic_enable;
|
|
+ u8 process_id_unknown_traffic_enable;
|
|
+ u8 replace_b_tag_dei_enable;
|
|
+ u8 replace_b_tag_pcp_enable;
|
|
+ u8 replace_b_tag_vid_enable;
|
|
+ u8 replace_b_tag_tpid_enable;
|
|
+ u8 mac_table_macinmac_action_enable;
|
|
+} __packed;
|
|
+
|
|
+static_assert(sizeof(struct mxl862xx_pce_action_pbb) == 36);
|
|
+
|
|
+/**
|
|
+ * struct mxl862xx_pce_action_dest_subif - Destination sub-interface ID
|
|
+ * action configuration
|
|
+ *
|
|
+ * @dest_subifid_action_enable: Destination sub-interface ID group field
|
|
+ * action enable
|
|
+ * @dest_subifid_assignment_enable: Destination sub-interface ID group field
|
|
+ * assignment enable
|
|
+ * @dest_subifgrp_field: Destination sub-interface ID group field value,
|
|
+ * or LAG index when trunking action is enabled
|
|
+ */
|
|
+struct mxl862xx_pce_action_dest_subif {
|
|
+ u8 dest_subifid_action_enable;
|
|
+ u8 dest_subifid_assignment_enable;
|
|
+ __le16 dest_subifgrp_field;
|
|
+} __packed;
|
|
+
|
|
+static_assert(sizeof(struct mxl862xx_pce_action_dest_subif) == 4);
|
|
+
|
|
+/**
|
|
+ * enum mxl862xx_pce_action_portmap - Forwarding group action selector
|
|
+ *
|
|
+ * Selects how the packet is forwarded. Mutually exclusive with
|
|
+ * the flow_id_action (bFlowID_Action in vendor API).
|
|
+ *
|
|
+ * @MXL862XX_PCE_ACTION_PORTMAP_DISABLE: Forwarding action is disabled
|
|
+ * @MXL862XX_PCE_ACTION_PORTMAP_REGULAR: Use default port-map from
|
|
+ * forwarding classification
|
|
+ * @MXL862XX_PCE_ACTION_PORTMAP_DISCARD: Discard the packet
|
|
+ * @MXL862XX_PCE_ACTION_PORTMAP_CPU: Forward to the CPU port
|
|
+ * (as configured by GSW_CPU_PortCfgSet, typically the on-die
|
|
+ * microcontroller -- not the DSA CPU port)
|
|
+ * @MXL862XX_PCE_ACTION_PORTMAP_ALTERNATIVE: Forward to an explicit
|
|
+ * portmap given by forward_port_map[]
|
|
+ */
|
|
+enum mxl862xx_pce_action_portmap {
|
|
+ MXL862XX_PCE_ACTION_PORTMAP_DISABLE = 0,
|
|
+ MXL862XX_PCE_ACTION_PORTMAP_REGULAR = 1,
|
|
+ MXL862XX_PCE_ACTION_PORTMAP_DISCARD = 2,
|
|
+ MXL862XX_PCE_ACTION_PORTMAP_CPU = 3,
|
|
+ MXL862XX_PCE_ACTION_PORTMAP_ALTERNATIVE = 4,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * enum mxl862xx_pce_action_cross_state - Cross state action selector
|
|
+ *
|
|
+ * Controls whether the packet ignores STP port-state filtering.
|
|
+ *
|
|
+ * @MXL862XX_PCE_ACTION_CROSS_STATE_DISABLE: Cross state action is disabled
|
|
+ * @MXL862XX_PCE_ACTION_CROSS_STATE_REGULAR: Enabled; packet is treated
|
|
+ * as non-cross-state (does not ignore port-state filtering)
|
|
+ * @MXL862XX_PCE_ACTION_CROSS_STATE_CROSS: Enabled; packet ignores
|
|
+ * port-state filtering rules (e.g. passes through BLOCKING state)
|
|
+ */
|
|
+enum mxl862xx_pce_action_cross_state {
|
|
+ MXL862XX_PCE_ACTION_CROSS_STATE_DISABLE = 0,
|
|
+ MXL862XX_PCE_ACTION_CROSS_STATE_REGULAR = 1,
|
|
+ MXL862XX_PCE_ACTION_CROSS_STATE_CROSS = 2,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct mxl862xx_pce_action - PCE rule action configuration
|
|
+ *
|
|
+ * Defines the actions applied to packets matching a PCE rule pattern.
|
|
+ *
|
|
+ * @time_comp: Signed time compensation value for OAM delay measurement
|
|
+ * @extended_vlan_block_id: Extended VLAN block allocated for this flow
|
|
+ * entry (valid when @extended_vlan_enable is set)
|
|
+ * @ins_ext_point: Insertion/extraction point
|
|
+ * @ptp_seq_id: PTP sequence ID for PTP application
|
|
+ * @pkt_update_offset: Byte offset (2..255) for counter/timestamp
|
|
+ * insertion (used when @no_pkt_update and
|
|
+ * @append_to_pkt are both false)
|
|
+ * @oam_flow_id: Traffic flow counter ID for OAM loss measurement
|
|
+ * @record_id: Record ID used by extraction and/or OAM process
|
|
+ * @forward_port_map: Target portmap for forwarded packets. Each bit
|
|
+ * represents one bridge port. Used when
|
|
+ * @port_map_action is %MXL862XX_PCE_ACTION_PORTMAP_ALTERNATIVE.
|
|
+ * @rmon_id: RMON counter ID (index starts from zero)
|
|
+ * @svlan_id: Alternative STAG VLAN ID
|
|
+ * @flow_id: Flow ID
|
|
+ * @rout_ext_id: Routing extension ID value (8-bit range)
|
|
+ * @traffic_class_alternate: Alternative traffic class (used when
|
|
+ * @traffic_class_action selects alternate)
|
|
+ * @meter_id: Meter ID
|
|
+ * @vlan_id: Alternative CTAG VLAN ID
|
|
+ * @fid: Alternative Filtering Identifier (FID)
|
|
+ * @traffic_class_action: Traffic class action selector
|
|
+ * (0 = disable, 1 = regular CoS, 2 = alternative)
|
|
+ * @snooping_type_action: IGMP snooping control selector
|
|
+ * @learning_action: MAC learning action selector
|
|
+ * (0 = disable, 1 = regular, 2 = force no learn,
|
|
+ * 3 = force learn)
|
|
+ * @irq_action: Interrupt action selector
|
|
+ * (0 = disable, 1 = regular, 2 = generate interrupt)
|
|
+ * @cross_state_action: Cross state action selector.
|
|
+ * See &enum mxl862xx_pce_action_cross_state
|
|
+ * @crit_frame_action: Critical frame action selector
|
|
+ * (0 = disable, 1 = regular, 2 = critical)
|
|
+ * @color_frame_action: Color frame action selector (replaces
|
|
+ * @crit_frame_action in GSWIP-3.1)
|
|
+ * @timestamp_action: Timestamp action selector
|
|
+ * (0 = disable, 1 = regular, 2 = store timestamps)
|
|
+ * @port_map_action: Forwarding portmap action selector.
|
|
+ * See &enum mxl862xx_pce_action_portmap
|
|
+ * @meter_action: Meter action selector
|
|
+ * (0 = disable, 1 = regular, 2 = meter 1,
|
|
+ * 3 = meter 1 and 2)
|
|
+ * @vlan_action: CTAG VLAN action selector
|
|
+ * (0 = disable, 1 = regular, 2 = alternative)
|
|
+ * @svlan_action: STAG VLAN action selector
|
|
+ * (0 = disable, 1 = regular, 2 = alternative)
|
|
+ * @vlan_cross_action: Cross-VLAN action selector
|
|
+ * (0 = disable, 1 = regular, 2 = cross-VLAN)
|
|
+ * @process_path_action: MPE processing path assignment
|
|
+ * (0 = unused, 1 = path-1, 2 = path-2, 3 = both)
|
|
+ * @port_filter_type_action: Port filter action type (0..6)
|
|
+ * @pbb_action: Provider Backbone Bridging (Mac-in-Mac) action.
|
|
+ * See &struct mxl862xx_pce_action_pbb
|
|
+ * @dest_subif_action: Destination sub-interface ID action.
|
|
+ * See &struct mxl862xx_pce_action_dest_subif
|
|
+ * @remark_action: Enable remarking action
|
|
+ * @remark_pcp: Enable CTAG VLAN PCP remarking
|
|
+ * @remark_stag_pcp: Enable STAG VLAN PCP remarking
|
|
+ * @remark_stag_dei: Enable STAG VLAN DEI remarking
|
|
+ * @remark_dscp: Enable DSCP remarking
|
|
+ * @remark_class: Enable class remarking
|
|
+ * @rmon_action: Enable RMON counter action
|
|
+ * @fid_enable: Enable alternative FID
|
|
+ * @extended_vlan_enable: Enable extended VLAN operation for matching
|
|
+ * traffic
|
|
+ * @cvlan_ignore_control: CVLAN ignore control
|
|
+ * @port_bitmap_mux_control: Port bitmap mux control
|
|
+ * @port_trunk_action: Enable trunking action
|
|
+ * @port_link_selection: Port link selection control
|
|
+ * @flow_id_action: Enable flow ID action (mutually exclusive with
|
|
+ * @port_map_action)
|
|
+ * @rout_ext_id_action: Enable routing extension ID action
|
|
+ * @rt_dst_port_mask_cmp_action: Routing destination port mask comparison
|
|
+ * @rt_src_port_mask_cmp_action: Routing source port mask comparison
|
|
+ * @rt_dst_ip_mask_cmp_action: Routing destination IP mask comparison
|
|
+ * @rt_src_ip_mask_cmp_action: Routing source IP mask comparison
|
|
+ * @rt_inner_ip_as_key_action: Use inner IP in tunneled header as
|
|
+ * routing key
|
|
+ * @rt_accel_ena_action: Routing acceleration enable
|
|
+ * @rt_ctrl_ena_action: Routing control enable (selects routing
|
|
+ * accelerate action)
|
|
+ * @extract_enable: Enable packet extraction at point defined by
|
|
+ * @record_id
|
|
+ * @oam_enable: Enable OAM processing for matching packets
|
|
+ * @pce_bypass_path: Update packet in PCE bypass path (after QoS queue)
|
|
+ * @tx_flow_cnt: Use TX flow counter (otherwise RX flow counter)
|
|
+ * @time_format: Timestamp format (0 = digital 10B, 1 = binary 10B,
|
|
+ * 2 = digital 8B, 3 = binary 8B)
|
|
+ * @no_pkt_update: Do not update packet
|
|
+ * @append_to_pkt: Append counter/timestamp to end of packet (when
|
|
+ * @no_pkt_update is false)
|
|
+ * @pbb_action_enable: Enable PBB action. See &struct mxl862xx_pce_action_pbb
|
|
+ * @dest_subif_action_enable: Enable destination sub-interface ID action.
|
|
+ * See &struct mxl862xx_pce_action_dest_subif
|
|
+ */
|
|
+struct mxl862xx_pce_action {
|
|
+ __le64 time_comp;
|
|
+ __le16 extended_vlan_block_id;
|
|
+ u8 ins_ext_point;
|
|
+ u8 ptp_seq_id;
|
|
+ __le16 pkt_update_offset;
|
|
+ __le16 oam_flow_id;
|
|
+ __le16 record_id;
|
|
+ __le16 forward_port_map[8];
|
|
+ __le16 rmon_id;
|
|
+ __le16 svlan_id;
|
|
+ __le16 flow_id;
|
|
+ __le16 rout_ext_id;
|
|
+ u8 traffic_class_alternate;
|
|
+ u8 meter_id;
|
|
+ u8 vlan_id;
|
|
+ u8 fid;
|
|
+ __le32 traffic_class_action;
|
|
+ __le32 snooping_type_action;
|
|
+ __le32 learning_action;
|
|
+ __le32 irq_action;
|
|
+ __le32 cross_state_action;
|
|
+ __le32 crit_frame_action;
|
|
+ __le32 color_frame_action;
|
|
+ __le32 timestamp_action;
|
|
+ __le32 port_map_action;
|
|
+ __le32 meter_action;
|
|
+ __le32 vlan_action;
|
|
+ __le32 svlan_action;
|
|
+ __le32 vlan_cross_action;
|
|
+ __le32 process_path_action;
|
|
+ __le32 port_filter_type_action;
|
|
+ struct mxl862xx_pce_action_pbb pbb_action;
|
|
+ struct mxl862xx_pce_action_dest_subif dest_subif_action;
|
|
+ u8 remark_action;
|
|
+ u8 remark_pcp;
|
|
+ u8 remark_stag_pcp;
|
|
+ u8 remark_stag_dei;
|
|
+ u8 remark_dscp;
|
|
+ u8 remark_class;
|
|
+ u8 rmon_action;
|
|
+ u8 fid_enable;
|
|
+ u8 extended_vlan_enable;
|
|
+ u8 cvlan_ignore_control;
|
|
+ u8 port_bitmap_mux_control;
|
|
+ u8 port_trunk_action;
|
|
+ u8 port_link_selection;
|
|
+ u8 flow_id_action;
|
|
+ u8 rout_ext_id_action;
|
|
+ u8 rt_dst_port_mask_cmp_action;
|
|
+ u8 rt_src_port_mask_cmp_action;
|
|
+ u8 rt_dst_ip_mask_cmp_action;
|
|
+ u8 rt_src_ip_mask_cmp_action;
|
|
+ u8 rt_inner_ip_as_key_action;
|
|
+ u8 rt_accel_ena_action;
|
|
+ u8 rt_ctrl_ena_action;
|
|
+ u8 extract_enable;
|
|
+ u8 oam_enable;
|
|
+ u8 pce_bypass_path;
|
|
+ u8 tx_flow_cnt;
|
|
+ __le32 time_format;
|
|
+ u8 no_pkt_update;
|
|
+ u8 append_to_pkt;
|
|
+ u8 pbb_action_enable;
|
|
+ u8 dest_subif_action_enable;
|
|
+} __packed;
|
|
+
|
|
+static_assert(sizeof(struct mxl862xx_pce_action) == 180);
|
|
+
|
|
+/**
|
|
+ * enum mxl862xx_pce_rule_region - PCE rule table region selector
|
|
+ *
|
|
+ * Selects which region of the traffic flow table the rule belongs to.
|
|
+ *
|
|
+ * @MXL862XX_PCE_RULE_COMMON: Common region shared by all CTPs
|
|
+ * (global rules, indices 0..63)
|
|
+ * @MXL862XX_PCE_RULE_CTP: Per-CTP region. The rule index is relative
|
|
+ * to the CTP block identified by logicalportid; the firmware
|
|
+ * translates it to an absolute hardware index.
|
|
+ * @MXL862XX_PCE_RULE_DEBUG: Debug region with direct HW index mapping
|
|
+ */
|
|
+enum mxl862xx_pce_rule_region {
|
|
+ MXL862XX_PCE_RULE_COMMON = 0,
|
|
+ MXL862XX_PCE_RULE_CTP = 1,
|
|
+ MXL862XX_PCE_RULE_DEBUG = 2,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct mxl862xx_pce_rule - PCE rule configuration
|
|
+ * @logicalportid: Logical Port Id
|
|
+ * @subifidgroup: Sub-interface ID group
|
|
+ * @region: PCE rule region (common or per-CTP)
|
|
+ * @pattern: Match pattern (destination MAC, EtherType, etc.)
|
|
+ * @action: Forwarding action (portmap, cross-state, etc.)
|
|
+ *
|
|
+ * This structure is passed to the firmware via the MDIO data
|
|
+ * buffer using the %MXL862XX_TFLOW_PCERULELOGICWRITE command.
|
|
+ * The binary layout must exactly match the firmware's
|
|
+ * GSW_PCE_rule_t (466 bytes, packed, little-endian scalars).
|
|
+ */
|
|
+struct mxl862xx_pce_rule {
|
|
+ u8 logicalportid;
|
|
+ __le16 subifidgroup;
|
|
+ __le32 region;
|
|
+ struct mxl862xx_pce_pattern pattern;
|
|
+ struct mxl862xx_pce_action action;
|
|
+} __packed;
|
|
+
|
|
+static_assert(sizeof(struct mxl862xx_pce_rule) == 466);
|
|
+
|
|
+/**
|
|
+ * struct mxl862xx_pce_rule_alloc - PCE rule block allocation
|
|
+ * @num_of_rules: Number of rules to allocate (input) / allocated (output).
|
|
+ * The firmware rounds up to a multiple of four consecutive entries.
|
|
+ * @blockid: Starting rule index of the allocated block (output on alloc,
|
|
+ * input on free).
|
|
+ *
|
|
+ * Used with %MXL862XX_TFLOW_PCERULEALLOC and %MXL862XX_TFLOW_PCERULEFREE.
|
|
+ * Maps to the firmware's ``GSW_PCE_rule_alloc_t``.
|
|
+ */
|
|
+struct mxl862xx_pce_rule_alloc {
|
|
+ __le16 num_of_rules;
|
|
+ __le16 blockid;
|
|
+} __packed;
|
|
+
|
|
+static_assert(sizeof(struct mxl862xx_pce_rule_alloc) == 4);
|
|
+
|
|
/**
|
|
* enum mxl862xx_stp_port_state - Spanning Tree Protocol port states
|
|
* @MXL862XX_STP_PORT_STATE_FORWARD: Forwarding state
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx-cmd.h
|
|
@@ -12,6 +12,7 @@
|
|
(MXL862XX_MMD_REG_DATA_LAST - MXL862XX_MMD_REG_DATA_FIRST + 1)
|
|
|
|
#define MXL862XX_COMMON_MAGIC 0x100
|
|
+#define MXL862XX_TFLOW_MAGIC 0x200
|
|
#define MXL862XX_BRDG_MAGIC 0x300
|
|
#define MXL862XX_BRDGPORT_MAGIC 0x400
|
|
#define MXL862XX_CTP_MAGIC 0x500
|
|
@@ -30,6 +31,11 @@
|
|
#define MXL862XX_COMMON_CFGSET (MXL862XX_COMMON_MAGIC + 0xa)
|
|
#define MXL862XX_COMMON_REGISTERMOD (MXL862XX_COMMON_MAGIC + 0x11)
|
|
|
|
+#define MXL862XX_TFLOW_PCERULEALLOC (MXL862XX_TFLOW_MAGIC + 0x4)
|
|
+#define MXL862XX_TFLOW_PCERULEFREE (MXL862XX_TFLOW_MAGIC + 0x5)
|
|
+#define MXL862XX_TFLOW_PCERULELOGICWRITE \
|
|
+ (MXL862XX_TFLOW_MAGIC + 0xa)
|
|
+
|
|
#define MXL862XX_BRIDGE_ALLOC (MXL862XX_BRDG_MAGIC + 0x1)
|
|
#define MXL862XX_BRIDGE_CONFIGSET (MXL862XX_BRDG_MAGIC + 0x2)
|
|
#define MXL862XX_BRIDGE_CONFIGGET (MXL862XX_BRDG_MAGIC + 0x3)
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
|
|
@@ -10,6 +10,7 @@
|
|
#include <linux/bitfield.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/etherdevice.h>
|
|
+#include <linux/icmpv6.h>
|
|
#include <linux/if_bridge.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_device.h>
|
|
@@ -251,9 +252,11 @@ static int mxl862xx_wait_ready(struct ds
|
|
ver.iv_major, ver.iv_minor,
|
|
le16_to_cpu(ver.iv_revision),
|
|
le32_to_cpu(ver.iv_build_num));
|
|
+
|
|
priv->fw_version.major = ver.iv_major;
|
|
priv->fw_version.minor = ver.iv_minor;
|
|
priv->fw_version.revision = le16_to_cpu(ver.iv_revision);
|
|
+
|
|
return 0;
|
|
|
|
not_ready_yet:
|
|
@@ -381,6 +384,170 @@ static int mxl862xx_setup_drop_meter(str
|
|
return MXL862XX_API_WRITE(priv, MXL862XX_COMMON_REGISTERMOD, reg);
|
|
}
|
|
|
|
+
|
|
+/* Per-CTP logical indices for protocol trap rules.
|
|
+ *
|
|
+ * The firmware pre-allocates a per-CTP PCE block for every port during
|
|
+ * init and reserves logical index 0 for its flow-control marking rule.
|
|
+ * Logical indices 1-4 are used here for link-local and multicast
|
|
+ * snooping traps; the firmware grows the underlying hardware block on
|
|
+ * demand as PCERULELOGICWRITE inserts new entries.
|
|
+ */
|
|
+#define MXL862XX_LINK_LOCAL_CTP_INDEX 1
|
|
+#define MXL862XX_IGMP_CTP_INDEX 2
|
|
+#define MXL862XX_MLDV1_CTP_INDEX 3
|
|
+#define MXL862XX_MLDV2_CTP_INDEX 4
|
|
+
|
|
+/* Install (or overwrite) a PCE rule via the firmware's logical-index
|
|
+ * API. The firmware translates the logical index in @rule->pattern.index
|
|
+ * to a physical position within the block selected by @rule->region and
|
|
+ * @rule->logicalportid, and expands the hardware block size as needed.
|
|
+ */
|
|
+static int mxl862xx_pce_rule_write(struct mxl862xx_priv *priv,
|
|
+ struct mxl862xx_pce_rule *rule)
|
|
+{
|
|
+ return MXL862XX_API_WRITE(priv, MXL862XX_TFLOW_PCERULELOGICWRITE,
|
|
+ *rule);
|
|
+}
|
|
+
|
|
+/* Fill the action fields of a PCE rule that traps ingress frames to
|
|
+ * the CPU port. Used by both the link-local trap and the multicast
|
|
+ * snooping traps. The caller must already have set the rule header
|
|
+ * (logicalportid, subifidgroup, region) and the pattern fields.
|
|
+ *
|
|
+ * PORTMAP_ALTERNATIVE redirects the frame to the CPU port but does
|
|
+ * not by itself bypass downstream flood gates. In SpTag mode the
|
|
+ * ingress port's private FID may have forward_unknown_multicast=false,
|
|
+ * which silently drops IGMP/MLD before they reach the CPU.
|
|
+ * Setting bFidEnable to cpu_trap_fid (a dedicated bridge with all
|
|
+ * flood modes enabled) overrides the FID used by the bridge engine,
|
|
+ * so the frame is never classified as blocked unknown MC regardless
|
|
+ * of the ingress port's standalone flood policy.
|
|
+ *
|
|
+ * Cross-state is enabled so trapped frames bypass STP port state.
|
|
+ */
|
|
+static void mxl862xx_fill_cpu_trap_action(struct dsa_switch *ds, int port,
|
|
+ struct mxl862xx_pce_rule *rule)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = ds->priv;
|
|
+ int cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
|
+
|
|
+ rule->action.port_map_action =
|
|
+ cpu_to_le32(MXL862XX_PCE_ACTION_PORTMAP_ALTERNATIVE);
|
|
+ mxl862xx_fw_portmap_set_bit(rule->action.forward_port_map, cpu_port);
|
|
+
|
|
+ rule->action.cross_state_action =
|
|
+ cpu_to_le32(MXL862XX_PCE_ACTION_CROSS_STATE_CROSS);
|
|
+
|
|
+ rule->action.fid_enable = 1;
|
|
+ rule->action.fid = priv->cpu_trap_fid;
|
|
+}
|
|
+
|
|
+/* Install a PCE rule that traps IEEE 802.1D link-local frames
|
|
+ * (01:80:c2:00:00:0x) to the CPU port for a single user port,
|
|
+ * preventing the hardware bridge from flooding them to other ports.
|
|
+ * The firmware does not install this rule by default because its own
|
|
+ * STP module is not used when DSA manages STP.
|
|
+ *
|
|
+ * The rule is written into the port's per-CTP flow table at logical
|
|
+ * index 1 using PCERULELOGICWRITE, which selects the per-CTP block via
|
|
+ * @region and @logicalportid and grows the block on demand.
|
|
+ *
|
|
+ * Cross-state is enabled so that link-local frames reach the CPU even
|
|
+ * when the bridge port is in BLOCKING or LEARNING state.
|
|
+ */
|
|
+static int mxl862xx_setup_link_local_trap(struct dsa_switch *ds, int port)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = ds->priv;
|
|
+ struct mxl862xx_pce_rule rule = {};
|
|
+
|
|
+ rule.logicalportid = port;
|
|
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
|
|
+
|
|
+ rule.pattern.index = cpu_to_le16(MXL862XX_LINK_LOCAL_CTP_INDEX);
|
|
+ rule.pattern.enable = 1;
|
|
+ rule.pattern.mac_dst_enable = 1;
|
|
+ memcpy(rule.pattern.mac_dst, eth_reserved_addr_base, ETH_ALEN);
|
|
+ rule.pattern.mac_dst_mask = cpu_to_le16(0x0001);
|
|
+
|
|
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
|
|
+
|
|
+ return mxl862xx_pce_rule_write(priv, &rule);
|
|
+}
|
|
+
|
|
+/* Install PCE rules that trap IGMP and MLD frames to the CPU port for
|
|
+ * a single user port. PORTMAP_ALTERNATIVE overrides the bridge
|
|
+ * forwarding portmap to the CPU port. bFidEnable points the bridge
|
|
+ * engine at cpu_trap_fid (all flood modes enabled) so the frames are
|
|
+ * never classified as blocked unknown MC regardless of the ingress
|
|
+ * port's standalone flood policy.
|
|
+ *
|
|
+ * Three rules are installed per port at logical indices in the per-CTP
|
|
+ * block:
|
|
+ * index 2 -- IPv4 IGMP (IP protocol 2, all versions)
|
|
+ * index 3 -- ICMPv6 types 130-132 (MLDv1 query, report, done)
|
|
+ * index 4 -- ICMPv6 type 143 (MLDv2 Listener Report)
|
|
+ *
|
|
+ * The MLDv1 rule uses range mode on the first two bytes after the IP
|
|
+ * header (ICMPv6 type + code): lower bound 0x8200 (type 130, code 0)
|
|
+ * to upper bound 0x84ff (type 132, code 255). The MLDv2 rule uses
|
|
+ * nibble mask 0x3 to match type 143 with any code byte.
|
|
+ */
|
|
+static int mxl862xx_setup_snooping_traps(struct dsa_switch *ds, int port)
|
|
+{
|
|
+ struct mxl862xx_priv *priv = ds->priv;
|
|
+ struct mxl862xx_pce_rule rule = {};
|
|
+ int ret;
|
|
+
|
|
+ rule.logicalportid = port;
|
|
+ rule.region = cpu_to_le32(MXL862XX_PCE_RULE_CTP);
|
|
+ mxl862xx_fill_cpu_trap_action(ds, port, &rule);
|
|
+
|
|
+ /* IGMP: IPv4 protocol 2, all versions */
|
|
+ rule.pattern.index = cpu_to_le16(MXL862XX_IGMP_CTP_INDEX);
|
|
+ rule.pattern.enable = 1;
|
|
+ rule.pattern.protocol = IPPROTO_IGMP;
|
|
+ rule.pattern.protocol_enable = 1;
|
|
+
|
|
+ ret = mxl862xx_pce_rule_write(priv, &rule);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* MLDv1: ICMPv6 types 130 (query), 131 (report), 132 (done).
|
|
+ * Range mode covers all three types with any code value.
|
|
+ */
|
|
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
|
|
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV1_CTP_INDEX);
|
|
+ rule.pattern.enable = 1;
|
|
+ rule.pattern.protocol = IPPROTO_ICMPV6;
|
|
+ rule.pattern.protocol_enable = 1;
|
|
+ rule.pattern.app_data_msb =
|
|
+ cpu_to_le16((u16)ICMPV6_MGM_QUERY << 8);
|
|
+ rule.pattern.app_mask_range_msb =
|
|
+ cpu_to_le16(((u16)ICMPV6_MGM_REDUCTION << 8) | 0xff);
|
|
+ rule.pattern.app_data_msb_enable = 1;
|
|
+ rule.pattern.app_mask_range_msb_select = 1; /* range mode */
|
|
+
|
|
+ ret = mxl862xx_pce_rule_write(priv, &rule);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* MLDv2: ICMPv6 type 143 (Listener Report v2), any code byte.
|
|
+ * Nibble mask 0x3 masks nibbles 0-1 (lower byte = code field).
|
|
+ */
|
|
+ memset(&rule.pattern, 0, sizeof(rule.pattern));
|
|
+ rule.pattern.index = cpu_to_le16(MXL862XX_MLDV2_CTP_INDEX);
|
|
+ rule.pattern.enable = 1;
|
|
+ rule.pattern.protocol = IPPROTO_ICMPV6;
|
|
+ rule.pattern.protocol_enable = 1;
|
|
+ rule.pattern.app_data_msb = cpu_to_le16((u16)ICMPV6_MLD2_REPORT << 8);
|
|
+ rule.pattern.app_mask_range_msb = cpu_to_le16(0x0003);
|
|
+ rule.pattern.app_data_msb_enable = 1;
|
|
+ /* app_mask_range_msb_select = 0: nibble mask mode (default) */
|
|
+
|
|
+ return mxl862xx_pce_rule_write(priv, &rule);
|
|
+}
|
|
+
|
|
static int mxl862xx_set_bridge_port(struct dsa_switch *ds, int port)
|
|
{
|
|
struct mxl862xx_bridge_port_config br_port_cfg = {};
|
|
@@ -684,6 +851,28 @@ static int mxl862xx_setup(struct dsa_swi
|
|
if (ret)
|
|
return ret;
|
|
|
|
+
|
|
+ /* Allocate a dedicated PCE snooping FID with all flood modes enabled.
|
|
+ * Per-port PCE trap rules (link-local, IGMP, MLD) set bFidEnable to
|
|
+ * this FID so that the bridge engine uses it for its flood-permission
|
|
+ * check instead of the ingress port's private FID (which has
|
|
+ * mc_flood=false to restrict unknown MC from reaching the CPU in the
|
|
+ * normal path). The hardware PCE FID action field is 6 bits wide, so
|
|
+ * the allocated ID must be in range 0..63.
|
|
+ */
|
|
+ ret = mxl862xx_allocate_bridge(priv);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ if (WARN_ON_ONCE(ret > 0x3F))
|
|
+ return -ERANGE;
|
|
+
|
|
+ priv->cpu_trap_fid = ret;
|
|
+
|
|
+ ret = mxl862xx_bridge_config_fwd(ds, priv->cpu_trap_fid,
|
|
+ true, true, true);
|
|
+ if (ret)
|
|
+ return ret;
|
|
schedule_delayed_work(&priv->stats_work,
|
|
MXL862XX_STATS_POLL_INTERVAL);
|
|
|
|
@@ -1383,6 +1572,15 @@ static int mxl862xx_port_setup(struct ds
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ /* install link-local and multicast snooping traps */
|
|
+ ret = mxl862xx_setup_link_local_trap(ds, port);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = mxl862xx_setup_snooping_traps(ds, port);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
priv->ports[port].ingress_evlan.block_size = priv->evlan_ingress_size;
|
|
ret = mxl862xx_evlan_block_alloc(priv, &priv->ports[port].ingress_evlan);
|
|
if (ret)
|
|
--- a/drivers/net/dsa/mxl862xx/mxl862xx.h
|
|
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.h
|
|
@@ -317,6 +317,13 @@ struct mxl862xx_fw_version {
|
|
* @evlan_ingress_size: per-port ingress Extended VLAN block size
|
|
* @evlan_egress_size: per-port egress Extended VLAN block size
|
|
* @vf_block_size: per-port VLAN Filter block size
|
|
+ * @cpu_trap_fid: firmware bridge FID allocated for PCE-trapped frames;
|
|
+ * configured with uc/mc/bc flood all enabled so that
|
|
+ * IGMP, MLD, and link-local frames always reach the CPU
|
|
+ * regardless of the ingress port's private FID flood
|
|
+ * policy. Set once in setup() and referenced by
|
|
+ * fill_cpu_trap_action() via bFidEnable. The PCE FID
|
|
+ * action field is 6 bits, so this value must be <= 63.
|
|
* @stats_work: periodic work item that polls RMON hardware counters
|
|
* and accumulates them into 64-bit per-port stats
|
|
*/
|
|
@@ -334,6 +341,7 @@ struct mxl862xx_priv {
|
|
u16 evlan_ingress_size;
|
|
u16 evlan_egress_size;
|
|
u16 vf_block_size;
|
|
+ u16 cpu_trap_fid;
|
|
struct delayed_work stats_work;
|
|
};
|
|
|