In VLAN-unaware mode, sja1105 uses VLAN tags with a custom TPID of 0xdadb. While in the yet-to-be introduced best_effort_vlan_filtering mode, it needs to work with normal VLAN TPID values. A complication arises when we must transmit a VLAN-tagged packet to the switch when it's in VLAN-aware mode. We need to construct a packet with 2 VLAN tags, and the switch will use the outer header for routing and pop it on egress. But sadly, here the 2 hardware generations don't behave the same: - E/T switches won't pop an ETH_P_8021AD tag on egress, it seems (packets will remain double-tagged). - P/Q/R/S switches will drop a packet with 2 ETH_P_8021Q tags (it looks like it tries to prevent VLAN hopping). But looks like the reverse is also true: - E/T switches have no problem popping the outer tag from packets with 2 ETH_P_8021Q tags. - P/Q/R/S will have no problem popping a single tag even if that is ETH_P_8021AD. So it is clear that if we want the hardware to work with dsa_8021q tagging in VLAN-aware mode, we need to send different TPIDs depending on revision. Keep that information in priv->info->qinq_tpid. The per-port tagger structure will hold an xmit_tpid value that depends not only upon the qinq_tpid, but also upon the VLAN awareness state itself (in case we must transmit using 0xdadb).
Unified · Split
| @@ -87,6 +87,12 @@ struct sja1105_info { · 86 unmodified lines | ||
| 87 | 87 | const struct sja1105_dynamic_table_ops *dyn_ops; |
| 88 | 88 | const struct sja1105_table_ops *static_ops; |
| 89 | 89 | const struct sja1105_regs *regs; |
| 90 | + /* Both E/T and P/Q/R/S have quirks when it comes to popping the S-Tag | |
| 91 | + * from double-tagged frames. E/T will pop it only when it's equal to | |
| 92 | + * TPID from the General Parameters Table, while P/Q/R/S will only | |
| 93 | + * pop it when it's equal to TPID2. | |
| 94 | + */ | |
| 95 | + u16 qinq_tpid; | |
| 90 | 96 | int (*reset_cmd)(struct dsa_switch *ds); |
| 91 | 97 | int (*setup_rgmii_delay)(const void *ctx, int port); |
| 92 | 98 | /* Prototypes from include/net/dsa.h */ |
| @@ -2153,6 +2153,15 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) · 2152 unmodified lines | ||
| 2153 | 2153 | tpid2 = ETH_P_SJA1105; |
| 2154 | 2154 | } |
| 2155 | 2155 | |
| 2156 | + for (port = 0; port < ds->num_ports; port++) { | |
| 2157 | + struct sja1105_port *sp = &priv->ports[port]; | |
| 2158 | + | |
| 2159 | + if (enabled) | |
| 2160 | + sp->xmit_tpid = priv->info->qinq_tpid; | |
| 2161 | + else | |
| 2162 | + sp->xmit_tpid = ETH_P_SJA1105; | |
| 2163 | + } | |
| 2164 | + | |
| 2156 | 2165 | if (!enabled) |
| 2157 | 2166 | state = SJA1105_VLAN_UNAWARE; |
| 2158 | 2167 | else |
| @@ -2866,6 +2875,7 @@ static int sja1105_probe(struct spi_device *spi) · 707 unmodified lines | ||
| 2866 | 2875 | goto out; |
| 2867 | 2876 | } |
| 2868 | 2877 | skb_queue_head_init(&sp->xmit_queue); |
| 2878 | + sp->xmit_tpid = ETH_P_SJA1105; | |
| 2869 | 2879 | } |
| 2870 | 2880 | |
| 2871 | 2881 | return 0; |
| @@ -512,6 +512,7 @@ struct sja1105_info sja1105e_info = { · 511 unmodified lines | ||
| 512 | 512 | .part_no = SJA1105ET_PART_NO, |
| 513 | 513 | .static_ops = sja1105e_table_ops, |
| 514 | 514 | .dyn_ops = sja1105et_dyn_ops, |
| 515 | + .qinq_tpid = ETH_P_8021Q, | |
| 515 | 516 | .ptp_ts_bits = 24, |
| 516 | 517 | .ptpegr_ts_bytes = 4, |
| 517 | 518 | .reset_cmd = sja1105et_reset_cmd, |
| @@ -526,6 +527,7 @@ struct sja1105_info sja1105t_info = { · 8 unmodified lines | ||
| 526 | 527 | .part_no = SJA1105ET_PART_NO, |
| 527 | 528 | .static_ops = sja1105t_table_ops, |
| 528 | 529 | .dyn_ops = sja1105et_dyn_ops, |
| 530 | + .qinq_tpid = ETH_P_8021Q, | |
| 529 | 531 | .ptp_ts_bits = 24, |
| 530 | 532 | .ptpegr_ts_bytes = 4, |
| 531 | 533 | .reset_cmd = sja1105et_reset_cmd, |
| @@ -540,6 +542,7 @@ struct sja1105_info sja1105p_info = { · 8 unmodified lines | ||
| 540 | 542 | .part_no = SJA1105P_PART_NO, |
| 541 | 543 | .static_ops = sja1105p_table_ops, |
| 542 | 544 | .dyn_ops = sja1105pqrs_dyn_ops, |
| 545 | + .qinq_tpid = ETH_P_8021AD, | |
| 543 | 546 | .ptp_ts_bits = 32, |
| 544 | 547 | .ptpegr_ts_bytes = 8, |
| 545 | 548 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
| @@ -555,6 +558,7 @@ struct sja1105_info sja1105q_info = { · 9 unmodified lines | ||
| 555 | 558 | .part_no = SJA1105Q_PART_NO, |
| 556 | 559 | .static_ops = sja1105q_table_ops, |
| 557 | 560 | .dyn_ops = sja1105pqrs_dyn_ops, |
| 561 | + .qinq_tpid = ETH_P_8021AD, | |
| 558 | 562 | .ptp_ts_bits = 32, |
| 559 | 563 | .ptpegr_ts_bytes = 8, |
| 560 | 564 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
| @@ -570,6 +574,7 @@ struct sja1105_info sja1105r_info = { · 9 unmodified lines | ||
| 570 | 574 | .part_no = SJA1105R_PART_NO, |
| 571 | 575 | .static_ops = sja1105r_table_ops, |
| 572 | 576 | .dyn_ops = sja1105pqrs_dyn_ops, |
| 577 | + .qinq_tpid = ETH_P_8021AD, | |
| 573 | 578 | .ptp_ts_bits = 32, |
| 574 | 579 | .ptpegr_ts_bytes = 8, |
| 575 | 580 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
| @@ -586,6 +591,7 @@ struct sja1105_info sja1105s_info = { · 10 unmodified lines | ||
| 586 | 591 | .static_ops = sja1105s_table_ops, |
| 587 | 592 | .dyn_ops = sja1105pqrs_dyn_ops, |
| 588 | 593 | .regs = &sja1105pqrs_regs, |
| 594 | + .qinq_tpid = ETH_P_8021AD, | |
| 589 | 595 | .ptp_ts_bits = 32, |
| 590 | 596 | .ptpegr_ts_bytes = 8, |
| 591 | 597 | .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay, |
| @@ -59,6 +59,7 @@ struct sja1105_port { · 58 unmodified lines | ||
| 59 | 59 | struct sja1105_tagger_data *data; |
| 60 | 60 | struct dsa_port *dp; |
| 61 | 61 | bool hwts_tx_en; |
| 62 | + u16 xmit_tpid; | |
| 62 | 63 | }; |
| 63 | 64 | |
| 64 | 65 | #endif /* _NET_DSA_SJA1105_H */ |
| @@ -69,12 +69,25 @@ static inline bool sja1105_is_meta_frame(const struct sk_buff *skb) · 68 unmodified lines | ||
| 69 | 69 | return true; |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | +static bool sja1105_can_use_vlan_as_tags(const struct sk_buff *skb) | |
| 73 | +{ | |
| 74 | + struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | |
| 75 | + | |
| 76 | + if (hdr->h_vlan_proto == ntohs(ETH_P_SJA1105)) | |
| 77 | + return true; | |
| 78 | + | |
| 79 | + if (hdr->h_vlan_proto != ntohs(ETH_P_8021Q)) | |
| 80 | + return false; | |
| 81 | + | |
| 82 | + return vid_is_dsa_8021q(ntohs(hdr->h_vlan_TCI) & VLAN_VID_MASK); | |
| 83 | +} | |
| 84 | + | |
| 72 | 85 | /* This is the first time the tagger sees the frame on RX. |
| 73 | 86 | * Figure out if we can decode it. |
| 74 | 87 | */ |
| 75 | 88 | static bool sja1105_filter(const struct sk_buff *skb, struct net_device *dev) |
| 76 | 89 | { |
| 77 | − if (!dsa_port_is_vlan_filtering(dev->dsa_ptr)) | |
| 90 | + if (sja1105_can_use_vlan_as_tags(skb)) | |
| 78 | 91 | return true; |
| 79 | 92 | if (sja1105_is_link_local(skb)) |
| 80 | 93 | return true; |
| @@ -96,6 +109,11 @@ static struct sk_buff *sja1105_defer_xmit(struct sja1105_port *sp, · 15 unmodified lines | ||
| 96 | 109 | return NULL; |
| 97 | 110 | } |
| 98 | 111 | |
| 112 | +static u16 sja1105_xmit_tpid(struct sja1105_port *sp) | |
| 113 | +{ | |
| 114 | + return sp->xmit_tpid; | |
| 115 | +} | |
| 116 | + | |
| 99 | 117 | static struct sk_buff *sja1105_xmit(struct sk_buff *skb, |
| 100 | 118 | struct net_device *netdev) |
| 101 | 119 | { |
| @@ -111,15 +129,7 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, · 9 unmodified lines | ||
| 111 | 129 | if (unlikely(sja1105_is_link_local(skb))) |
| 112 | 130 | return sja1105_defer_xmit(dp->priv, skb); |
| 113 | 131 | |
| 114 | − /* If we are under a vlan_filtering bridge, IP termination on | |
| 115 | − * switch ports based on 802.1Q tags is simply too brittle to | |
| 116 | − * be passable. So just defer to the dsa_slave_notag_xmit | |
| 117 | − * implementation. | |
| 118 | − */ | |
| 119 | − if (dsa_port_is_vlan_filtering(dp)) | |
| 120 | − return skb; | |
| 121 | − | |
| 122 | − return dsa_8021q_xmit(skb, netdev, ETH_P_SJA1105, | |
| 132 | + return dsa_8021q_xmit(skb, netdev, sja1105_xmit_tpid(dp->priv), | |
| 123 | 133 | ((pcp << VLAN_PRIO_SHIFT) | tx_vid)); |
| 124 | 134 | } |
| 125 | 135 | |
| @@ -258,7 +268,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, · 132 unmodified lines | ||
| 258 | 268 | |
| 259 | 269 | hdr = eth_hdr(skb); |
| 260 | 270 | tpid = ntohs(hdr->h_proto); |
| 261 | − is_tagged = (tpid == ETH_P_SJA1105); | |
| 271 | + is_tagged = (tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q); | |
| 262 | 272 | is_link_local = sja1105_is_link_local(skb); |
| 263 | 273 | is_meta = sja1105_is_meta_frame(skb); |
| 264 | 274 | |