diff options
author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2021-08-24 20:15:02 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-08-25 13:14:34 +0300 |
commit | 8ded9160928e545c2e694b77a87263fa078ff4c6 (patch) | |
tree | 074b602fa93e2dbeff8d3bb9fd215a3e0218baaa | |
parent | b0b8c67eaa5c65f8426017e78fcce12dc7d85110 (diff) | |
download | linux-8ded9160928e545c2e694b77a87263fa078ff4c6.tar.xz |
net: dsa: tag_sja1105: stop asking the sja1105 driver in sja1105_xmit_tpid
Introduced in commit 38b5beeae7a4 ("net: dsa: sja1105: prepare tagger
for handling DSA tags and VLAN simultaneously"), the sja1105_xmit_tpid
function solved quite a different problem than our needs are now.
Then, we used best-effort VLAN filtering and we were using the xmit_tpid
to tunnel packets coming from an 8021q upper through the TX VLAN allocated
by tag_8021q to that egress port. The need for a different VLAN protocol
depending on switch revision came from the fact that this in itself was
more of a hack to trick the hardware into accepting tunneled VLANs in
the first place.
Right now, we deny 8021q uppers (see sja1105_prechangeupper). Even if we
supported them again, we would not do that using the same method of
{tunneling the VLAN on egress, retagging the VLAN on ingress} that we
had in the best-effort VLAN filtering mode. It seems rather simpler that
we just allocate a VLAN in the VLAN table that is simply not used by the
bridge at all, or by any other port.
Anyway, I have 2 gripes with the current sja1105_xmit_tpid:
1. When sending packets on behalf of a VLAN-aware bridge (with the new
TX forwarding offload framework) plus untagged (with the tag_8021q
VLAN added by the tagger) packets, we can see that on SJA1105P/Q/R/S
and later (which have a qinq_tpid of ETH_P_8021AD), some packets sent
through the DSA master have a VLAN protocol of 0x8100 and others of
0x88a8. This is strange and there is no reason for it now. If we have
a bridge and are therefore forced to send using that bridge's TPID,
we can as well blend with that bridge's VLAN protocol for all packets.
2. The sja1105_xmit_tpid introduces a dependency on the sja1105 driver,
because it looks inside dp->priv. It is desirable to keep as much
separation between taggers and switch drivers as possible. Now it
doesn't do that anymore.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/dsa/sja1105/sja1105.h | 6 | ||||
-rw-r--r-- | drivers/net/dsa/sja1105/sja1105_main.c | 10 | ||||
-rw-r--r-- | drivers/net/dsa/sja1105/sja1105_spi.c | 10 | ||||
-rw-r--r-- | include/linux/dsa/sja1105.h | 1 | ||||
-rw-r--r-- | net/dsa/tag_sja1105.c | 38 |
5 files changed, 34 insertions, 31 deletions
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 2e899c9f036d..5e5d24e7c02b 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -115,12 +115,6 @@ struct sja1105_info { const struct sja1105_dynamic_table_ops *dyn_ops; const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; - /* Both E/T and P/Q/R/S have quirks when it comes to popping the S-Tag - * from double-tagged frames. E/T will pop it only when it's equal to - * TPID from the General Parameters Table, while P/Q/R/S will only - * pop it when it's equal to TPID2. - */ - u16 qinq_tpid; bool can_limit_mcast_flood; int (*reset_cmd)(struct dsa_switch *ds); int (*setup_rgmii_delay)(const void *ctx, int port); diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 976f06462223..2f8cc6686c38 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2295,15 +2295,6 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled, tpid2 = ETH_P_SJA1105; } - for (port = 0; port < ds->num_ports; port++) { - struct sja1105_port *sp = &priv->ports[port]; - - if (enabled) - sp->xmit_tpid = priv->info->qinq_tpid; - else - sp->xmit_tpid = ETH_P_SJA1105; - } - if (priv->vlan_aware == enabled) return 0; @@ -2988,7 +2979,6 @@ static int sja1105_setup_ports(struct sja1105_private *priv) } sp->xmit_worker = worker; skb_queue_head_init(&sp->xmit_queue); - sp->xmit_tpid = ETH_P_SJA1105; } return 0; diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 08cc5dbf2fa6..d60a530d0272 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -575,7 +575,6 @@ const struct sja1105_info sja1105e_info = { .part_no = SJA1105ET_PART_NO, .static_ops = sja1105e_table_ops, .dyn_ops = sja1105et_dyn_ops, - .qinq_tpid = ETH_P_8021Q, .tag_proto = DSA_TAG_PROTO_SJA1105, .can_limit_mcast_flood = false, .ptp_ts_bits = 24, @@ -608,7 +607,6 @@ const struct sja1105_info sja1105t_info = { .part_no = SJA1105ET_PART_NO, .static_ops = sja1105t_table_ops, .dyn_ops = sja1105et_dyn_ops, - .qinq_tpid = ETH_P_8021Q, .tag_proto = DSA_TAG_PROTO_SJA1105, .can_limit_mcast_flood = false, .ptp_ts_bits = 24, @@ -641,7 +639,6 @@ const struct sja1105_info sja1105p_info = { .part_no = SJA1105P_PART_NO, .static_ops = sja1105p_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1105, .can_limit_mcast_flood = true, .ptp_ts_bits = 32, @@ -675,7 +672,6 @@ const struct sja1105_info sja1105q_info = { .part_no = SJA1105Q_PART_NO, .static_ops = sja1105q_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1105, .can_limit_mcast_flood = true, .ptp_ts_bits = 32, @@ -709,7 +705,6 @@ const struct sja1105_info sja1105r_info = { .part_no = SJA1105R_PART_NO, .static_ops = sja1105r_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1105, .can_limit_mcast_flood = true, .ptp_ts_bits = 32, @@ -747,7 +742,6 @@ const struct sja1105_info sja1105s_info = { .static_ops = sja1105s_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, .regs = &sja1105pqrs_regs, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1105, .can_limit_mcast_flood = true, .ptp_ts_bits = 32, @@ -784,7 +778,6 @@ const struct sja1105_info sja1110a_info = { .static_ops = sja1110_table_ops, .dyn_ops = sja1110_dyn_ops, .regs = &sja1110_regs, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1110, .can_limit_mcast_flood = true, .multiple_cascade_ports = true, @@ -835,7 +828,6 @@ const struct sja1105_info sja1110b_info = { .static_ops = sja1110_table_ops, .dyn_ops = sja1110_dyn_ops, .regs = &sja1110_regs, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1110, .can_limit_mcast_flood = true, .multiple_cascade_ports = true, @@ -886,7 +878,6 @@ const struct sja1105_info sja1110c_info = { .static_ops = sja1110_table_ops, .dyn_ops = sja1110_dyn_ops, .regs = &sja1110_regs, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1110, .can_limit_mcast_flood = true, .multiple_cascade_ports = true, @@ -937,7 +928,6 @@ const struct sja1105_info sja1110d_info = { .static_ops = sja1110_table_ops, .dyn_ops = sja1110_dyn_ops, .regs = &sja1110_regs, - .qinq_tpid = ETH_P_8021AD, .tag_proto = DSA_TAG_PROTO_SJA1110, .can_limit_mcast_flood = true, .multiple_cascade_ports = true, diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h index 8c5601f1c979..171106202fe5 100644 --- a/include/linux/dsa/sja1105.h +++ b/include/linux/dsa/sja1105.h @@ -67,7 +67,6 @@ struct sja1105_port { struct sja1105_tagger_data *data; struct dsa_port *dp; bool hwts_tx_en; - u16 xmit_tpid; }; enum sja1110_meta_tstamp { diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index a49308fbd19f..c054f48541c8 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -133,14 +133,44 @@ static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp, return NULL; } +/* Send VLAN tags with a TPID that blends in with whatever VLAN protocol a + * bridge spanning ports of this switch might have. + */ static u16 sja1105_xmit_tpid(struct dsa_port *dp) { - struct sja1105_port *sp = dp->priv; + struct dsa_switch *ds = dp->ds; + struct dsa_port *other_dp; + u16 proto; + + /* Since VLAN awareness is global, then if this port is VLAN-unaware, + * all ports are. Use the VLAN-unaware TPID used for tag_8021q. + */ + if (!dsa_port_is_vlan_filtering(dp)) + return ETH_P_SJA1105; + + /* Port is VLAN-aware, so there is a bridge somewhere (a single one, + * we're sure about that). It may not be on this port though, so we + * need to find it. + */ + list_for_each_entry(other_dp, &ds->dst->ports, list) { + if (other_dp->ds != ds) + continue; + + if (!other_dp->bridge_dev) + continue; + + /* Error is returned only if CONFIG_BRIDGE_VLAN_FILTERING, + * which seems pointless to handle, as our port cannot become + * VLAN-aware in that case. + */ + br_vlan_get_proto(other_dp->bridge_dev, &proto); + + return proto; + } - if (unlikely(!dsa_port_is_sja1105(dp))) - return ETH_P_8021Q; + WARN_ONCE(1, "Port is VLAN-aware but cannot find associated bridge!\n"); - return sp->xmit_tpid; + return ETH_P_SJA1105; } static struct sk_buff *sja1105_imprecise_xmit(struct sk_buff *skb, |