Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'introduce-the-dsa_xmit_port_mask-tagging-protocol-helper'

Vladimir Oltean says:

====================
Introduce the dsa_xmit_port_mask() tagging protocol helper

What
----

Some DSA tags have just the port number in the TX header format, others
have a bit field where in theory, multiple bits can be set, even though
DSA only sets one.

The latter kind is now making use of a dsa_xmit_port_mask() helper,
which will decide when to set more than 1 bit in that mask.

Why
---

David Yang has pointed out in a recently posted patch that HSR packet
duplication on transmission can be offloaded even on HSR-unaware
switches. This should be made generally available to all DSA switches.

How to test
-----------

These patches just lay the groundwork, and there should be no functional
change - so for this set, regression testing is all that's necessary.

For testing the HSR packet duplication idea, I've put together a branch:
https://github.com/vladimiroltean/linux/commits/dsa-simple-hsr-offload/
where most drivers are patched to call dsa_port_simple_hsr_join() and
dsa_port_simple_hsr_leave().

Assuming there are volunteers to also test the latter, one can enable
CONFIG_HSR and create a HSR device using:
$ ip link add name hsr0 type hsr slave1 swp0 slave2 swp1 supervision 45 version 1

This needs to be connected using 2 cables to another system where the
same command was run. Then, one should be able to ping the other board
through the hsr0 interface.

Without the Github branch, a ping over HSR should increase the DSA
conduit interface's TX counters by 2 packets. With the Github branch,
the TX counters should increase by only 1 packet.

Why so many patches
-------------------

To avoid the situation where a patch has to be backported, conflicts
with the work done here, pulls this in as a dependency, and that pulls
in 13 other unrelated drivers. These don't have any dependencies between
each other and can be cherry-picked at will (except they all depend on
patch 1/15).
====================

