mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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>
This commit is contained in:
@@ -319,6 +319,24 @@ static inline void *dsa_etype_header_pos_tx(struct sk_buff *skb)
|
||||
return skb->data + 2 * ETH_ALEN;
|
||||
}
|
||||
|
||||
static inline unsigned long dsa_xmit_port_mask(const struct sk_buff *skb,
|
||||
const struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
unsigned long mask = BIT(dp->index);
|
||||
|
||||
if (IS_ENABLED(CONFIG_HSR) &&
|
||||
unlikely(dev->features & NETIF_F_HW_HSR_DUP)) {
|
||||
struct net_device *hsr_dev = dp->hsr_dev;
|
||||
struct dsa_port *other_dp;
|
||||
|
||||
dsa_hsr_foreach_port(other_dp, dp->ds, hsr_dev)
|
||||
mask |= BIT(other_dp->index);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* Create 2 modaliases per tagging protocol, one to auto-load the module
|
||||
* given the ID reported by get_tag_protocol(), and the other by name.
|
||||
*/
|
||||
|
||||
@@ -92,6 +92,7 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
u16 queue = skb_get_queue_mapping(skb);
|
||||
u16 port_mask;
|
||||
u8 *brcm_tag;
|
||||
|
||||
/* The Ethernet switch we are interfaced with needs packets to be at
|
||||
@@ -119,10 +120,9 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
|
||||
brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
|
||||
((queue & BRCM_IG_TC_MASK) << BRCM_IG_TC_SHIFT);
|
||||
brcm_tag[1] = 0;
|
||||
brcm_tag[2] = 0;
|
||||
if (dp->index == 8)
|
||||
brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
|
||||
brcm_tag[3] = (1 << dp->index) & BRCM_IG_DSTMAP1_MASK;
|
||||
port_mask = dsa_xmit_port_mask(skb, dev);
|
||||
brcm_tag[2] = (port_mask >> 8) & BRCM_IG_DSTMAP2_MASK;
|
||||
brcm_tag[3] = port_mask & BRCM_IG_DSTMAP1_MASK;
|
||||
|
||||
/* Now tell the conduit network device about the desired output queue
|
||||
* as well
|
||||
|
||||
@@ -48,8 +48,7 @@
|
||||
|
||||
/* Byte 3 */
|
||||
#define GSWIP_TX_DPID_EN BIT(0)
|
||||
#define GSWIP_TX_PORT_MAP_SHIFT 1
|
||||
#define GSWIP_TX_PORT_MAP_MASK GENMASK(6, 1)
|
||||
#define GSWIP_TX_PORT_MAP GENMASK(6, 1)
|
||||
|
||||
#define GSWIP_RX_HEADER_LEN 8
|
||||
|
||||
@@ -61,7 +60,6 @@
|
||||
static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
u8 *gswip_tag;
|
||||
|
||||
skb_push(skb, GSWIP_TX_HEADER_LEN);
|
||||
@@ -70,7 +68,7 @@ static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb,
|
||||
gswip_tag[0] = GSWIP_TX_SLPID_CPU;
|
||||
gswip_tag[1] = GSWIP_TX_DPID_ELAN;
|
||||
gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL;
|
||||
gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK;
|
||||
gswip_tag[3] = FIELD_PREP(GSWIP_TX_PORT_MAP, dsa_xmit_port_mask(skb, dev));
|
||||
gswip_tag[3] |= GSWIP_TX_DPID_EN;
|
||||
|
||||
return skb;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
static struct sk_buff *hellcreek_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
u8 *tag;
|
||||
|
||||
/* Calculate checksums (if required) before adding the trailer tag to
|
||||
@@ -33,7 +32,7 @@ static struct sk_buff *hellcreek_xmit(struct sk_buff *skb,
|
||||
|
||||
/* Tag encoding */
|
||||
tag = skb_put(skb, HELLCREEK_TAG_LEN);
|
||||
*tag = BIT(dp->index);
|
||||
*tag = dsa_xmit_port_mask(skb, dev);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,6 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
|
||||
|
||||
static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
struct ethhdr *hdr;
|
||||
u8 *tag;
|
||||
|
||||
@@ -131,7 +130,7 @@ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
|
||||
hdr = skb_eth_hdr(skb);
|
||||
|
||||
*tag = 1 << dp->index;
|
||||
*tag = dsa_xmit_port_mask(skb, dev);
|
||||
if (is_link_local_ether_addr(hdr->h_dest))
|
||||
*tag |= KSZ8795_TAIL_TAG_OVERRIDE;
|
||||
|
||||
@@ -294,21 +293,12 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
|
||||
tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN);
|
||||
hdr = skb_eth_hdr(skb);
|
||||
|
||||
val = BIT(dp->index);
|
||||
|
||||
val = dsa_xmit_port_mask(skb, dev);
|
||||
val |= FIELD_PREP(KSZ9477_TAIL_TAG_PRIO, prio);
|
||||
|
||||
if (is_link_local_ether_addr(hdr->h_dest))
|
||||
val |= KSZ9477_TAIL_TAG_OVERRIDE;
|
||||
|
||||
if (dev->features & NETIF_F_HW_HSR_DUP) {
|
||||
struct net_device *hsr_dev = dp->hsr_dev;
|
||||
struct dsa_port *other_dp;
|
||||
|
||||
dsa_hsr_foreach_port(other_dp, dp->ds, hsr_dev)
|
||||
val |= BIT(other_dp->index);
|
||||
}
|
||||
|
||||
*tag = cpu_to_be16(val);
|
||||
|
||||
return ksz_defer_xmit(dp, skb);
|
||||
@@ -371,8 +361,7 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
|
||||
tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
|
||||
hdr = skb_eth_hdr(skb);
|
||||
|
||||
*tag = BIT(dp->index);
|
||||
|
||||
*tag = dsa_xmit_port_mask(skb, dev);
|
||||
*tag |= FIELD_PREP(KSZ9893_TAIL_TAG_PRIO, prio);
|
||||
|
||||
if (is_link_local_ether_addr(hdr->h_dest))
|
||||
@@ -436,8 +425,7 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb,
|
||||
|
||||
tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN);
|
||||
|
||||
val = BIT(dp->index);
|
||||
|
||||
val = dsa_xmit_port_mask(skb, dev);
|
||||
val |= FIELD_PREP(LAN937X_TAIL_TAG_PRIO, prio);
|
||||
|
||||
if (is_link_local_ether_addr(hdr->h_dest))
|
||||
|
||||
@@ -54,7 +54,8 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
|
||||
* whether that's a combined special tag with 802.1Q header.
|
||||
*/
|
||||
mtk_tag[0] = xmit_tpid;
|
||||
mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
|
||||
mtk_tag[1] = FIELD_PREP(MTK_HDR_XMIT_DP_BIT_MASK,
|
||||
dsa_xmit_port_mask(skb, dev));
|
||||
|
||||
/* Tag control information is kept for 802.1Q */
|
||||
if (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) {
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
static struct sk_buff *gsw1xx_tag_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
__be16 *gsw1xx_tag;
|
||||
u16 tag;
|
||||
|
||||
/* provide additional space 'GSW1XX_HEADER_LEN' bytes */
|
||||
skb_push(skb, GSW1XX_HEADER_LEN);
|
||||
@@ -55,9 +55,10 @@ static struct sk_buff *gsw1xx_tag_xmit(struct sk_buff *skb,
|
||||
/* special tag ingress */
|
||||
gsw1xx_tag = dsa_etype_header_pos_tx(skb);
|
||||
gsw1xx_tag[0] = htons(ETH_P_MXLGSW);
|
||||
gsw1xx_tag[1] = htons(GSW1XX_TX_PORT_MAP_EN | GSW1XX_TX_LRN_DIS |
|
||||
FIELD_PREP(GSW1XX_TX_PORT_MAP, BIT(dp->index)));
|
||||
|
||||
tag = FIELD_PREP(GSW1XX_TX_PORT_MAP, dsa_xmit_port_mask(skb, dev)) |
|
||||
GSW1XX_TX_PORT_MAP_EN | GSW1XX_TX_LRN_DIS;
|
||||
gsw1xx_tag[1] = htons(tag);
|
||||
gsw1xx_tag[2] = 0;
|
||||
gsw1xx_tag[3] = 0;
|
||||
|
||||
|
||||
@@ -46,11 +46,10 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
|
||||
static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(netdev);
|
||||
void *injection;
|
||||
|
||||
ocelot_xmit_common(skb, netdev, cpu_to_be32(0x8880000a), &injection);
|
||||
ocelot_ifh_set_dest(injection, BIT_ULL(dp->index));
|
||||
ocelot_ifh_set_dest(injection, dsa_xmit_port_mask(skb, netdev));
|
||||
|
||||
return skb;
|
||||
}
|
||||
@@ -58,11 +57,10 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
|
||||
static struct sk_buff *seville_xmit(struct sk_buff *skb,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(netdev);
|
||||
void *injection;
|
||||
|
||||
ocelot_xmit_common(skb, netdev, cpu_to_be32(0x88800005), &injection);
|
||||
seville_ifh_set_dest(injection, BIT_ULL(dp->index));
|
||||
seville_ifh_set_dest(injection, dsa_xmit_port_mask(skb, netdev));
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
__be16 *phdr;
|
||||
u16 hdr;
|
||||
|
||||
@@ -26,7 +25,7 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
/* Set the version field, and set destination port information */
|
||||
hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
|
||||
hdr |= QCA_HDR_XMIT_FROM_CPU;
|
||||
hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(dp->index));
|
||||
hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, dsa_xmit_port_mask(skb, dev));
|
||||
|
||||
*phdr = htons(hdr);
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
|
||||
|
||||
out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT);
|
||||
/* The lower bits indicate the port number */
|
||||
out |= BIT(dp->index);
|
||||
out |= dsa_xmit_port_mask(skb, dev);
|
||||
|
||||
p = (__be16 *)(tag + 2);
|
||||
*p = htons(out);
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev,
|
||||
void *tag)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
__be16 tag16[RTL8_4_TAG_LEN / 2];
|
||||
|
||||
/* Set Realtek EtherType */
|
||||
@@ -116,7 +115,7 @@ static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev,
|
||||
tag16[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1));
|
||||
|
||||
/* Zero ALLOW; set RX (CPU->switch) forwarding port mask */
|
||||
tag16[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index)));
|
||||
tag16[3] = htons(FIELD_PREP(RTL8_4_RX, dsa_xmit_port_mask(skb, dev)));
|
||||
|
||||
memcpy(tag, tag16, RTL8_4_TAG_LEN);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ struct a5psw_tag {
|
||||
|
||||
static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
struct a5psw_tag *ptag;
|
||||
u32 data2_val;
|
||||
|
||||
@@ -60,7 +59,7 @@ static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *de
|
||||
|
||||
ptag = dsa_etype_header_pos_tx(skb);
|
||||
|
||||
data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, BIT(dp->index));
|
||||
data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, dsa_xmit_port_mask(skb, dev));
|
||||
ptag->ctrl_tag = htons(ETH_P_DSA_A5PSW);
|
||||
ptag->ctrl_data = htons(A5PSW_CTRL_DATA_FORCE_FORWARD);
|
||||
ptag->ctrl_data2_lo = htons(data2_val);
|
||||
|
||||
@@ -14,12 +14,11 @@
|
||||
|
||||
static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(dev);
|
||||
u8 *trailer;
|
||||
|
||||
trailer = skb_put(skb, 4);
|
||||
trailer[0] = 0x80;
|
||||
trailer[1] = 1 << dp->index;
|
||||
trailer[1] = dsa_xmit_port_mask(skb, dev);
|
||||
trailer[2] = 0x10;
|
||||
trailer[3] = 0x00;
|
||||
|
||||
|
||||
@@ -13,16 +13,10 @@
|
||||
|
||||
static struct sk_buff *xrs700x_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *partner, *dp = dsa_user_to_port(dev);
|
||||
u8 *trailer;
|
||||
|
||||
trailer = skb_put(skb, 1);
|
||||
trailer[0] = BIT(dp->index);
|
||||
|
||||
if (dp->hsr_dev)
|
||||
dsa_hsr_foreach_port(partner, dp->ds, dp->hsr_dev)
|
||||
if (partner != dp)
|
||||
trailer[0] |= BIT(partner->index);
|
||||
trailer[0] = dsa_xmit_port_mask(skb, dev);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
@@ -38,14 +38,11 @@
|
||||
#define YT921X_TAG_RX_CMD_FORWARDED 0x80
|
||||
#define YT921X_TAG_RX_CMD_UNK_UCAST 0xb2
|
||||
#define YT921X_TAG_RX_CMD_UNK_MCAST 0xb4
|
||||
#define YT921X_TAG_TX_PORTS_M GENMASK(10, 0)
|
||||
#define YT921X_TAG_TX_PORTn(port) BIT(port)
|
||||
#define YT921X_TAG_TX_PORTS GENMASK(10, 0)
|
||||
|
||||
static struct sk_buff *
|
||||
yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_user_to_port(netdev);
|
||||
unsigned int port = dp->index;
|
||||
__be16 *tag;
|
||||
u16 tx;
|
||||
|
||||
@@ -58,7 +55,8 @@ yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
/* VLAN tag unrelated when TX */
|
||||
tag[1] = 0;
|
||||
tag[2] = 0;
|
||||
tx = YT921X_TAG_PORT_EN | YT921X_TAG_TX_PORTn(port);
|
||||
tx = FIELD_PREP(YT921X_TAG_TX_PORTS, dsa_xmit_port_mask(skb, netdev)) |
|
||||
YT921X_TAG_PORT_EN;
|
||||
tag[3] = htons(tx);
|
||||
|
||||
return skb;
|
||||
|
||||
Reference in New Issue
Block a user