Commit | Line | Data |
---|---|---|
dfedd3b6 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
8b8010fb WH |
2 | /* |
3 | * net/dsa/tag_ksz.c - Microchip KSZ Switch tag format handling | |
4 | * Copyright (c) 2017 Microchip Technology | |
8b8010fb WH |
5 | */ |
6 | ||
7 | #include <linux/etherdevice.h> | |
8 | #include <linux/list.h> | |
8b8010fb WH |
9 | #include <net/dsa.h> |
10 | #include "dsa_priv.h" | |
11 | ||
bafe9ba7 TH |
12 | /* Typically only one byte is used for tail tag. */ |
13 | #define KSZ_EGRESS_TAG_LEN 1 | |
88b573af | 14 | #define KSZ_INGRESS_TAG_LEN 1 |
8b8010fb | 15 | |
bafe9ba7 TH |
16 | static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, |
17 | struct net_device *dev, | |
18 | unsigned int port, unsigned int len) | |
8b8010fb | 19 | { |
bafe9ba7 TH |
20 | skb->dev = dsa_master_find_slave(dev, 0, port); |
21 | if (!skb->dev) | |
22 | return NULL; | |
8b8010fb | 23 | |
bafe9ba7 | 24 | pskb_trim_rcsum(skb, skb->len - len); |
8b8010fb | 25 | |
bea79078 | 26 | dsa_default_offload_fwd_mark(skb); |
cbd72b48 | 27 | |
bafe9ba7 TH |
28 | return skb; |
29 | } | |
3775b1b7 | 30 | |
016e43a2 TH |
31 | /* |
32 | * For Ingress (Host -> KSZ8795), 1 byte is added before FCS. | |
33 | * --------------------------------------------------------------------------- | |
34 | * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag(1byte)|FCS(4bytes) | |
35 | * --------------------------------------------------------------------------- | |
36 | * tag : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) | |
37 | * | |
38 | * For Egress (KSZ8795 -> Host), 1 byte is added before FCS. | |
39 | * --------------------------------------------------------------------------- | |
40 | * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) | |
41 | * --------------------------------------------------------------------------- | |
42 | * tag0 : zero-based value represents port | |
43 | * (eg, 0x00=port1, 0x02=port3, 0x06=port7) | |
44 | */ | |
45 | ||
016e43a2 TH |
46 | #define KSZ8795_TAIL_TAG_OVERRIDE BIT(6) |
47 | #define KSZ8795_TAIL_TAG_LOOKUP BIT(7) | |
48 | ||
49 | static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) | |
50 | { | |
51 | struct dsa_port *dp = dsa_slave_to_port(dev); | |
016e43a2 TH |
52 | u8 *tag; |
53 | u8 *addr; | |
54 | ||
37120f23 LS |
55 | if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) |
56 | return NULL; | |
57 | ||
016e43a2 | 58 | /* Tag encoding */ |
88fda8ee CE |
59 | tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); |
60 | addr = skb_mac_header(skb); | |
016e43a2 TH |
61 | |
62 | *tag = 1 << dp->index; | |
63 | if (is_link_local_ether_addr(addr)) | |
64 | *tag |= KSZ8795_TAIL_TAG_OVERRIDE; | |
65 | ||
88fda8ee | 66 | return skb; |
016e43a2 TH |
67 | } |
68 | ||
29a097b7 | 69 | static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev) |
016e43a2 TH |
70 | { |
71 | u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; | |
72 | ||
73 | return ksz_common_rcv(skb, dev, tag[0] & 7, KSZ_EGRESS_TAG_LEN); | |
74 | } | |
75 | ||
76 | static const struct dsa_device_ops ksz8795_netdev_ops = { | |
77 | .name = "ksz8795", | |
78 | .proto = DSA_TAG_PROTO_KSZ8795, | |
79 | .xmit = ksz8795_xmit, | |
80 | .rcv = ksz8795_rcv, | |
4e500251 | 81 | .needed_tailroom = KSZ_INGRESS_TAG_LEN, |
016e43a2 TH |
82 | }; |
83 | ||
84 | DSA_TAG_DRIVER(ksz8795_netdev_ops); | |
85 | MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795); | |
86 | ||
bafe9ba7 TH |
87 | /* |
88 | * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS. | |
89 | * --------------------------------------------------------------------------- | |
90 | * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) | |
91 | * --------------------------------------------------------------------------- | |
92 | * tag0 : Prioritization (not used now) | |
93 | * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) | |
94 | * | |
95 | * For Egress (KSZ9477 -> Host), 1 byte is added before FCS. | |
96 | * --------------------------------------------------------------------------- | |
97 | * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) | |
98 | * --------------------------------------------------------------------------- | |
99 | * tag0 : zero-based value represents port | |
100 | * (eg, 0x00=port1, 0x02=port3, 0x06=port7) | |
101 | */ | |
102 | ||
103 | #define KSZ9477_INGRESS_TAG_LEN 2 | |
104 | #define KSZ9477_PTP_TAG_LEN 4 | |
105 | #define KSZ9477_PTP_TAG_INDICATION 0x80 | |
106 | ||
107 | #define KSZ9477_TAIL_TAG_OVERRIDE BIT(9) | |
108 | #define KSZ9477_TAIL_TAG_LOOKUP BIT(10) | |
109 | ||
110 | static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, | |
111 | struct net_device *dev) | |
112 | { | |
113 | struct dsa_port *dp = dsa_slave_to_port(dev); | |
ed6444ea | 114 | __be16 *tag; |
bafe9ba7 | 115 | u8 *addr; |
ed6444ea | 116 | u16 val; |
bafe9ba7 | 117 | |
37120f23 LS |
118 | if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) |
119 | return NULL; | |
120 | ||
bafe9ba7 | 121 | /* Tag encoding */ |
88fda8ee CE |
122 | tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN); |
123 | addr = skb_mac_header(skb); | |
8b8010fb | 124 | |
ed6444ea | 125 | val = BIT(dp->index); |
8a75b9d4 MV |
126 | |
127 | if (is_link_local_ether_addr(addr)) | |
ed6444ea | 128 | val |= KSZ9477_TAIL_TAG_OVERRIDE; |
8a75b9d4 | 129 | |
ed6444ea | 130 | *tag = cpu_to_be16(val); |
bafe9ba7 | 131 | |
88fda8ee | 132 | return skb; |
bafe9ba7 TH |
133 | } |
134 | ||
29a097b7 | 135 | static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev) |
bafe9ba7 TH |
136 | { |
137 | /* Tag decoding */ | |
138 | u8 *tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; | |
139 | unsigned int port = tag[0] & 7; | |
140 | unsigned int len = KSZ_EGRESS_TAG_LEN; | |
141 | ||
142 | /* Extra 4-bytes PTP timestamp */ | |
143 | if (tag[0] & KSZ9477_PTP_TAG_INDICATION) | |
144 | len += KSZ9477_PTP_TAG_LEN; | |
145 | ||
146 | return ksz_common_rcv(skb, dev, port, len); | |
8b8010fb WH |
147 | } |
148 | ||
f81a43e8 | 149 | static const struct dsa_device_ops ksz9477_netdev_ops = { |
875138f8 | 150 | .name = "ksz9477", |
056eed2f | 151 | .proto = DSA_TAG_PROTO_KSZ9477, |
bafe9ba7 TH |
152 | .xmit = ksz9477_xmit, |
153 | .rcv = ksz9477_rcv, | |
4e500251 | 154 | .needed_tailroom = KSZ9477_INGRESS_TAG_LEN, |
8b8010fb | 155 | }; |
88b573af | 156 | |
d3b8c049 | 157 | DSA_TAG_DRIVER(ksz9477_netdev_ops); |
0b42f033 AL |
158 | MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9477); |
159 | ||
88b573af TH |
160 | #define KSZ9893_TAIL_TAG_OVERRIDE BIT(5) |
161 | #define KSZ9893_TAIL_TAG_LOOKUP BIT(6) | |
162 | ||
163 | static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, | |
164 | struct net_device *dev) | |
165 | { | |
166 | struct dsa_port *dp = dsa_slave_to_port(dev); | |
88b573af TH |
167 | u8 *addr; |
168 | u8 *tag; | |
169 | ||
37120f23 LS |
170 | if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) |
171 | return NULL; | |
172 | ||
88b573af | 173 | /* Tag encoding */ |
88fda8ee CE |
174 | tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); |
175 | addr = skb_mac_header(skb); | |
88b573af TH |
176 | |
177 | *tag = BIT(dp->index); | |
178 | ||
179 | if (is_link_local_ether_addr(addr)) | |
180 | *tag |= KSZ9893_TAIL_TAG_OVERRIDE; | |
181 | ||
88fda8ee | 182 | return skb; |
88b573af TH |
183 | } |
184 | ||
f81a43e8 | 185 | static const struct dsa_device_ops ksz9893_netdev_ops = { |
875138f8 | 186 | .name = "ksz9893", |
056eed2f | 187 | .proto = DSA_TAG_PROTO_KSZ9893, |
88b573af TH |
188 | .xmit = ksz9893_xmit, |
189 | .rcv = ksz9477_rcv, | |
4e500251 | 190 | .needed_tailroom = KSZ_INGRESS_TAG_LEN, |
88b573af | 191 | }; |
0b42f033 | 192 | |
d3b8c049 | 193 | DSA_TAG_DRIVER(ksz9893_netdev_ops); |
0b42f033 | 194 | MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893); |
d3b8c049 | 195 | |
092f8751 PV |
196 | /* For xmit, 2 bytes are added before FCS. |
197 | * --------------------------------------------------------------------------- | |
198 | * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) | |
199 | * --------------------------------------------------------------------------- | |
200 | * tag0 : represents tag override, lookup and valid | |
201 | * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) | |
202 | * | |
203 | * For rcv, 1 byte is added before FCS. | |
204 | * --------------------------------------------------------------------------- | |
205 | * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) | |
206 | * --------------------------------------------------------------------------- | |
207 | * tag0 : zero-based value represents port | |
208 | * (eg, 0x00=port1, 0x02=port3, 0x07=port8) | |
209 | */ | |
210 | #define LAN937X_EGRESS_TAG_LEN 2 | |
211 | ||
212 | #define LAN937X_TAIL_TAG_BLOCKING_OVERRIDE BIT(11) | |
213 | #define LAN937X_TAIL_TAG_LOOKUP BIT(12) | |
214 | #define LAN937X_TAIL_TAG_VALID BIT(13) | |
215 | #define LAN937X_TAIL_TAG_PORT_MASK 7 | |
216 | ||
217 | static struct sk_buff *lan937x_xmit(struct sk_buff *skb, | |
218 | struct net_device *dev) | |
219 | { | |
220 | struct dsa_port *dp = dsa_slave_to_port(dev); | |
221 | const struct ethhdr *hdr = eth_hdr(skb); | |
222 | __be16 *tag; | |
223 | u16 val; | |
224 | ||
225 | if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) | |
226 | return NULL; | |
227 | ||
228 | tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN); | |
229 | ||
230 | val = BIT(dp->index); | |
231 | ||
232 | if (is_link_local_ether_addr(hdr->h_dest)) | |
233 | val |= LAN937X_TAIL_TAG_BLOCKING_OVERRIDE; | |
234 | ||
235 | /* Tail tag valid bit - This bit should always be set by the CPU */ | |
236 | val |= LAN937X_TAIL_TAG_VALID; | |
237 | ||
238 | put_unaligned_be16(val, tag); | |
239 | ||
240 | return skb; | |
241 | } | |
242 | ||
243 | static const struct dsa_device_ops lan937x_netdev_ops = { | |
244 | .name = "lan937x", | |
245 | .proto = DSA_TAG_PROTO_LAN937X, | |
246 | .xmit = lan937x_xmit, | |
247 | .rcv = ksz9477_rcv, | |
248 | .needed_tailroom = LAN937X_EGRESS_TAG_LEN, | |
249 | }; | |
250 | ||
251 | DSA_TAG_DRIVER(lan937x_netdev_ops); | |
252 | MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X); | |
253 | ||
d3b8c049 | 254 | static struct dsa_tag_driver *dsa_tag_driver_array[] = { |
016e43a2 | 255 | &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops), |
d3b8c049 AL |
256 | &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops), |
257 | &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops), | |
092f8751 | 258 | &DSA_TAG_DRIVER_NAME(lan937x_netdev_ops), |
d3b8c049 AL |
259 | }; |
260 | ||
261 | module_dsa_tag_drivers(dsa_tag_driver_array); | |
262 | ||
263 | MODULE_LICENSE("GPL"); |