Link: https://patch.msgid.link/20251127120902.292555-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+46 -55
+18
net/dsa/tag.h
··· 319 319 return skb->data + 2 * ETH_ALEN; 320 320 } 321 321 322 + static inline unsigned long dsa_xmit_port_mask(const struct sk_buff *skb, 323 + const struct net_device *dev) 324 + { 325 + struct dsa_port *dp = dsa_user_to_port(dev); 326 + unsigned long mask = BIT(dp->index); 327 + 328 + if (IS_ENABLED(CONFIG_HSR) && 329 + unlikely(dev->features & NETIF_F_HW_HSR_DUP)) { 330 + struct net_device *hsr_dev = dp->hsr_dev; 331 + struct dsa_port *other_dp; 332 + 333 + dsa_hsr_foreach_port(other_dp, dp->ds, hsr_dev) 334 + mask |= BIT(other_dp->index); 335 + } 336 + 337 + return mask; 338 + } 339 + 322 340 /* Create 2 modaliases per tagging protocol, one to auto-load the module 323 341 * given the ID reported by get_tag_protocol(), and the other by name. 324 342 */
+4 -4
net/dsa/tag_brcm.c
··· 92 92 { 93 93 struct dsa_port *dp = dsa_user_to_port(dev); 94 94 u16 queue = skb_get_queue_mapping(skb); 95 + u16 port_mask; 95 96 u8 *brcm_tag; 96 97 97 98 /* The Ethernet switch we are interfaced with needs packets to be at ··· 120 119 brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) | 121 120 ((queue & BRCM_IG_TC_MASK) << BRCM_IG_TC_SHIFT); 122 121 brcm_tag[1] = 0; 123 - brcm_tag[2] = 0; 124 - if (dp->index == 8) 125 - brcm_tag[2] = BRCM_IG_DSTMAP2_MASK; 126 - brcm_tag[3] = (1 << dp->index) & BRCM_IG_DSTMAP1_MASK; 122 + port_mask = dsa_xmit_port_mask(skb, dev); 123 + brcm_tag[2] = (port_mask >> 8) & BRCM_IG_DSTMAP2_MASK; 124 + brcm_tag[3] = port_mask & BRCM_IG_DSTMAP1_MASK; 127 125 128 126 /* Now tell the conduit network device about the desired output queue 129 127 * as well
+2 -4
net/dsa/tag_gswip.c
··· 48 48 49 49 /* Byte 3 */ 50 50 #define GSWIP_TX_DPID_EN BIT(0) 51 - #define GSWIP_TX_PORT_MAP_SHIFT 1 52 - #define GSWIP_TX_PORT_MAP_MASK GENMASK(6, 1) 51 + #define GSWIP_TX_PORT_MAP GENMASK(6, 1) 53 52 54 53 #define GSWIP_RX_HEADER_LEN 8 55 54 ··· 60 61 static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb, 61 62 struct net_device *dev) 62 63 { 63 - struct dsa_port *dp = dsa_user_to_port(dev); 64 64 u8 *gswip_tag; 65 65 66 66 skb_push(skb, GSWIP_TX_HEADER_LEN); ··· 68 70 gswip_tag[0] = GSWIP_TX_SLPID_CPU; 69 71 gswip_tag[1] = GSWIP_TX_DPID_ELAN; 70 72 gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL; 71 - gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK; 73 + gswip_tag[3] = FIELD_PREP(GSWIP_TX_PORT_MAP, dsa_xmit_port_mask(skb, dev)); 72 74 gswip_tag[3] |= GSWIP_TX_DPID_EN; 73 75 74 76 return skb;
+1 -2
net/dsa/tag_hellcreek.c
··· 20 20 static struct sk_buff *hellcreek_xmit(struct sk_buff *skb, 21 21 struct net_device *dev) 22 22 { 23 - struct dsa_port *dp = dsa_user_to_port(dev); 24 23 u8 *tag; 25 24 26 25 /* Calculate checksums (if required) before adding the trailer tag to ··· 32 33 33 34 /* Tag encoding */ 34 35 tag = skb_put(skb, HELLCREEK_TAG_LEN); 35 - *tag = BIT(dp->index); 36 + *tag = dsa_xmit_port_mask(skb, dev); 36 37 37 38 return skb; 38 39 }
+4 -16
net/dsa/tag_ksz.c
··· 120 120 121 121 static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) 122 122 { 123 - struct dsa_port *dp = dsa_user_to_port(dev); 124 123 struct ethhdr *hdr; 125 124 u8 *tag; 126 125 ··· 130 131 tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); 131 132 hdr = skb_eth_hdr(skb); 132 133 133 - *tag = 1 << dp->index; 134 + *tag = dsa_xmit_port_mask(skb, dev); 134 135 if (is_link_local_ether_addr(hdr->h_dest)) 135 136 *tag |= KSZ8795_TAIL_TAG_OVERRIDE; 136 137 ··· 293 294 tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN); 294 295 hdr = skb_eth_hdr(skb); 295 296 296 - val = BIT(dp->index); 297 - 297 + val = dsa_xmit_port_mask(skb, dev); 298 298 val |= FIELD_PREP(KSZ9477_TAIL_TAG_PRIO, prio); 299 299 300 300 if (is_link_local_ether_addr(hdr->h_dest)) 301 301 val |= KSZ9477_TAIL_TAG_OVERRIDE; 302 - 303 - if (dev->features & NETIF_F_HW_HSR_DUP) { 304 - struct net_device *hsr_dev = dp->hsr_dev; 305 - struct dsa_port *other_dp; 306 - 307 - dsa_hsr_foreach_port(other_dp, dp->ds, hsr_dev) 308 - val |= BIT(other_dp->index); 309 - } 310 302 311 303 *tag = cpu_to_be16(val); 312 304 ··· 361 371 tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); 362 372 hdr = skb_eth_hdr(skb); 363 373 364 - *tag = BIT(dp->index); 365 - 374 + *tag = dsa_xmit_port_mask(skb, dev); 366 375 *tag |= FIELD_PREP(KSZ9893_TAIL_TAG_PRIO, prio); 367 376 368 377 if (is_link_local_ether_addr(hdr->h_dest)) ··· 425 436 426 437 tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN); 427 438 428 - val = BIT(dp->index); 429 - 439 + val = dsa_xmit_port_mask(skb, dev); 430 440 val |= FIELD_PREP(LAN937X_TAIL_TAG_PRIO, prio); 431 441 432 442 if (is_link_local_ether_addr(hdr->h_dest))
+2 -1
net/dsa/tag_mtk.c
··· 54 54 * whether that's a combined special tag with 802.1Q header. 55 55 */ 56 56 mtk_tag[0] = xmit_tpid; 57 - mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; 57 + mtk_tag[1] = FIELD_PREP(MTK_HDR_XMIT_DP_BIT_MASK, 58 + dsa_xmit_port_mask(skb, dev)); 58 59 59 60 /* Tag control information is kept for 802.1Q */ 60 61 if (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) {
+4 -3
net/dsa/tag_mxl-gsw1xx.c
··· 43 43 static struct sk_buff *gsw1xx_tag_xmit(struct sk_buff *skb, 44 44 struct net_device *dev) 45 45 { 46 - struct dsa_port *dp = dsa_user_to_port(dev); 47 46 __be16 *gsw1xx_tag; 47 + u16 tag; 48 48 49 49 /* provide additional space 'GSW1XX_HEADER_LEN' bytes */ 50 50 skb_push(skb, GSW1XX_HEADER_LEN); ··· 55 55 /* special tag ingress */ 56 56 gsw1xx_tag = dsa_etype_header_pos_tx(skb); 57 57 gsw1xx_tag[0] = htons(ETH_P_MXLGSW); 58 - gsw1xx_tag[1] = htons(GSW1XX_TX_PORT_MAP_EN | GSW1XX_TX_LRN_DIS | 59 - FIELD_PREP(GSW1XX_TX_PORT_MAP, BIT(dp->index))); 60 58 59 + tag = FIELD_PREP(GSW1XX_TX_PORT_MAP, dsa_xmit_port_mask(skb, dev)) | 60 + GSW1XX_TX_PORT_MAP_EN | GSW1XX_TX_LRN_DIS; 61 + gsw1xx_tag[1] = htons(tag); 61 62 gsw1xx_tag[2] = 0; 62 63 gsw1xx_tag[3] = 0; 63 64
+2 -4
net/dsa/tag_ocelot.c
··· 46 46 static struct sk_buff *ocelot_xmit(struct sk_buff *skb, 47 47 struct net_device *netdev) 48 48 { 49 - struct dsa_port *dp = dsa_user_to_port(netdev); 50 49 void *injection; 51 50 52 51 ocelot_xmit_common(skb, netdev, cpu_to_be32(0x8880000a), &injection); 53 - ocelot_ifh_set_dest(injection, BIT_ULL(dp->index)); 52 + ocelot_ifh_set_dest(injection, dsa_xmit_port_mask(skb, netdev)); 54 53 55 54 return skb; 56 55 } ··· 57 58 static struct sk_buff *seville_xmit(struct sk_buff *skb, 58 59 struct net_device *netdev) 59 60 { 60 - struct dsa_port *dp = dsa_user_to_port(netdev); 61 61 void *injection; 62 62 63 63 ocelot_xmit_common(skb, netdev, cpu_to_be32(0x88800005), &injection); 64 - seville_ifh_set_dest(injection, BIT_ULL(dp->index)); 64 + seville_ifh_set_dest(injection, dsa_xmit_port_mask(skb, netdev)); 65 65 66 66 return skb; 67 67 }
+1 -2
net/dsa/tag_qca.c
··· 14 14 15 15 static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) 16 16 { 17 - struct dsa_port *dp = dsa_user_to_port(dev); 18 17 __be16 *phdr; 19 18 u16 hdr; 20 19 ··· 25 26 /* Set the version field, and set destination port information */ 26 27 hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); 27 28 hdr |= QCA_HDR_XMIT_FROM_CPU; 28 - hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(dp->index)); 29 + hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, dsa_xmit_port_mask(skb, dev)); 29 30 30 31 *phdr = htons(hdr); 31 32
+1 -1
net/dsa/tag_rtl4_a.c
··· 57 57 58 58 out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT); 59 59 /* The lower bits indicate the port number */ 60 - out |= BIT(dp->index); 60 + out |= dsa_xmit_port_mask(skb, dev); 61 61 62 62 p = (__be16 *)(tag + 2); 63 63 *p = htons(out);
+1 -2
net/dsa/tag_rtl8_4.c
··· 103 103 static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev, 104 104 void *tag) 105 105 { 106 - struct dsa_port *dp = dsa_user_to_port(dev); 107 106 __be16 tag16[RTL8_4_TAG_LEN / 2]; 108 107 109 108 /* Set Realtek EtherType */ ··· 115 116 tag16[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1)); 116 117 117 118 /* Zero ALLOW; set RX (CPU->switch) forwarding port mask */ 118 - tag16[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index))); 119 + tag16[3] = htons(FIELD_PREP(RTL8_4_RX, dsa_xmit_port_mask(skb, dev))); 119 120 120 121 memcpy(tag, tag16, RTL8_4_TAG_LEN); 121 122 }
+1 -2
net/dsa/tag_rzn1_a5psw.c
··· 39 39 40 40 static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev) 41 41 { 42 - struct dsa_port *dp = dsa_user_to_port(dev); 43 42 struct a5psw_tag *ptag; 44 43 u32 data2_val; 45 44 ··· 59 60 60 61 ptag = dsa_etype_header_pos_tx(skb); 61 62 62 - data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, BIT(dp->index)); 63 + data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, dsa_xmit_port_mask(skb, dev)); 63 64 ptag->ctrl_tag = htons(ETH_P_DSA_A5PSW); 64 65 ptag->ctrl_data = htons(A5PSW_CTRL_DATA_FORCE_FORWARD); 65 66 ptag->ctrl_data2_lo = htons(data2_val);
+1 -2
net/dsa/tag_trailer.c
··· 14 14 15 15 static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev) 16 16 { 17 - struct dsa_port *dp = dsa_user_to_port(dev); 18 17 u8 *trailer; 19 18 20 19 trailer = skb_put(skb, 4); 21 20 trailer[0] = 0x80; 22 - trailer[1] = 1 << dp->index; 21 + trailer[1] = dsa_xmit_port_mask(skb, dev); 23 22 trailer[2] = 0x10; 24 23 trailer[3] = 0x00; 25 24
+1 -7
net/dsa/tag_xrs700x.c
··· 13 13 14 14 static struct sk_buff *xrs700x_xmit(struct sk_buff *skb, struct net_device *dev) 15 15 { 16 - struct dsa_port *partner, *dp = dsa_user_to_port(dev); 17 16 u8 *trailer; 18 17 19 18 trailer = skb_put(skb, 1); 20 - trailer[0] = BIT(dp->index); 21 - 22 - if (dp->hsr_dev) 23 - dsa_hsr_foreach_port(partner, dp->ds, dp->hsr_dev) 24 - if (partner != dp) 25 - trailer[0] |= BIT(partner->index); 19 + trailer[0] = dsa_xmit_port_mask(skb, dev); 26 20 27 21 return skb; 28 22 }
+3 -5
net/dsa/tag_yt921x.c
··· 38 38 #define YT921X_TAG_RX_CMD_FORWARDED 0x80 39 39 #define YT921X_TAG_RX_CMD_UNK_UCAST 0xb2 40 40 #define YT921X_TAG_RX_CMD_UNK_MCAST 0xb4 41 - #define YT921X_TAG_TX_PORTS_M GENMASK(10, 0) 42 - #define YT921X_TAG_TX_PORTn(port) BIT(port) 41 + #define YT921X_TAG_TX_PORTS GENMASK(10, 0) 43 42 44 43 static struct sk_buff * 45 44 yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev) 46 45 { 47 - struct dsa_port *dp = dsa_user_to_port(netdev); 48 - unsigned int port = dp->index; 49 46 __be16 *tag; 50 47 u16 tx; 51 48 ··· 55 58 /* VLAN tag unrelated when TX */ 56 59 tag[1] = 0; 57 60 tag[2] = 0; 58 - tx = YT921X_TAG_PORT_EN | YT921X_TAG_TX_PORTn(port); 61 + tx = FIELD_PREP(YT921X_TAG_TX_PORTS, dsa_xmit_port_mask(skb, netdev)) | 62 + YT921X_TAG_PORT_EN; 59 63 tag[3] = htons(tx); 60 64 61 65 return skb;