]>
Commit | Line | Data |
---|---|---|
a556c76a AB |
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | /* | |
3 | * Microsemi Ocelot Switch driver | |
4 | * | |
5 | * Copyright (c) 2017 Microsemi Corporation | |
6 | */ | |
7 | #include <linux/etherdevice.h> | |
8 | #include <linux/ethtool.h> | |
9 | #include <linux/if_bridge.h> | |
10 | #include <linux/if_ether.h> | |
11 | #include <linux/if_vlan.h> | |
12 | #include <linux/interrupt.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/netdevice.h> | |
16 | #include <linux/phy.h> | |
4e3b0468 | 17 | #include <linux/ptp_clock_kernel.h> |
a556c76a | 18 | #include <linux/skbuff.h> |
639c1b26 | 19 | #include <linux/iopoll.h> |
a556c76a AB |
20 | #include <net/arp.h> |
21 | #include <net/netevent.h> | |
22 | #include <net/rtnetlink.h> | |
23 | #include <net/switchdev.h> | |
24 | ||
25 | #include "ocelot.h" | |
b5962294 | 26 | #include "ocelot_ace.h" |
a556c76a | 27 | |
639c1b26 SH |
28 | #define TABLE_UPDATE_SLEEP_US 10 |
29 | #define TABLE_UPDATE_TIMEOUT_US 100000 | |
30 | ||
a556c76a AB |
31 | /* MAC table entry types. |
32 | * ENTRYTYPE_NORMAL is subject to aging. | |
33 | * ENTRYTYPE_LOCKED is not subject to aging. | |
34 | * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast. | |
35 | * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast. | |
36 | */ | |
37 | enum macaccess_entry_type { | |
38 | ENTRYTYPE_NORMAL = 0, | |
39 | ENTRYTYPE_LOCKED, | |
40 | ENTRYTYPE_MACv4, | |
41 | ENTRYTYPE_MACv6, | |
42 | }; | |
43 | ||
44 | struct ocelot_mact_entry { | |
45 | u8 mac[ETH_ALEN]; | |
46 | u16 vid; | |
47 | enum macaccess_entry_type type; | |
48 | }; | |
49 | ||
639c1b26 | 50 | static inline u32 ocelot_mact_read_macaccess(struct ocelot *ocelot) |
a556c76a | 51 | { |
639c1b26 SH |
52 | return ocelot_read(ocelot, ANA_TABLES_MACACCESS); |
53 | } | |
a556c76a | 54 | |
639c1b26 SH |
55 | static inline int ocelot_mact_wait_for_completion(struct ocelot *ocelot) |
56 | { | |
57 | u32 val; | |
a556c76a | 58 | |
639c1b26 SH |
59 | return readx_poll_timeout(ocelot_mact_read_macaccess, |
60 | ocelot, val, | |
61 | (val & ANA_TABLES_MACACCESS_MAC_TABLE_CMD_M) == | |
62 | MACACCESS_CMD_IDLE, | |
63 | TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US); | |
a556c76a AB |
64 | } |
65 | ||
66 | static void ocelot_mact_select(struct ocelot *ocelot, | |
67 | const unsigned char mac[ETH_ALEN], | |
68 | unsigned int vid) | |
69 | { | |
70 | u32 macl = 0, mach = 0; | |
71 | ||
72 | /* Set the MAC address to handle and the vlan associated in a format | |
73 | * understood by the hardware. | |
74 | */ | |
75 | mach |= vid << 16; | |
76 | mach |= mac[0] << 8; | |
77 | mach |= mac[1] << 0; | |
78 | macl |= mac[2] << 24; | |
79 | macl |= mac[3] << 16; | |
80 | macl |= mac[4] << 8; | |
81 | macl |= mac[5] << 0; | |
82 | ||
83 | ocelot_write(ocelot, macl, ANA_TABLES_MACLDATA); | |
84 | ocelot_write(ocelot, mach, ANA_TABLES_MACHDATA); | |
85 | ||
86 | } | |
87 | ||
88 | static int ocelot_mact_learn(struct ocelot *ocelot, int port, | |
89 | const unsigned char mac[ETH_ALEN], | |
90 | unsigned int vid, | |
91 | enum macaccess_entry_type type) | |
92 | { | |
93 | ocelot_mact_select(ocelot, mac, vid); | |
94 | ||
95 | /* Issue a write command */ | |
96 | ocelot_write(ocelot, ANA_TABLES_MACACCESS_VALID | | |
97 | ANA_TABLES_MACACCESS_DEST_IDX(port) | | |
98 | ANA_TABLES_MACACCESS_ENTRYTYPE(type) | | |
99 | ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_LEARN), | |
100 | ANA_TABLES_MACACCESS); | |
101 | ||
102 | return ocelot_mact_wait_for_completion(ocelot); | |
103 | } | |
104 | ||
105 | static int ocelot_mact_forget(struct ocelot *ocelot, | |
106 | const unsigned char mac[ETH_ALEN], | |
107 | unsigned int vid) | |
108 | { | |
109 | ocelot_mact_select(ocelot, mac, vid); | |
110 | ||
111 | /* Issue a forget command */ | |
112 | ocelot_write(ocelot, | |
113 | ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_FORGET), | |
114 | ANA_TABLES_MACACCESS); | |
115 | ||
116 | return ocelot_mact_wait_for_completion(ocelot); | |
117 | } | |
118 | ||
119 | static void ocelot_mact_init(struct ocelot *ocelot) | |
120 | { | |
121 | /* Configure the learning mode entries attributes: | |
122 | * - Do not copy the frame to the CPU extraction queues. | |
123 | * - Use the vlan and mac_cpoy for dmac lookup. | |
124 | */ | |
125 | ocelot_rmw(ocelot, 0, | |
126 | ANA_AGENCTRL_LEARN_CPU_COPY | ANA_AGENCTRL_IGNORE_DMAC_FLAGS | |
127 | | ANA_AGENCTRL_LEARN_FWD_KILL | |
128 | | ANA_AGENCTRL_LEARN_IGNORE_VLAN, | |
129 | ANA_AGENCTRL); | |
130 | ||
131 | /* Clear the MAC table */ | |
132 | ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS); | |
133 | } | |
134 | ||
f270dbfa | 135 | static void ocelot_vcap_enable(struct ocelot *ocelot, int port) |
b5962294 HV |
136 | { |
137 | ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA | | |
138 | ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa), | |
f270dbfa | 139 | ANA_PORT_VCAP_S2_CFG, port); |
b5962294 HV |
140 | } |
141 | ||
639c1b26 | 142 | static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot) |
a556c76a | 143 | { |
639c1b26 SH |
144 | return ocelot_read(ocelot, ANA_TABLES_VLANACCESS); |
145 | } | |
a556c76a | 146 | |
639c1b26 SH |
147 | static inline int ocelot_vlant_wait_for_completion(struct ocelot *ocelot) |
148 | { | |
149 | u32 val; | |
150 | ||
151 | return readx_poll_timeout(ocelot_vlant_read_vlanaccess, | |
152 | ocelot, | |
153 | val, | |
154 | (val & ANA_TABLES_VLANACCESS_VLAN_TBL_CMD_M) == | |
155 | ANA_TABLES_VLANACCESS_CMD_IDLE, | |
156 | TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US); | |
a556c76a AB |
157 | } |
158 | ||
7142529f AT |
159 | static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask) |
160 | { | |
161 | /* Select the VID to configure */ | |
162 | ocelot_write(ocelot, ANA_TABLES_VLANTIDX_V_INDEX(vid), | |
163 | ANA_TABLES_VLANTIDX); | |
164 | /* Set the vlan port members mask and issue a write command */ | |
165 | ocelot_write(ocelot, ANA_TABLES_VLANACCESS_VLAN_PORT_MASK(mask) | | |
166 | ANA_TABLES_VLANACCESS_CMD_WRITE, | |
167 | ANA_TABLES_VLANACCESS); | |
168 | ||
169 | return ocelot_vlant_wait_for_completion(ocelot); | |
170 | } | |
171 | ||
f270dbfa | 172 | static void ocelot_vlan_mode(struct ocelot *ocelot, int port, |
7142529f AT |
173 | netdev_features_t features) |
174 | { | |
7142529f AT |
175 | u32 val; |
176 | ||
177 | /* Filtering */ | |
178 | val = ocelot_read(ocelot, ANA_VLANMASK); | |
179 | if (features & NETIF_F_HW_VLAN_CTAG_FILTER) | |
f270dbfa | 180 | val |= BIT(port); |
7142529f | 181 | else |
f270dbfa | 182 | val &= ~BIT(port); |
7142529f AT |
183 | ocelot_write(ocelot, val, ANA_VLANMASK); |
184 | } | |
185 | ||
87b0f983 VO |
186 | static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port, |
187 | u16 vid) | |
7142529f | 188 | { |
97bb69e1 | 189 | struct ocelot_port *ocelot_port = ocelot->ports[port]; |
87b0f983 | 190 | u32 val = 0; |
7142529f | 191 | |
87b0f983 VO |
192 | if (ocelot_port->vid != vid) { |
193 | /* Always permit deleting the native VLAN (vid = 0) */ | |
194 | if (ocelot_port->vid && vid) { | |
195 | dev_err(ocelot->dev, | |
196 | "Port already has a native VLAN: %d\n", | |
197 | ocelot_port->vid); | |
198 | return -EBUSY; | |
199 | } | |
200 | ocelot_port->vid = vid; | |
201 | } | |
202 | ||
203 | ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid), | |
204 | REW_PORT_VLAN_CFG_PORT_VID_M, | |
205 | REW_PORT_VLAN_CFG, port); | |
7142529f | 206 | |
87b0f983 | 207 | if (ocelot_port->vlan_aware && !ocelot_port->vid) |
7142529f AT |
208 | /* If port is vlan-aware and tagged, drop untagged and priority |
209 | * tagged frames. | |
210 | */ | |
97bb69e1 VO |
211 | val = ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA | |
212 | ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | | |
213 | ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA; | |
97bb69e1 VO |
214 | ocelot_rmw_gix(ocelot, val, |
215 | ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA | | |
7142529f | 216 | ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | |
97bb69e1 VO |
217 | ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, |
218 | ANA_PORT_DROP_CFG, port); | |
7142529f | 219 | |
87b0f983 | 220 | if (ocelot_port->vlan_aware) { |
97bb69e1 | 221 | if (ocelot_port->vid) |
7142529f | 222 | /* Tag all frames except when VID == DEFAULT_VLAN */ |
87b0f983 | 223 | val = REW_TAG_CFG_TAG_CFG(1); |
7142529f AT |
224 | else |
225 | /* Tag all frames */ | |
87b0f983 | 226 | val = REW_TAG_CFG_TAG_CFG(3); |
97bb69e1 VO |
227 | } else { |
228 | /* Port tagging disabled. */ | |
229 | val = REW_TAG_CFG_TAG_CFG(0); | |
7142529f AT |
230 | } |
231 | ocelot_rmw_gix(ocelot, val, | |
7142529f | 232 | REW_TAG_CFG_TAG_CFG_M, |
97bb69e1 | 233 | REW_TAG_CFG, port); |
87b0f983 VO |
234 | |
235 | return 0; | |
97bb69e1 VO |
236 | } |
237 | ||
87b0f983 VO |
238 | void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, |
239 | bool vlan_aware) | |
97bb69e1 VO |
240 | { |
241 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
87b0f983 | 242 | u32 val; |
97bb69e1 | 243 | |
87b0f983 | 244 | ocelot_port->vlan_aware = vlan_aware; |
97bb69e1 | 245 | |
87b0f983 VO |
246 | if (vlan_aware) |
247 | val = ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | | |
248 | ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1); | |
249 | else | |
250 | val = 0; | |
251 | ocelot_rmw_gix(ocelot, val, | |
252 | ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | | |
253 | ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M, | |
254 | ANA_PORT_VLAN_CFG, port); | |
97bb69e1 | 255 | |
87b0f983 | 256 | ocelot_port_set_native_vlan(ocelot, port, ocelot_port->vid); |
97bb69e1 | 257 | } |
87b0f983 | 258 | EXPORT_SYMBOL(ocelot_port_vlan_filtering); |
97bb69e1 VO |
259 | |
260 | /* Default vlan to clasify for untagged frames (may be zero) */ | |
261 | static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid) | |
262 | { | |
263 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
264 | ||
265 | ocelot_rmw_gix(ocelot, | |
266 | ANA_PORT_VLAN_CFG_VLAN_VID(pvid), | |
267 | ANA_PORT_VLAN_CFG_VLAN_VID_M, | |
268 | ANA_PORT_VLAN_CFG, port); | |
269 | ||
270 | ocelot_port->pvid = pvid; | |
7142529f AT |
271 | } |
272 | ||
5e256365 VO |
273 | int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, |
274 | bool untagged) | |
7142529f | 275 | { |
7142529f AT |
276 | int ret; |
277 | ||
7142529f | 278 | /* Make the port a member of the VLAN */ |
97bb69e1 | 279 | ocelot->vlan_mask[vid] |= BIT(port); |
7142529f AT |
280 | ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); |
281 | if (ret) | |
282 | return ret; | |
283 | ||
284 | /* Default ingress vlan classification */ | |
285 | if (pvid) | |
97bb69e1 | 286 | ocelot_port_set_pvid(ocelot, port, vid); |
7142529f AT |
287 | |
288 | /* Untagged egress vlan clasification */ | |
97bb69e1 VO |
289 | if (untagged) { |
290 | ret = ocelot_port_set_native_vlan(ocelot, port, vid); | |
291 | if (ret) | |
292 | return ret; | |
b9cd75e6 | 293 | } |
7142529f | 294 | |
7142529f AT |
295 | return 0; |
296 | } | |
5e256365 | 297 | EXPORT_SYMBOL(ocelot_vlan_add); |
7142529f | 298 | |
9855934c VO |
299 | static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, |
300 | bool untagged) | |
7142529f | 301 | { |
004d44f6 VO |
302 | struct ocelot_port_private *priv = netdev_priv(dev); |
303 | struct ocelot_port *ocelot_port = &priv->port; | |
97bb69e1 | 304 | struct ocelot *ocelot = ocelot_port->ocelot; |
004d44f6 | 305 | int port = priv->chip_port; |
7142529f AT |
306 | int ret; |
307 | ||
9855934c VO |
308 | ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged); |
309 | if (ret) | |
310 | return ret; | |
7142529f | 311 | |
9855934c VO |
312 | /* Add the port MAC address to with the right VLAN information */ |
313 | ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid, | |
314 | ENTRYTYPE_LOCKED); | |
315 | ||
316 | return 0; | |
317 | } | |
318 | ||
5e256365 | 319 | int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) |
9855934c VO |
320 | { |
321 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
322 | int ret; | |
7142529f AT |
323 | |
324 | /* Stop the port from being a member of the vlan */ | |
97bb69e1 | 325 | ocelot->vlan_mask[vid] &= ~BIT(port); |
7142529f AT |
326 | ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); |
327 | if (ret) | |
328 | return ret; | |
329 | ||
330 | /* Ingress */ | |
97bb69e1 VO |
331 | if (ocelot_port->pvid == vid) |
332 | ocelot_port_set_pvid(ocelot, port, 0); | |
7142529f AT |
333 | |
334 | /* Egress */ | |
97bb69e1 VO |
335 | if (ocelot_port->vid == vid) |
336 | ocelot_port_set_native_vlan(ocelot, port, 0); | |
7142529f AT |
337 | |
338 | return 0; | |
339 | } | |
5e256365 | 340 | EXPORT_SYMBOL(ocelot_vlan_del); |
7142529f | 341 | |
9855934c VO |
342 | static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) |
343 | { | |
004d44f6 VO |
344 | struct ocelot_port_private *priv = netdev_priv(dev); |
345 | struct ocelot *ocelot = priv->port.ocelot; | |
346 | int port = priv->chip_port; | |
9855934c VO |
347 | int ret; |
348 | ||
349 | /* 8021q removes VID 0 on module unload for all interfaces | |
350 | * with VLAN filtering feature. We need to keep it to receive | |
351 | * untagged traffic. | |
352 | */ | |
353 | if (vid == 0) | |
354 | return 0; | |
355 | ||
356 | ret = ocelot_vlan_del(ocelot, port, vid); | |
357 | if (ret) | |
358 | return ret; | |
359 | ||
360 | /* Del the port MAC address to with the right VLAN information */ | |
361 | ocelot_mact_forget(ocelot, dev->dev_addr, vid); | |
362 | ||
363 | return 0; | |
364 | } | |
365 | ||
a556c76a AB |
366 | static void ocelot_vlan_init(struct ocelot *ocelot) |
367 | { | |
7142529f AT |
368 | u16 port, vid; |
369 | ||
a556c76a AB |
370 | /* Clear VLAN table, by default all ports are members of all VLANs */ |
371 | ocelot_write(ocelot, ANA_TABLES_VLANACCESS_CMD_INIT, | |
372 | ANA_TABLES_VLANACCESS); | |
373 | ocelot_vlant_wait_for_completion(ocelot); | |
7142529f AT |
374 | |
375 | /* Configure the port VLAN memberships */ | |
376 | for (vid = 1; vid < VLAN_N_VID; vid++) { | |
377 | ocelot->vlan_mask[vid] = 0; | |
378 | ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); | |
379 | } | |
380 | ||
381 | /* Because VLAN filtering is enabled, we need VID 0 to get untagged | |
382 | * traffic. It is added automatically if 8021q module is loaded, but | |
383 | * we can't rely on it since module may be not loaded. | |
384 | */ | |
385 | ocelot->vlan_mask[0] = GENMASK(ocelot->num_phys_ports - 1, 0); | |
386 | ocelot_vlant_set_mask(ocelot, 0, ocelot->vlan_mask[0]); | |
387 | ||
7142529f AT |
388 | /* Set vlan ingress filter mask to all ports but the CPU port by |
389 | * default. | |
390 | */ | |
714d0ffa VO |
391 | ocelot_write(ocelot, GENMASK(ocelot->num_phys_ports - 1, 0), |
392 | ANA_VLANMASK); | |
7142529f AT |
393 | |
394 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
395 | ocelot_write_gix(ocelot, 0, REW_PORT_VLAN_CFG, port); | |
396 | ocelot_write_gix(ocelot, 0, REW_TAG_CFG, port); | |
397 | } | |
a556c76a AB |
398 | } |
399 | ||
400 | /* Watermark encode | |
401 | * Bit 8: Unit; 0:1, 1:16 | |
402 | * Bit 7-0: Value to be multiplied with unit | |
403 | */ | |
404 | static u16 ocelot_wm_enc(u16 value) | |
405 | { | |
406 | if (value >= BIT(8)) | |
407 | return BIT(8) | (value / 16); | |
408 | ||
409 | return value; | |
410 | } | |
411 | ||
5e256365 VO |
412 | void ocelot_adjust_link(struct ocelot *ocelot, int port, |
413 | struct phy_device *phydev) | |
a556c76a | 414 | { |
26f4dbab | 415 | struct ocelot_port *ocelot_port = ocelot->ports[port]; |
5bc9d2e6 | 416 | int speed, mode = 0; |
a556c76a | 417 | |
26f4dbab | 418 | switch (phydev->speed) { |
a556c76a AB |
419 | case SPEED_10: |
420 | speed = OCELOT_SPEED_10; | |
421 | break; | |
422 | case SPEED_100: | |
423 | speed = OCELOT_SPEED_100; | |
424 | break; | |
425 | case SPEED_1000: | |
426 | speed = OCELOT_SPEED_1000; | |
427 | mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; | |
428 | break; | |
429 | case SPEED_2500: | |
430 | speed = OCELOT_SPEED_2500; | |
431 | mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; | |
432 | break; | |
433 | default: | |
26f4dbab VO |
434 | dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n", |
435 | port, phydev->speed); | |
a556c76a AB |
436 | return; |
437 | } | |
438 | ||
26f4dbab | 439 | phy_print_status(phydev); |
a556c76a | 440 | |
26f4dbab | 441 | if (!phydev->link) |
a556c76a AB |
442 | return; |
443 | ||
444 | /* Only full duplex supported for now */ | |
004d44f6 | 445 | ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA | |
a556c76a AB |
446 | mode, DEV_MAC_MODE_CFG); |
447 | ||
1ba8f656 VO |
448 | /* Disable HDX fast control */ |
449 | ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS, | |
450 | DEV_PORT_MISC); | |
451 | ||
452 | /* SGMII only for now */ | |
453 | ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA, | |
454 | PCS1G_MODE_CFG); | |
455 | ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG); | |
456 | ||
457 | /* Enable PCS */ | |
458 | ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG); | |
459 | ||
460 | /* No aneg on SGMII */ | |
461 | ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG); | |
462 | ||
463 | /* No loopback */ | |
464 | ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG); | |
a556c76a | 465 | |
a556c76a | 466 | /* Enable MAC module */ |
004d44f6 | 467 | ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | |
a556c76a AB |
468 | DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); |
469 | ||
470 | /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of | |
471 | * reset */ | |
004d44f6 | 472 | ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed), |
a556c76a AB |
473 | DEV_CLOCK_CFG); |
474 | ||
a556c76a AB |
475 | /* No PFC */ |
476 | ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed), | |
004d44f6 | 477 | ANA_PFC_PFC_CFG, port); |
a556c76a | 478 | |
a556c76a AB |
479 | /* Core: Enable port for frame transfer */ |
480 | ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | | |
481 | QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | | |
482 | QSYS_SWITCH_PORT_MODE_PORT_ENA, | |
004d44f6 | 483 | QSYS_SWITCH_PORT_MODE, port); |
a556c76a AB |
484 | |
485 | /* Flow control */ | |
486 | ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | | |
487 | SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA | | |
488 | SYS_MAC_FC_CFG_ZERO_PAUSE_ENA | | |
489 | SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | | |
490 | SYS_MAC_FC_CFG_FC_LINK_SPEED(speed), | |
004d44f6 VO |
491 | SYS_MAC_FC_CFG, port); |
492 | ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); | |
a556c76a | 493 | } |
5e256365 | 494 | EXPORT_SYMBOL(ocelot_adjust_link); |
a556c76a | 495 | |
26f4dbab VO |
496 | static void ocelot_port_adjust_link(struct net_device *dev) |
497 | { | |
498 | struct ocelot_port_private *priv = netdev_priv(dev); | |
499 | struct ocelot *ocelot = priv->port.ocelot; | |
500 | int port = priv->chip_port; | |
501 | ||
502 | ocelot_adjust_link(ocelot, port, dev->phydev); | |
503 | } | |
504 | ||
5e256365 VO |
505 | void ocelot_port_enable(struct ocelot *ocelot, int port, |
506 | struct phy_device *phy) | |
a556c76a | 507 | { |
a556c76a AB |
508 | /* Enable receiving frames on the port, and activate auto-learning of |
509 | * MAC addresses. | |
510 | */ | |
511 | ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | | |
512 | ANA_PORT_PORT_CFG_RECV_ENA | | |
004d44f6 VO |
513 | ANA_PORT_PORT_CFG_PORTID_VAL(port), |
514 | ANA_PORT_PORT_CFG, port); | |
889b8950 | 515 | } |
5e256365 | 516 | EXPORT_SYMBOL(ocelot_port_enable); |
889b8950 VO |
517 | |
518 | static int ocelot_port_open(struct net_device *dev) | |
519 | { | |
520 | struct ocelot_port_private *priv = netdev_priv(dev); | |
ee50d07c VO |
521 | struct ocelot_port *ocelot_port = &priv->port; |
522 | struct ocelot *ocelot = ocelot_port->ocelot; | |
889b8950 VO |
523 | int port = priv->chip_port; |
524 | int err; | |
a556c76a | 525 | |
004d44f6 VO |
526 | if (priv->serdes) { |
527 | err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET, | |
ee50d07c | 528 | ocelot_port->phy_mode); |
71e32a20 QS |
529 | if (err) { |
530 | netdev_err(dev, "Could not set mode of SerDes\n"); | |
531 | return err; | |
532 | } | |
533 | } | |
534 | ||
004d44f6 | 535 | err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link, |
ee50d07c | 536 | ocelot_port->phy_mode); |
a556c76a AB |
537 | if (err) { |
538 | netdev_err(dev, "Could not attach to PHY\n"); | |
539 | return err; | |
540 | } | |
541 | ||
004d44f6 | 542 | dev->phydev = priv->phy; |
a556c76a | 543 | |
004d44f6 VO |
544 | phy_attached_info(priv->phy); |
545 | phy_start(priv->phy); | |
889b8950 VO |
546 | |
547 | ocelot_port_enable(ocelot, port, priv->phy); | |
548 | ||
a556c76a AB |
549 | return 0; |
550 | } | |
551 | ||
5e256365 | 552 | void ocelot_port_disable(struct ocelot *ocelot, int port) |
889b8950 VO |
553 | { |
554 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
555 | ||
556 | ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); | |
557 | ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, | |
558 | QSYS_SWITCH_PORT_MODE, port); | |
559 | } | |
5e256365 | 560 | EXPORT_SYMBOL(ocelot_port_disable); |
889b8950 | 561 | |
a556c76a AB |
562 | static int ocelot_port_stop(struct net_device *dev) |
563 | { | |
004d44f6 | 564 | struct ocelot_port_private *priv = netdev_priv(dev); |
889b8950 VO |
565 | struct ocelot *ocelot = priv->port.ocelot; |
566 | int port = priv->chip_port; | |
a556c76a | 567 | |
004d44f6 | 568 | phy_disconnect(priv->phy); |
a556c76a AB |
569 | |
570 | dev->phydev = NULL; | |
571 | ||
889b8950 VO |
572 | ocelot_port_disable(ocelot, port); |
573 | ||
a556c76a AB |
574 | return 0; |
575 | } | |
576 | ||
577 | /* Generate the IFH for frame injection | |
578 | * | |
579 | * The IFH is a 128bit-value | |
580 | * bit 127: bypass the analyzer processing | |
581 | * bit 56-67: destination mask | |
582 | * bit 28-29: pop_cnt: 3 disables all rewriting of the frame | |
583 | * bit 20-27: cpu extraction queue mask | |
584 | * bit 16: tag type 0: C-tag, 1: S-tag | |
585 | * bit 0-11: VID | |
586 | */ | |
587 | static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info) | |
588 | { | |
4e3b0468 | 589 | ifh[0] = IFH_INJ_BYPASS | ((0x1ff & info->rew_op) << 21); |
08d02364 | 590 | ifh[1] = (0xf00 & info->port) >> 8; |
a556c76a | 591 | ifh[2] = (0xff & info->port) << 24; |
08d02364 | 592 | ifh[3] = (info->tag_type << 16) | info->vid; |
a556c76a AB |
593 | |
594 | return 0; | |
595 | } | |
596 | ||
400928bf YL |
597 | int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port, |
598 | struct sk_buff *skb) | |
599 | { | |
600 | struct skb_shared_info *shinfo = skb_shinfo(skb); | |
601 | struct ocelot *ocelot = ocelot_port->ocelot; | |
602 | ||
603 | if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP && | |
604 | ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { | |
400928bf | 605 | shinfo->tx_flags |= SKBTX_IN_PROGRESS; |
b049da13 YL |
606 | /* Store timestamp ID in cb[0] of sk_buff */ |
607 | skb->cb[0] = ocelot_port->ts_id % 4; | |
608 | skb_queue_tail(&ocelot_port->tx_skbs, skb); | |
400928bf YL |
609 | return 0; |
610 | } | |
611 | return -ENODATA; | |
612 | } | |
613 | EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb); | |
614 | ||
a556c76a AB |
615 | static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) |
616 | { | |
004d44f6 | 617 | struct ocelot_port_private *priv = netdev_priv(dev); |
4e3b0468 | 618 | struct skb_shared_info *shinfo = skb_shinfo(skb); |
004d44f6 VO |
619 | struct ocelot_port *ocelot_port = &priv->port; |
620 | struct ocelot *ocelot = ocelot_port->ocelot; | |
f24711fd | 621 | u32 val, ifh[OCELOT_TAG_LEN / 4]; |
a556c76a AB |
622 | struct frame_info info = {}; |
623 | u8 grp = 0; /* Send everything on CPU group 0 */ | |
624 | unsigned int i, count, last; | |
004d44f6 | 625 | int port = priv->chip_port; |
a556c76a AB |
626 | |
627 | val = ocelot_read(ocelot, QS_INJ_STATUS); | |
628 | if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) || | |
629 | (val & QS_INJ_STATUS_WMARK_REACHED(BIT(grp)))) | |
630 | return NETDEV_TX_BUSY; | |
631 | ||
632 | ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) | | |
633 | QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp); | |
634 | ||
004d44f6 | 635 | info.port = BIT(port); |
08d02364 AT |
636 | info.tag_type = IFH_TAG_TYPE_C; |
637 | info.vid = skb_vlan_tag_get(skb); | |
4e3b0468 AT |
638 | |
639 | /* Check if timestamping is needed */ | |
640 | if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) { | |
004d44f6 VO |
641 | info.rew_op = ocelot_port->ptp_cmd; |
642 | if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) | |
643 | info.rew_op |= (ocelot_port->ts_id % 4) << 3; | |
4e3b0468 AT |
644 | } |
645 | ||
a556c76a AB |
646 | ocelot_gen_ifh(ifh, &info); |
647 | ||
f24711fd | 648 | for (i = 0; i < OCELOT_TAG_LEN / 4; i++) |
c2cd650b AT |
649 | ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]), |
650 | QS_INJ_WR, grp); | |
a556c76a AB |
651 | |
652 | count = (skb->len + 3) / 4; | |
653 | last = skb->len % 4; | |
654 | for (i = 0; i < count; i++) { | |
655 | ocelot_write_rix(ocelot, ((u32 *)skb->data)[i], QS_INJ_WR, grp); | |
656 | } | |
657 | ||
658 | /* Add padding */ | |
659 | while (i < (OCELOT_BUFFER_CELL_SZ / 4)) { | |
660 | ocelot_write_rix(ocelot, 0, QS_INJ_WR, grp); | |
661 | i++; | |
662 | } | |
663 | ||
664 | /* Indicate EOF and valid bytes in last word */ | |
665 | ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) | | |
666 | QS_INJ_CTRL_VLD_BYTES(skb->len < OCELOT_BUFFER_CELL_SZ ? 0 : last) | | |
667 | QS_INJ_CTRL_EOF, | |
668 | QS_INJ_CTRL, grp); | |
669 | ||
670 | /* Add dummy CRC */ | |
671 | ocelot_write_rix(ocelot, 0, QS_INJ_WR, grp); | |
672 | skb_tx_timestamp(skb); | |
673 | ||
674 | dev->stats.tx_packets++; | |
675 | dev->stats.tx_bytes += skb->len; | |
a556c76a | 676 | |
400928bf | 677 | if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) { |
004d44f6 | 678 | ocelot_port->ts_id++; |
4e3b0468 AT |
679 | return NETDEV_TX_OK; |
680 | } | |
681 | ||
4e3b0468 | 682 | dev_kfree_skb_any(skb); |
a556c76a AB |
683 | return NETDEV_TX_OK; |
684 | } | |
685 | ||
e23a7b3e YL |
686 | static void ocelot_get_hwtimestamp(struct ocelot *ocelot, |
687 | struct timespec64 *ts) | |
4e3b0468 AT |
688 | { |
689 | unsigned long flags; | |
690 | u32 val; | |
691 | ||
692 | spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); | |
693 | ||
694 | /* Read current PTP time to get seconds */ | |
695 | val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); | |
696 | ||
697 | val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); | |
698 | val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE); | |
699 | ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); | |
700 | ts->tv_sec = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); | |
701 | ||
702 | /* Read packet HW timestamp from FIFO */ | |
703 | val = ocelot_read(ocelot, SYS_PTP_TXSTAMP); | |
704 | ts->tv_nsec = SYS_PTP_TXSTAMP_PTP_TXSTAMP(val); | |
705 | ||
706 | /* Sec has incremented since the ts was registered */ | |
707 | if ((ts->tv_sec & 0x1) != !!(val & SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC)) | |
708 | ts->tv_sec--; | |
709 | ||
710 | spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); | |
711 | } | |
e23a7b3e YL |
712 | |
713 | void ocelot_get_txtstamp(struct ocelot *ocelot) | |
714 | { | |
715 | int budget = OCELOT_PTP_QUEUE_SZ; | |
716 | ||
717 | while (budget--) { | |
b049da13 | 718 | struct sk_buff *skb, *skb_tmp, *skb_match = NULL; |
e23a7b3e | 719 | struct skb_shared_hwtstamps shhwtstamps; |
e23a7b3e YL |
720 | struct ocelot_port *port; |
721 | struct timespec64 ts; | |
b049da13 | 722 | unsigned long flags; |
e23a7b3e YL |
723 | u32 val, id, txport; |
724 | ||
725 | val = ocelot_read(ocelot, SYS_PTP_STATUS); | |
726 | ||
727 | /* Check if a timestamp can be retrieved */ | |
728 | if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD)) | |
729 | break; | |
730 | ||
731 | WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL); | |
732 | ||
733 | /* Retrieve the ts ID and Tx port */ | |
734 | id = SYS_PTP_STATUS_PTP_MESS_ID_X(val); | |
735 | txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val); | |
736 | ||
737 | /* Retrieve its associated skb */ | |
738 | port = ocelot->ports[txport]; | |
739 | ||
b049da13 | 740 | spin_lock_irqsave(&port->tx_skbs.lock, flags); |
e23a7b3e | 741 | |
b049da13 YL |
742 | skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { |
743 | if (skb->cb[0] != id) | |
744 | continue; | |
745 | __skb_unlink(skb, &port->tx_skbs); | |
746 | skb_match = skb; | |
fc62c094 | 747 | break; |
e23a7b3e YL |
748 | } |
749 | ||
b049da13 YL |
750 | spin_unlock_irqrestore(&port->tx_skbs.lock, flags); |
751 | ||
e23a7b3e YL |
752 | /* Next ts */ |
753 | ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); | |
754 | ||
b049da13 | 755 | if (unlikely(!skb_match)) |
e23a7b3e YL |
756 | continue; |
757 | ||
758 | /* Get the h/w timestamp */ | |
759 | ocelot_get_hwtimestamp(ocelot, &ts); | |
760 | ||
761 | /* Set the timestamp into the skb */ | |
762 | memset(&shhwtstamps, 0, sizeof(shhwtstamps)); | |
763 | shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); | |
b049da13 | 764 | skb_tstamp_tx(skb_match, &shhwtstamps); |
e23a7b3e | 765 | |
b049da13 | 766 | dev_kfree_skb_any(skb_match); |
e23a7b3e YL |
767 | } |
768 | } | |
769 | EXPORT_SYMBOL(ocelot_get_txtstamp); | |
4e3b0468 | 770 | |
40a1578d | 771 | static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr) |
a556c76a | 772 | { |
004d44f6 VO |
773 | struct ocelot_port_private *priv = netdev_priv(dev); |
774 | struct ocelot_port *ocelot_port = &priv->port; | |
775 | struct ocelot *ocelot = ocelot_port->ocelot; | |
a556c76a | 776 | |
004d44f6 | 777 | return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid); |
a556c76a AB |
778 | } |
779 | ||
40a1578d | 780 | static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr) |
a556c76a | 781 | { |
004d44f6 VO |
782 | struct ocelot_port_private *priv = netdev_priv(dev); |
783 | struct ocelot_port *ocelot_port = &priv->port; | |
784 | struct ocelot *ocelot = ocelot_port->ocelot; | |
a556c76a | 785 | |
004d44f6 | 786 | return ocelot_mact_learn(ocelot, PGID_CPU, addr, ocelot_port->pvid, |
40a1578d | 787 | ENTRYTYPE_LOCKED); |
a556c76a AB |
788 | } |
789 | ||
790 | static void ocelot_set_rx_mode(struct net_device *dev) | |
791 | { | |
004d44f6 VO |
792 | struct ocelot_port_private *priv = netdev_priv(dev); |
793 | struct ocelot *ocelot = priv->port.ocelot; | |
a556c76a | 794 | u32 val; |
004d44f6 | 795 | int i; |
a556c76a AB |
796 | |
797 | /* This doesn't handle promiscuous mode because the bridge core is | |
798 | * setting IFF_PROMISC on all slave interfaces and all frames would be | |
799 | * forwarded to the CPU port. | |
800 | */ | |
801 | val = GENMASK(ocelot->num_phys_ports - 1, 0); | |
802 | for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) | |
803 | ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i); | |
804 | ||
40a1578d | 805 | __dev_mc_sync(dev, ocelot_mc_sync, ocelot_mc_unsync); |
a556c76a AB |
806 | } |
807 | ||
808 | static int ocelot_port_get_phys_port_name(struct net_device *dev, | |
809 | char *buf, size_t len) | |
810 | { | |
004d44f6 VO |
811 | struct ocelot_port_private *priv = netdev_priv(dev); |
812 | int port = priv->chip_port; | |
a556c76a AB |
813 | int ret; |
814 | ||
004d44f6 | 815 | ret = snprintf(buf, len, "p%d", port); |
a556c76a AB |
816 | if (ret >= len) |
817 | return -EINVAL; | |
818 | ||
819 | return 0; | |
820 | } | |
821 | ||
822 | static int ocelot_port_set_mac_address(struct net_device *dev, void *p) | |
823 | { | |
004d44f6 VO |
824 | struct ocelot_port_private *priv = netdev_priv(dev); |
825 | struct ocelot_port *ocelot_port = &priv->port; | |
826 | struct ocelot *ocelot = ocelot_port->ocelot; | |
a556c76a AB |
827 | const struct sockaddr *addr = p; |
828 | ||
829 | /* Learn the new net device MAC address in the mac table. */ | |
004d44f6 | 830 | ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, ocelot_port->pvid, |
a556c76a AB |
831 | ENTRYTYPE_LOCKED); |
832 | /* Then forget the previous one. */ | |
004d44f6 | 833 | ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid); |
a556c76a AB |
834 | |
835 | ether_addr_copy(dev->dev_addr, addr->sa_data); | |
836 | return 0; | |
837 | } | |
838 | ||
839 | static void ocelot_get_stats64(struct net_device *dev, | |
840 | struct rtnl_link_stats64 *stats) | |
841 | { | |
004d44f6 VO |
842 | struct ocelot_port_private *priv = netdev_priv(dev); |
843 | struct ocelot *ocelot = priv->port.ocelot; | |
844 | int port = priv->chip_port; | |
a556c76a AB |
845 | |
846 | /* Configure the port to read the stats from */ | |
004d44f6 | 847 | ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), |
a556c76a AB |
848 | SYS_STAT_CFG); |
849 | ||
850 | /* Get Rx stats */ | |
851 | stats->rx_bytes = ocelot_read(ocelot, SYS_COUNT_RX_OCTETS); | |
852 | stats->rx_packets = ocelot_read(ocelot, SYS_COUNT_RX_SHORTS) + | |
853 | ocelot_read(ocelot, SYS_COUNT_RX_FRAGMENTS) + | |
854 | ocelot_read(ocelot, SYS_COUNT_RX_JABBERS) + | |
855 | ocelot_read(ocelot, SYS_COUNT_RX_LONGS) + | |
856 | ocelot_read(ocelot, SYS_COUNT_RX_64) + | |
857 | ocelot_read(ocelot, SYS_COUNT_RX_65_127) + | |
858 | ocelot_read(ocelot, SYS_COUNT_RX_128_255) + | |
859 | ocelot_read(ocelot, SYS_COUNT_RX_256_1023) + | |
860 | ocelot_read(ocelot, SYS_COUNT_RX_1024_1526) + | |
861 | ocelot_read(ocelot, SYS_COUNT_RX_1527_MAX); | |
862 | stats->multicast = ocelot_read(ocelot, SYS_COUNT_RX_MULTICAST); | |
863 | stats->rx_dropped = dev->stats.rx_dropped; | |
864 | ||
865 | /* Get Tx stats */ | |
866 | stats->tx_bytes = ocelot_read(ocelot, SYS_COUNT_TX_OCTETS); | |
867 | stats->tx_packets = ocelot_read(ocelot, SYS_COUNT_TX_64) + | |
868 | ocelot_read(ocelot, SYS_COUNT_TX_65_127) + | |
869 | ocelot_read(ocelot, SYS_COUNT_TX_128_511) + | |
870 | ocelot_read(ocelot, SYS_COUNT_TX_512_1023) + | |
871 | ocelot_read(ocelot, SYS_COUNT_TX_1024_1526) + | |
872 | ocelot_read(ocelot, SYS_COUNT_TX_1527_MAX); | |
873 | stats->tx_dropped = ocelot_read(ocelot, SYS_COUNT_TX_DROPS) + | |
874 | ocelot_read(ocelot, SYS_COUNT_TX_AGING); | |
875 | stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION); | |
876 | } | |
877 | ||
5e256365 | 878 | int ocelot_fdb_add(struct ocelot *ocelot, int port, |
87b0f983 | 879 | const unsigned char *addr, u16 vid) |
a556c76a | 880 | { |
531ee1a6 | 881 | struct ocelot_port *ocelot_port = ocelot->ports[port]; |
a556c76a | 882 | |
7142529f | 883 | if (!vid) { |
87b0f983 | 884 | if (!ocelot_port->vlan_aware) |
7142529f AT |
885 | /* If the bridge is not VLAN aware and no VID was |
886 | * provided, set it to pvid to ensure the MAC entry | |
887 | * matches incoming untagged packets | |
888 | */ | |
531ee1a6 | 889 | vid = ocelot_port->pvid; |
7142529f AT |
890 | else |
891 | /* If the bridge is VLAN aware a VID must be provided as | |
892 | * otherwise the learnt entry wouldn't match any frame. | |
893 | */ | |
894 | return -EINVAL; | |
895 | } | |
896 | ||
531ee1a6 | 897 | return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED); |
a556c76a | 898 | } |
5e256365 | 899 | EXPORT_SYMBOL(ocelot_fdb_add); |
a556c76a | 900 | |
531ee1a6 VO |
901 | static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], |
902 | struct net_device *dev, | |
903 | const unsigned char *addr, | |
904 | u16 vid, u16 flags, | |
905 | struct netlink_ext_ack *extack) | |
a556c76a | 906 | { |
004d44f6 VO |
907 | struct ocelot_port_private *priv = netdev_priv(dev); |
908 | struct ocelot *ocelot = priv->port.ocelot; | |
909 | int port = priv->chip_port; | |
a556c76a | 910 | |
87b0f983 | 911 | return ocelot_fdb_add(ocelot, port, addr, vid); |
531ee1a6 VO |
912 | } |
913 | ||
5e256365 VO |
914 | int ocelot_fdb_del(struct ocelot *ocelot, int port, |
915 | const unsigned char *addr, u16 vid) | |
531ee1a6 | 916 | { |
a556c76a AB |
917 | return ocelot_mact_forget(ocelot, addr, vid); |
918 | } | |
5e256365 | 919 | EXPORT_SYMBOL(ocelot_fdb_del); |
a556c76a | 920 | |
531ee1a6 VO |
921 | static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], |
922 | struct net_device *dev, | |
923 | const unsigned char *addr, u16 vid) | |
924 | { | |
004d44f6 VO |
925 | struct ocelot_port_private *priv = netdev_priv(dev); |
926 | struct ocelot *ocelot = priv->port.ocelot; | |
927 | int port = priv->chip_port; | |
531ee1a6 | 928 | |
004d44f6 | 929 | return ocelot_fdb_del(ocelot, port, addr, vid); |
531ee1a6 VO |
930 | } |
931 | ||
a556c76a AB |
932 | struct ocelot_dump_ctx { |
933 | struct net_device *dev; | |
934 | struct sk_buff *skb; | |
935 | struct netlink_callback *cb; | |
936 | int idx; | |
937 | }; | |
938 | ||
531ee1a6 VO |
939 | static int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid, |
940 | bool is_static, void *data) | |
a556c76a | 941 | { |
531ee1a6 | 942 | struct ocelot_dump_ctx *dump = data; |
a556c76a AB |
943 | u32 portid = NETLINK_CB(dump->cb->skb).portid; |
944 | u32 seq = dump->cb->nlh->nlmsg_seq; | |
945 | struct nlmsghdr *nlh; | |
946 | struct ndmsg *ndm; | |
947 | ||
948 | if (dump->idx < dump->cb->args[2]) | |
949 | goto skip; | |
950 | ||
951 | nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, | |
952 | sizeof(*ndm), NLM_F_MULTI); | |
953 | if (!nlh) | |
954 | return -EMSGSIZE; | |
955 | ||
956 | ndm = nlmsg_data(nlh); | |
957 | ndm->ndm_family = AF_BRIDGE; | |
958 | ndm->ndm_pad1 = 0; | |
959 | ndm->ndm_pad2 = 0; | |
960 | ndm->ndm_flags = NTF_SELF; | |
961 | ndm->ndm_type = 0; | |
962 | ndm->ndm_ifindex = dump->dev->ifindex; | |
531ee1a6 | 963 | ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; |
a556c76a | 964 | |
531ee1a6 | 965 | if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) |
a556c76a AB |
966 | goto nla_put_failure; |
967 | ||
531ee1a6 | 968 | if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) |
a556c76a AB |
969 | goto nla_put_failure; |
970 | ||
971 | nlmsg_end(dump->skb, nlh); | |
972 | ||
973 | skip: | |
974 | dump->idx++; | |
975 | return 0; | |
976 | ||
977 | nla_put_failure: | |
978 | nlmsg_cancel(dump->skb, nlh); | |
979 | return -EMSGSIZE; | |
980 | } | |
981 | ||
531ee1a6 VO |
982 | static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col, |
983 | struct ocelot_mact_entry *entry) | |
a556c76a | 984 | { |
a556c76a | 985 | u32 val, dst, macl, mach; |
531ee1a6 | 986 | char mac[ETH_ALEN]; |
a556c76a AB |
987 | |
988 | /* Set row and column to read from */ | |
989 | ocelot_field_write(ocelot, ANA_TABLES_MACTINDX_M_INDEX, row); | |
990 | ocelot_field_write(ocelot, ANA_TABLES_MACTINDX_BUCKET, col); | |
991 | ||
992 | /* Issue a read command */ | |
993 | ocelot_write(ocelot, | |
994 | ANA_TABLES_MACACCESS_MAC_TABLE_CMD(MACACCESS_CMD_READ), | |
995 | ANA_TABLES_MACACCESS); | |
996 | ||
997 | if (ocelot_mact_wait_for_completion(ocelot)) | |
998 | return -ETIMEDOUT; | |
999 | ||
1000 | /* Read the entry flags */ | |
1001 | val = ocelot_read(ocelot, ANA_TABLES_MACACCESS); | |
1002 | if (!(val & ANA_TABLES_MACACCESS_VALID)) | |
1003 | return -EINVAL; | |
1004 | ||
1005 | /* If the entry read has another port configured as its destination, | |
1006 | * do not report it. | |
1007 | */ | |
1008 | dst = (val & ANA_TABLES_MACACCESS_DEST_IDX_M) >> 3; | |
531ee1a6 | 1009 | if (dst != port) |
a556c76a AB |
1010 | return -EINVAL; |
1011 | ||
1012 | /* Get the entry's MAC address and VLAN id */ | |
1013 | macl = ocelot_read(ocelot, ANA_TABLES_MACLDATA); | |
1014 | mach = ocelot_read(ocelot, ANA_TABLES_MACHDATA); | |
1015 | ||
1016 | mac[0] = (mach >> 8) & 0xff; | |
1017 | mac[1] = (mach >> 0) & 0xff; | |
1018 | mac[2] = (macl >> 24) & 0xff; | |
1019 | mac[3] = (macl >> 16) & 0xff; | |
1020 | mac[4] = (macl >> 8) & 0xff; | |
1021 | mac[5] = (macl >> 0) & 0xff; | |
1022 | ||
1023 | entry->vid = (mach >> 16) & 0xfff; | |
1024 | ether_addr_copy(entry->mac, mac); | |
1025 | ||
1026 | return 0; | |
1027 | } | |
1028 | ||
5e256365 VO |
1029 | int ocelot_fdb_dump(struct ocelot *ocelot, int port, |
1030 | dsa_fdb_dump_cb_t *cb, void *data) | |
a556c76a | 1031 | { |
531ee1a6 | 1032 | int i, j; |
a556c76a | 1033 | |
21ce7f3e VO |
1034 | /* Loop through all the mac tables entries. */ |
1035 | for (i = 0; i < ocelot->num_mact_rows; i++) { | |
a556c76a | 1036 | for (j = 0; j < 4; j++) { |
531ee1a6 VO |
1037 | struct ocelot_mact_entry entry; |
1038 | bool is_static; | |
1039 | int ret; | |
1040 | ||
1041 | ret = ocelot_mact_read(ocelot, port, i, j, &entry); | |
a556c76a AB |
1042 | /* If the entry is invalid (wrong port, invalid...), |
1043 | * skip it. | |
1044 | */ | |
1045 | if (ret == -EINVAL) | |
1046 | continue; | |
1047 | else if (ret) | |
531ee1a6 VO |
1048 | return ret; |
1049 | ||
1050 | is_static = (entry.type == ENTRYTYPE_LOCKED); | |
a556c76a | 1051 | |
531ee1a6 | 1052 | ret = cb(entry.mac, entry.vid, is_static, data); |
a556c76a | 1053 | if (ret) |
531ee1a6 | 1054 | return ret; |
a556c76a AB |
1055 | } |
1056 | } | |
1057 | ||
531ee1a6 VO |
1058 | return 0; |
1059 | } | |
5e256365 | 1060 | EXPORT_SYMBOL(ocelot_fdb_dump); |
531ee1a6 VO |
1061 | |
1062 | static int ocelot_port_fdb_dump(struct sk_buff *skb, | |
1063 | struct netlink_callback *cb, | |
1064 | struct net_device *dev, | |
1065 | struct net_device *filter_dev, int *idx) | |
1066 | { | |
004d44f6 VO |
1067 | struct ocelot_port_private *priv = netdev_priv(dev); |
1068 | struct ocelot *ocelot = priv->port.ocelot; | |
531ee1a6 VO |
1069 | struct ocelot_dump_ctx dump = { |
1070 | .dev = dev, | |
1071 | .skb = skb, | |
1072 | .cb = cb, | |
1073 | .idx = *idx, | |
1074 | }; | |
004d44f6 | 1075 | int port = priv->chip_port; |
531ee1a6 VO |
1076 | int ret; |
1077 | ||
004d44f6 | 1078 | ret = ocelot_fdb_dump(ocelot, port, ocelot_port_fdb_do_dump, &dump); |
531ee1a6 | 1079 | |
a556c76a | 1080 | *idx = dump.idx; |
531ee1a6 | 1081 | |
a556c76a AB |
1082 | return ret; |
1083 | } | |
1084 | ||
7142529f AT |
1085 | static int ocelot_vlan_rx_add_vid(struct net_device *dev, __be16 proto, |
1086 | u16 vid) | |
1087 | { | |
1c44ce56 | 1088 | return ocelot_vlan_vid_add(dev, vid, false, false); |
7142529f AT |
1089 | } |
1090 | ||
1091 | static int ocelot_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, | |
1092 | u16 vid) | |
1093 | { | |
1094 | return ocelot_vlan_vid_del(dev, vid); | |
1095 | } | |
1096 | ||
1097 | static int ocelot_set_features(struct net_device *dev, | |
1098 | netdev_features_t features) | |
1099 | { | |
7142529f | 1100 | netdev_features_t changed = dev->features ^ features; |
004d44f6 VO |
1101 | struct ocelot_port_private *priv = netdev_priv(dev); |
1102 | struct ocelot *ocelot = priv->port.ocelot; | |
1103 | int port = priv->chip_port; | |
7142529f | 1104 | |
2c1d029a | 1105 | if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && |
004d44f6 | 1106 | priv->tc.offload_cnt) { |
2c1d029a JA |
1107 | netdev_err(dev, |
1108 | "Cannot disable HW TC offload while offloads active\n"); | |
1109 | return -EBUSY; | |
1110 | } | |
1111 | ||
7142529f | 1112 | if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) |
f270dbfa | 1113 | ocelot_vlan_mode(ocelot, port, features); |
7142529f AT |
1114 | |
1115 | return 0; | |
1116 | } | |
1117 | ||
751302c3 FF |
1118 | static int ocelot_get_port_parent_id(struct net_device *dev, |
1119 | struct netdev_phys_item_id *ppid) | |
1120 | { | |
004d44f6 VO |
1121 | struct ocelot_port_private *priv = netdev_priv(dev); |
1122 | struct ocelot *ocelot = priv->port.ocelot; | |
751302c3 FF |
1123 | |
1124 | ppid->id_len = sizeof(ocelot->base_mac); | |
1125 | memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len); | |
1126 | ||
1127 | return 0; | |
1128 | } | |
1129 | ||
f145922d | 1130 | int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr) |
4e3b0468 | 1131 | { |
4e3b0468 AT |
1132 | return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config, |
1133 | sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0; | |
1134 | } | |
f145922d | 1135 | EXPORT_SYMBOL(ocelot_hwstamp_get); |
4e3b0468 | 1136 | |
f145922d | 1137 | int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) |
4e3b0468 | 1138 | { |
306fd44b | 1139 | struct ocelot_port *ocelot_port = ocelot->ports[port]; |
4e3b0468 AT |
1140 | struct hwtstamp_config cfg; |
1141 | ||
1142 | if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) | |
1143 | return -EFAULT; | |
1144 | ||
1145 | /* reserved for future extensions */ | |
1146 | if (cfg.flags) | |
1147 | return -EINVAL; | |
1148 | ||
1149 | /* Tx type sanity check */ | |
1150 | switch (cfg.tx_type) { | |
1151 | case HWTSTAMP_TX_ON: | |
306fd44b | 1152 | ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; |
4e3b0468 AT |
1153 | break; |
1154 | case HWTSTAMP_TX_ONESTEP_SYNC: | |
1155 | /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we | |
1156 | * need to update the origin time. | |
1157 | */ | |
306fd44b | 1158 | ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP; |
4e3b0468 AT |
1159 | break; |
1160 | case HWTSTAMP_TX_OFF: | |
306fd44b | 1161 | ocelot_port->ptp_cmd = 0; |
4e3b0468 AT |
1162 | break; |
1163 | default: | |
1164 | return -ERANGE; | |
1165 | } | |
1166 | ||
1167 | mutex_lock(&ocelot->ptp_lock); | |
1168 | ||
1169 | switch (cfg.rx_filter) { | |
1170 | case HWTSTAMP_FILTER_NONE: | |
1171 | break; | |
1172 | case HWTSTAMP_FILTER_ALL: | |
1173 | case HWTSTAMP_FILTER_SOME: | |
1174 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | |
1175 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | |
1176 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | |
1177 | case HWTSTAMP_FILTER_NTP_ALL: | |
1178 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | |
1179 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | |
1180 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | |
1181 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | |
1182 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | |
1183 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | |
1184 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | |
1185 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | |
1186 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | |
1187 | cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; | |
1188 | break; | |
1189 | default: | |
1190 | mutex_unlock(&ocelot->ptp_lock); | |
1191 | return -ERANGE; | |
1192 | } | |
1193 | ||
1194 | /* Commit back the result & save it */ | |
1195 | memcpy(&ocelot->hwtstamp_config, &cfg, sizeof(cfg)); | |
1196 | mutex_unlock(&ocelot->ptp_lock); | |
1197 | ||
1198 | return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; | |
1199 | } | |
f145922d | 1200 | EXPORT_SYMBOL(ocelot_hwstamp_set); |
4e3b0468 AT |
1201 | |
1202 | static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |
1203 | { | |
004d44f6 VO |
1204 | struct ocelot_port_private *priv = netdev_priv(dev); |
1205 | struct ocelot *ocelot = priv->port.ocelot; | |
1206 | int port = priv->chip_port; | |
4e3b0468 AT |
1207 | |
1208 | /* The function is only used for PTP operations for now */ | |
1209 | if (!ocelot->ptp) | |
1210 | return -EOPNOTSUPP; | |
1211 | ||
1212 | switch (cmd) { | |
1213 | case SIOCSHWTSTAMP: | |
306fd44b | 1214 | return ocelot_hwstamp_set(ocelot, port, ifr); |
4e3b0468 | 1215 | case SIOCGHWTSTAMP: |
306fd44b | 1216 | return ocelot_hwstamp_get(ocelot, port, ifr); |
4e3b0468 AT |
1217 | default: |
1218 | return -EOPNOTSUPP; | |
1219 | } | |
1220 | } | |
1221 | ||
a556c76a AB |
1222 | static const struct net_device_ops ocelot_port_netdev_ops = { |
1223 | .ndo_open = ocelot_port_open, | |
1224 | .ndo_stop = ocelot_port_stop, | |
1225 | .ndo_start_xmit = ocelot_port_xmit, | |
1226 | .ndo_set_rx_mode = ocelot_set_rx_mode, | |
1227 | .ndo_get_phys_port_name = ocelot_port_get_phys_port_name, | |
1228 | .ndo_set_mac_address = ocelot_port_set_mac_address, | |
1229 | .ndo_get_stats64 = ocelot_get_stats64, | |
531ee1a6 VO |
1230 | .ndo_fdb_add = ocelot_port_fdb_add, |
1231 | .ndo_fdb_del = ocelot_port_fdb_del, | |
1232 | .ndo_fdb_dump = ocelot_port_fdb_dump, | |
7142529f AT |
1233 | .ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid, |
1234 | .ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid, | |
1235 | .ndo_set_features = ocelot_set_features, | |
751302c3 | 1236 | .ndo_get_port_parent_id = ocelot_get_port_parent_id, |
2c1d029a | 1237 | .ndo_setup_tc = ocelot_setup_tc, |
4e3b0468 | 1238 | .ndo_do_ioctl = ocelot_ioctl, |
a556c76a AB |
1239 | }; |
1240 | ||
5e256365 | 1241 | void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data) |
a556c76a | 1242 | { |
a556c76a AB |
1243 | int i; |
1244 | ||
1245 | if (sset != ETH_SS_STATS) | |
1246 | return; | |
1247 | ||
1248 | for (i = 0; i < ocelot->num_stats; i++) | |
1249 | memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name, | |
1250 | ETH_GSTRING_LEN); | |
1251 | } | |
5e256365 | 1252 | EXPORT_SYMBOL(ocelot_get_strings); |
a556c76a | 1253 | |
c7282d38 VO |
1254 | static void ocelot_port_get_strings(struct net_device *netdev, u32 sset, |
1255 | u8 *data) | |
1256 | { | |
1257 | struct ocelot_port_private *priv = netdev_priv(netdev); | |
1258 | struct ocelot *ocelot = priv->port.ocelot; | |
1259 | int port = priv->chip_port; | |
1260 | ||
1261 | ocelot_get_strings(ocelot, port, sset, data); | |
1262 | } | |
1263 | ||
1e1caa97 | 1264 | static void ocelot_update_stats(struct ocelot *ocelot) |
a556c76a | 1265 | { |
a556c76a AB |
1266 | int i, j; |
1267 | ||
1268 | mutex_lock(&ocelot->stats_lock); | |
1269 | ||
1270 | for (i = 0; i < ocelot->num_phys_ports; i++) { | |
1271 | /* Configure the port to read the stats from */ | |
1272 | ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(i), SYS_STAT_CFG); | |
1273 | ||
1274 | for (j = 0; j < ocelot->num_stats; j++) { | |
1275 | u32 val; | |
1276 | unsigned int idx = i * ocelot->num_stats + j; | |
1277 | ||
1278 | val = ocelot_read_rix(ocelot, SYS_COUNT_RX_OCTETS, | |
1279 | ocelot->stats_layout[j].offset); | |
1280 | ||
1281 | if (val < (ocelot->stats[idx] & U32_MAX)) | |
1282 | ocelot->stats[idx] += (u64)1 << 32; | |
1283 | ||
1284 | ocelot->stats[idx] = (ocelot->stats[idx] & | |
1285 | ~(u64)U32_MAX) + val; | |
1286 | } | |
1287 | } | |
1288 | ||
1e1caa97 CM |
1289 | mutex_unlock(&ocelot->stats_lock); |
1290 | } | |
1291 | ||
1292 | static void ocelot_check_stats_work(struct work_struct *work) | |
1293 | { | |
1294 | struct delayed_work *del_work = to_delayed_work(work); | |
1295 | struct ocelot *ocelot = container_of(del_work, struct ocelot, | |
1296 | stats_work); | |
1297 | ||
1298 | ocelot_update_stats(ocelot); | |
1299 | ||
a556c76a AB |
1300 | queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work, |
1301 | OCELOT_STATS_CHECK_DELAY); | |
a556c76a AB |
1302 | } |
1303 | ||
5e256365 | 1304 | void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) |
a556c76a | 1305 | { |
a556c76a AB |
1306 | int i; |
1307 | ||
1308 | /* check and update now */ | |
1e1caa97 | 1309 | ocelot_update_stats(ocelot); |
a556c76a AB |
1310 | |
1311 | /* Copy all counters */ | |
1312 | for (i = 0; i < ocelot->num_stats; i++) | |
004d44f6 | 1313 | *data++ = ocelot->stats[port * ocelot->num_stats + i]; |
a556c76a | 1314 | } |
5e256365 | 1315 | EXPORT_SYMBOL(ocelot_get_ethtool_stats); |
a556c76a | 1316 | |
c7282d38 VO |
1317 | static void ocelot_port_get_ethtool_stats(struct net_device *dev, |
1318 | struct ethtool_stats *stats, | |
1319 | u64 *data) | |
a556c76a | 1320 | { |
004d44f6 VO |
1321 | struct ocelot_port_private *priv = netdev_priv(dev); |
1322 | struct ocelot *ocelot = priv->port.ocelot; | |
c7282d38 | 1323 | int port = priv->chip_port; |
a556c76a | 1324 | |
c7282d38 VO |
1325 | ocelot_get_ethtool_stats(ocelot, port, data); |
1326 | } | |
1327 | ||
5e256365 | 1328 | int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset) |
c7282d38 | 1329 | { |
a556c76a AB |
1330 | if (sset != ETH_SS_STATS) |
1331 | return -EOPNOTSUPP; | |
c7282d38 | 1332 | |
a556c76a AB |
1333 | return ocelot->num_stats; |
1334 | } | |
5e256365 | 1335 | EXPORT_SYMBOL(ocelot_get_sset_count); |
a556c76a | 1336 | |
c7282d38 | 1337 | static int ocelot_port_get_sset_count(struct net_device *dev, int sset) |
4e3b0468 | 1338 | { |
004d44f6 VO |
1339 | struct ocelot_port_private *priv = netdev_priv(dev); |
1340 | struct ocelot *ocelot = priv->port.ocelot; | |
c7282d38 | 1341 | int port = priv->chip_port; |
4e3b0468 | 1342 | |
c7282d38 VO |
1343 | return ocelot_get_sset_count(ocelot, port, sset); |
1344 | } | |
4e3b0468 | 1345 | |
5e256365 VO |
1346 | int ocelot_get_ts_info(struct ocelot *ocelot, int port, |
1347 | struct ethtool_ts_info *info) | |
c7282d38 | 1348 | { |
4e3b0468 AT |
1349 | info->phc_index = ocelot->ptp_clock ? |
1350 | ptp_clock_index(ocelot->ptp_clock) : -1; | |
1351 | info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | | |
1352 | SOF_TIMESTAMPING_RX_SOFTWARE | | |
1353 | SOF_TIMESTAMPING_SOFTWARE | | |
1354 | SOF_TIMESTAMPING_TX_HARDWARE | | |
1355 | SOF_TIMESTAMPING_RX_HARDWARE | | |
1356 | SOF_TIMESTAMPING_RAW_HARDWARE; | |
1357 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) | | |
1358 | BIT(HWTSTAMP_TX_ONESTEP_SYNC); | |
1359 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); | |
1360 | ||
1361 | return 0; | |
1362 | } | |
5e256365 | 1363 | EXPORT_SYMBOL(ocelot_get_ts_info); |
4e3b0468 | 1364 | |
c7282d38 VO |
1365 | static int ocelot_port_get_ts_info(struct net_device *dev, |
1366 | struct ethtool_ts_info *info) | |
1367 | { | |
1368 | struct ocelot_port_private *priv = netdev_priv(dev); | |
1369 | struct ocelot *ocelot = priv->port.ocelot; | |
1370 | int port = priv->chip_port; | |
1371 | ||
1372 | if (!ocelot->ptp) | |
1373 | return ethtool_op_get_ts_info(dev, info); | |
1374 | ||
1375 | return ocelot_get_ts_info(ocelot, port, info); | |
1376 | } | |
1377 | ||
a556c76a | 1378 | static const struct ethtool_ops ocelot_ethtool_ops = { |
c7282d38 VO |
1379 | .get_strings = ocelot_port_get_strings, |
1380 | .get_ethtool_stats = ocelot_port_get_ethtool_stats, | |
1381 | .get_sset_count = ocelot_port_get_sset_count, | |
dc96ee37 AB |
1382 | .get_link_ksettings = phy_ethtool_get_link_ksettings, |
1383 | .set_link_ksettings = phy_ethtool_set_link_ksettings, | |
c7282d38 | 1384 | .get_ts_info = ocelot_port_get_ts_info, |
a556c76a AB |
1385 | }; |
1386 | ||
5e256365 | 1387 | void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) |
a556c76a | 1388 | { |
a556c76a | 1389 | u32 port_cfg; |
4bda1415 | 1390 | int p, i; |
a556c76a | 1391 | |
4bda1415 VO |
1392 | if (!(BIT(port) & ocelot->bridge_mask)) |
1393 | return; | |
a556c76a | 1394 | |
4bda1415 | 1395 | port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port); |
a556c76a AB |
1396 | |
1397 | switch (state) { | |
1398 | case BR_STATE_FORWARDING: | |
4bda1415 | 1399 | ocelot->bridge_fwd_mask |= BIT(port); |
a556c76a AB |
1400 | /* Fallthrough */ |
1401 | case BR_STATE_LEARNING: | |
1402 | port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA; | |
1403 | break; | |
1404 | ||
1405 | default: | |
1406 | port_cfg &= ~ANA_PORT_PORT_CFG_LEARN_ENA; | |
4bda1415 | 1407 | ocelot->bridge_fwd_mask &= ~BIT(port); |
a556c76a AB |
1408 | break; |
1409 | } | |
1410 | ||
4bda1415 | 1411 | ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, port); |
a556c76a AB |
1412 | |
1413 | /* Apply FWD mask. The loop is needed to add/remove the current port as | |
1414 | * a source for the other ports. | |
1415 | */ | |
4bda1415 | 1416 | for (p = 0; p < ocelot->num_phys_ports; p++) { |
69df578c | 1417 | if (ocelot->bridge_fwd_mask & BIT(p)) { |
4bda1415 | 1418 | unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p); |
a556c76a AB |
1419 | |
1420 | for (i = 0; i < ocelot->num_phys_ports; i++) { | |
1421 | unsigned long bond_mask = ocelot->lags[i]; | |
1422 | ||
1423 | if (!bond_mask) | |
1424 | continue; | |
1425 | ||
4bda1415 | 1426 | if (bond_mask & BIT(p)) { |
a556c76a AB |
1427 | mask &= ~bond_mask; |
1428 | break; | |
1429 | } | |
1430 | } | |
1431 | ||
c9d2203b | 1432 | ocelot_write_rix(ocelot, mask, |
4bda1415 | 1433 | ANA_PGID_PGID, PGID_SRC + p); |
a556c76a | 1434 | } else { |
69df578c | 1435 | ocelot_write_rix(ocelot, 0, |
4bda1415 | 1436 | ANA_PGID_PGID, PGID_SRC + p); |
a556c76a AB |
1437 | } |
1438 | } | |
4bda1415 | 1439 | } |
5e256365 | 1440 | EXPORT_SYMBOL(ocelot_bridge_stp_state_set); |
a556c76a | 1441 | |
4bda1415 VO |
1442 | static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port, |
1443 | struct switchdev_trans *trans, | |
1444 | u8 state) | |
1445 | { | |
1446 | if (switchdev_trans_ph_prepare(trans)) | |
1447 | return; | |
1448 | ||
1449 | ocelot_bridge_stp_state_set(ocelot, port, state); | |
1450 | } | |
1451 | ||
5e256365 | 1452 | void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs) |
4bda1415 | 1453 | { |
c0d7eccb VO |
1454 | unsigned int age_period = ANA_AUTOAGE_AGE_PERIOD(msecs / 2000); |
1455 | ||
1456 | /* Setting AGE_PERIOD to zero effectively disables automatic aging, | |
1457 | * which is clearly not what our intention is. So avoid that. | |
1458 | */ | |
1459 | if (!age_period) | |
1460 | age_period = 1; | |
1461 | ||
1462 | ocelot_rmw(ocelot, age_period, ANA_AUTOAGE_AGE_PERIOD_M, ANA_AUTOAGE); | |
a556c76a | 1463 | } |
5e256365 | 1464 | EXPORT_SYMBOL(ocelot_set_ageing_time); |
a556c76a | 1465 | |
4bda1415 | 1466 | static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port, |
a556c76a AB |
1467 | unsigned long ageing_clock_t) |
1468 | { | |
a556c76a AB |
1469 | unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t); |
1470 | u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000; | |
1471 | ||
4bda1415 | 1472 | ocelot_set_ageing_time(ocelot, ageing_time); |
a556c76a AB |
1473 | } |
1474 | ||
4bda1415 | 1475 | static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc) |
a556c76a | 1476 | { |
4bda1415 VO |
1477 | u32 cpu_fwd_mcast = ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA | |
1478 | ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA | | |
1479 | ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA; | |
1480 | u32 val = 0; | |
a556c76a AB |
1481 | |
1482 | if (mc) | |
4bda1415 | 1483 | val = cpu_fwd_mcast; |
a556c76a | 1484 | |
4bda1415 VO |
1485 | ocelot_rmw_gix(ocelot, val, cpu_fwd_mcast, |
1486 | ANA_PORT_CPU_FWD_CFG, port); | |
a556c76a AB |
1487 | } |
1488 | ||
1489 | static int ocelot_port_attr_set(struct net_device *dev, | |
1490 | const struct switchdev_attr *attr, | |
1491 | struct switchdev_trans *trans) | |
1492 | { | |
004d44f6 VO |
1493 | struct ocelot_port_private *priv = netdev_priv(dev); |
1494 | struct ocelot *ocelot = priv->port.ocelot; | |
1495 | int port = priv->chip_port; | |
a556c76a AB |
1496 | int err = 0; |
1497 | ||
1498 | switch (attr->id) { | |
1499 | case SWITCHDEV_ATTR_ID_PORT_STP_STATE: | |
4bda1415 | 1500 | ocelot_port_attr_stp_state_set(ocelot, port, trans, |
a556c76a AB |
1501 | attr->u.stp_state); |
1502 | break; | |
1503 | case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: | |
4bda1415 | 1504 | ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time); |
a556c76a | 1505 | break; |
7142529f | 1506 | case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: |
87b0f983 VO |
1507 | ocelot_port_vlan_filtering(ocelot, port, |
1508 | attr->u.vlan_filtering); | |
7142529f | 1509 | break; |
a556c76a | 1510 | case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: |
4bda1415 | 1511 | ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled); |
a556c76a AB |
1512 | break; |
1513 | default: | |
1514 | err = -EOPNOTSUPP; | |
1515 | break; | |
1516 | } | |
1517 | ||
1518 | return err; | |
1519 | } | |
1520 | ||
7142529f AT |
1521 | static int ocelot_port_obj_add_vlan(struct net_device *dev, |
1522 | const struct switchdev_obj_port_vlan *vlan, | |
1523 | struct switchdev_trans *trans) | |
1524 | { | |
1525 | int ret; | |
1526 | u16 vid; | |
1527 | ||
1528 | for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { | |
1529 | ret = ocelot_vlan_vid_add(dev, vid, | |
1530 | vlan->flags & BRIDGE_VLAN_INFO_PVID, | |
1531 | vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); | |
1532 | if (ret) | |
1533 | return ret; | |
1534 | } | |
1535 | ||
1536 | return 0; | |
1537 | } | |
1538 | ||
1539 | static int ocelot_port_vlan_del_vlan(struct net_device *dev, | |
1540 | const struct switchdev_obj_port_vlan *vlan) | |
1541 | { | |
1542 | int ret; | |
1543 | u16 vid; | |
1544 | ||
1545 | for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { | |
1546 | ret = ocelot_vlan_vid_del(dev, vid); | |
1547 | ||
1548 | if (ret) | |
1549 | return ret; | |
1550 | } | |
1551 | ||
1552 | return 0; | |
1553 | } | |
1554 | ||
a556c76a AB |
1555 | static struct ocelot_multicast *ocelot_multicast_get(struct ocelot *ocelot, |
1556 | const unsigned char *addr, | |
1557 | u16 vid) | |
1558 | { | |
1559 | struct ocelot_multicast *mc; | |
1560 | ||
1561 | list_for_each_entry(mc, &ocelot->multicast, list) { | |
1562 | if (ether_addr_equal(mc->addr, addr) && mc->vid == vid) | |
1563 | return mc; | |
1564 | } | |
1565 | ||
1566 | return NULL; | |
1567 | } | |
1568 | ||
1569 | static int ocelot_port_obj_add_mdb(struct net_device *dev, | |
1570 | const struct switchdev_obj_port_mdb *mdb, | |
1571 | struct switchdev_trans *trans) | |
1572 | { | |
004d44f6 VO |
1573 | struct ocelot_port_private *priv = netdev_priv(dev); |
1574 | struct ocelot_port *ocelot_port = &priv->port; | |
1575 | struct ocelot *ocelot = ocelot_port->ocelot; | |
a556c76a | 1576 | unsigned char addr[ETH_ALEN]; |
004d44f6 VO |
1577 | struct ocelot_multicast *mc; |
1578 | int port = priv->chip_port; | |
a556c76a AB |
1579 | u16 vid = mdb->vid; |
1580 | bool new = false; | |
1581 | ||
1582 | if (!vid) | |
004d44f6 | 1583 | vid = ocelot_port->pvid; |
a556c76a AB |
1584 | |
1585 | mc = ocelot_multicast_get(ocelot, mdb->addr, vid); | |
1586 | if (!mc) { | |
1587 | mc = devm_kzalloc(ocelot->dev, sizeof(*mc), GFP_KERNEL); | |
1588 | if (!mc) | |
1589 | return -ENOMEM; | |
1590 | ||
1591 | memcpy(mc->addr, mdb->addr, ETH_ALEN); | |
1592 | mc->vid = vid; | |
1593 | ||
1594 | list_add_tail(&mc->list, &ocelot->multicast); | |
1595 | new = true; | |
1596 | } | |
1597 | ||
1598 | memcpy(addr, mc->addr, ETH_ALEN); | |
1599 | addr[0] = 0; | |
1600 | ||
1601 | if (!new) { | |
1602 | addr[2] = mc->ports << 0; | |
1603 | addr[1] = mc->ports << 8; | |
1604 | ocelot_mact_forget(ocelot, addr, vid); | |
1605 | } | |
1606 | ||
004d44f6 | 1607 | mc->ports |= BIT(port); |
a556c76a AB |
1608 | addr[2] = mc->ports << 0; |
1609 | addr[1] = mc->ports << 8; | |
1610 | ||
1611 | return ocelot_mact_learn(ocelot, 0, addr, vid, ENTRYTYPE_MACv4); | |
1612 | } | |
1613 | ||
1614 | static int ocelot_port_obj_del_mdb(struct net_device *dev, | |
1615 | const struct switchdev_obj_port_mdb *mdb) | |
1616 | { | |
004d44f6 VO |
1617 | struct ocelot_port_private *priv = netdev_priv(dev); |
1618 | struct ocelot_port *ocelot_port = &priv->port; | |
1619 | struct ocelot *ocelot = ocelot_port->ocelot; | |
a556c76a | 1620 | unsigned char addr[ETH_ALEN]; |
004d44f6 VO |
1621 | struct ocelot_multicast *mc; |
1622 | int port = priv->chip_port; | |
a556c76a AB |
1623 | u16 vid = mdb->vid; |
1624 | ||
1625 | if (!vid) | |
004d44f6 | 1626 | vid = ocelot_port->pvid; |
a556c76a AB |
1627 | |
1628 | mc = ocelot_multicast_get(ocelot, mdb->addr, vid); | |
1629 | if (!mc) | |
1630 | return -ENOENT; | |
1631 | ||
1632 | memcpy(addr, mc->addr, ETH_ALEN); | |
1633 | addr[2] = mc->ports << 0; | |
1634 | addr[1] = mc->ports << 8; | |
1635 | addr[0] = 0; | |
1636 | ocelot_mact_forget(ocelot, addr, vid); | |
1637 | ||
004d44f6 | 1638 | mc->ports &= ~BIT(port); |
a556c76a AB |
1639 | if (!mc->ports) { |
1640 | list_del(&mc->list); | |
1641 | devm_kfree(ocelot->dev, mc); | |
1642 | return 0; | |
1643 | } | |
1644 | ||
1645 | addr[2] = mc->ports << 0; | |
1646 | addr[1] = mc->ports << 8; | |
1647 | ||
1648 | return ocelot_mact_learn(ocelot, 0, addr, vid, ENTRYTYPE_MACv4); | |
1649 | } | |
1650 | ||
1651 | static int ocelot_port_obj_add(struct net_device *dev, | |
1652 | const struct switchdev_obj *obj, | |
69213513 PM |
1653 | struct switchdev_trans *trans, |
1654 | struct netlink_ext_ack *extack) | |
a556c76a AB |
1655 | { |
1656 | int ret = 0; | |
1657 | ||
1658 | switch (obj->id) { | |
7142529f AT |
1659 | case SWITCHDEV_OBJ_ID_PORT_VLAN: |
1660 | ret = ocelot_port_obj_add_vlan(dev, | |
1661 | SWITCHDEV_OBJ_PORT_VLAN(obj), | |
1662 | trans); | |
1663 | break; | |
a556c76a AB |
1664 | case SWITCHDEV_OBJ_ID_PORT_MDB: |
1665 | ret = ocelot_port_obj_add_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj), | |
1666 | trans); | |
1667 | break; | |
1668 | default: | |
1669 | return -EOPNOTSUPP; | |
1670 | } | |
1671 | ||
1672 | return ret; | |
1673 | } | |
1674 | ||
1675 | static int ocelot_port_obj_del(struct net_device *dev, | |
1676 | const struct switchdev_obj *obj) | |
1677 | { | |
1678 | int ret = 0; | |
1679 | ||
1680 | switch (obj->id) { | |
7142529f AT |
1681 | case SWITCHDEV_OBJ_ID_PORT_VLAN: |
1682 | ret = ocelot_port_vlan_del_vlan(dev, | |
1683 | SWITCHDEV_OBJ_PORT_VLAN(obj)); | |
1684 | break; | |
a556c76a AB |
1685 | case SWITCHDEV_OBJ_ID_PORT_MDB: |
1686 | ret = ocelot_port_obj_del_mdb(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); | |
1687 | break; | |
1688 | default: | |
1689 | return -EOPNOTSUPP; | |
1690 | } | |
1691 | ||
1692 | return ret; | |
1693 | } | |
1694 | ||
5e256365 VO |
1695 | int ocelot_port_bridge_join(struct ocelot *ocelot, int port, |
1696 | struct net_device *bridge) | |
a556c76a | 1697 | { |
a556c76a AB |
1698 | if (!ocelot->bridge_mask) { |
1699 | ocelot->hw_bridge_dev = bridge; | |
1700 | } else { | |
1701 | if (ocelot->hw_bridge_dev != bridge) | |
1702 | /* This is adding the port to a second bridge, this is | |
1703 | * unsupported */ | |
1704 | return -ENODEV; | |
1705 | } | |
1706 | ||
f270dbfa | 1707 | ocelot->bridge_mask |= BIT(port); |
a556c76a AB |
1708 | |
1709 | return 0; | |
1710 | } | |
5e256365 | 1711 | EXPORT_SYMBOL(ocelot_port_bridge_join); |
a556c76a | 1712 | |
5e256365 VO |
1713 | int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, |
1714 | struct net_device *bridge) | |
a556c76a | 1715 | { |
97bb69e1 | 1716 | ocelot->bridge_mask &= ~BIT(port); |
a556c76a AB |
1717 | |
1718 | if (!ocelot->bridge_mask) | |
1719 | ocelot->hw_bridge_dev = NULL; | |
7142529f | 1720 | |
97bb69e1 VO |
1721 | ocelot_port_vlan_filtering(ocelot, port, 0); |
1722 | ocelot_port_set_pvid(ocelot, port, 0); | |
1723 | return ocelot_port_set_native_vlan(ocelot, port, 0); | |
a556c76a | 1724 | } |
5e256365 | 1725 | EXPORT_SYMBOL(ocelot_port_bridge_leave); |
a556c76a | 1726 | |
dc96ee37 AB |
1727 | static void ocelot_set_aggr_pgids(struct ocelot *ocelot) |
1728 | { | |
1729 | int i, port, lag; | |
1730 | ||
1731 | /* Reset destination and aggregation PGIDS */ | |
1732 | for (port = 0; port < ocelot->num_phys_ports; port++) | |
1733 | ocelot_write_rix(ocelot, BIT(port), ANA_PGID_PGID, port); | |
1734 | ||
1735 | for (i = PGID_AGGR; i < PGID_SRC; i++) | |
1736 | ocelot_write_rix(ocelot, GENMASK(ocelot->num_phys_ports - 1, 0), | |
1737 | ANA_PGID_PGID, i); | |
1738 | ||
1739 | /* Now, set PGIDs for each LAG */ | |
1740 | for (lag = 0; lag < ocelot->num_phys_ports; lag++) { | |
1741 | unsigned long bond_mask; | |
1742 | int aggr_count = 0; | |
1743 | u8 aggr_idx[16]; | |
1744 | ||
1745 | bond_mask = ocelot->lags[lag]; | |
1746 | if (!bond_mask) | |
1747 | continue; | |
1748 | ||
1749 | for_each_set_bit(port, &bond_mask, ocelot->num_phys_ports) { | |
1750 | // Destination mask | |
1751 | ocelot_write_rix(ocelot, bond_mask, | |
1752 | ANA_PGID_PGID, port); | |
1753 | aggr_idx[aggr_count] = port; | |
1754 | aggr_count++; | |
1755 | } | |
1756 | ||
1757 | for (i = PGID_AGGR; i < PGID_SRC; i++) { | |
1758 | u32 ac; | |
1759 | ||
1760 | ac = ocelot_read_rix(ocelot, ANA_PGID_PGID, i); | |
1761 | ac &= ~bond_mask; | |
1762 | ac |= BIT(aggr_idx[i % aggr_count]); | |
1763 | ocelot_write_rix(ocelot, ac, ANA_PGID_PGID, i); | |
1764 | } | |
1765 | } | |
1766 | } | |
1767 | ||
1768 | static void ocelot_setup_lag(struct ocelot *ocelot, int lag) | |
1769 | { | |
1770 | unsigned long bond_mask = ocelot->lags[lag]; | |
1771 | unsigned int p; | |
1772 | ||
1773 | for_each_set_bit(p, &bond_mask, ocelot->num_phys_ports) { | |
1774 | u32 port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, p); | |
1775 | ||
1776 | port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M; | |
1777 | ||
1778 | /* Use lag port as logical port for port i */ | |
1779 | ocelot_write_gix(ocelot, port_cfg | | |
1780 | ANA_PORT_PORT_CFG_PORTID_VAL(lag), | |
1781 | ANA_PORT_PORT_CFG, p); | |
1782 | } | |
1783 | } | |
1784 | ||
f270dbfa | 1785 | static int ocelot_port_lag_join(struct ocelot *ocelot, int port, |
dc96ee37 AB |
1786 | struct net_device *bond) |
1787 | { | |
dc96ee37 AB |
1788 | struct net_device *ndev; |
1789 | u32 bond_mask = 0; | |
f270dbfa | 1790 | int lag, lp; |
dc96ee37 AB |
1791 | |
1792 | rcu_read_lock(); | |
1793 | for_each_netdev_in_bond_rcu(bond, ndev) { | |
004d44f6 | 1794 | struct ocelot_port_private *priv = netdev_priv(ndev); |
dc96ee37 | 1795 | |
004d44f6 | 1796 | bond_mask |= BIT(priv->chip_port); |
dc96ee37 AB |
1797 | } |
1798 | rcu_read_unlock(); | |
1799 | ||
1800 | lp = __ffs(bond_mask); | |
1801 | ||
1802 | /* If the new port is the lowest one, use it as the logical port from | |
1803 | * now on | |
1804 | */ | |
f270dbfa VO |
1805 | if (port == lp) { |
1806 | lag = port; | |
1807 | ocelot->lags[port] = bond_mask; | |
1808 | bond_mask &= ~BIT(port); | |
dc96ee37 AB |
1809 | if (bond_mask) { |
1810 | lp = __ffs(bond_mask); | |
1811 | ocelot->lags[lp] = 0; | |
1812 | } | |
1813 | } else { | |
1814 | lag = lp; | |
f270dbfa | 1815 | ocelot->lags[lp] |= BIT(port); |
dc96ee37 AB |
1816 | } |
1817 | ||
1818 | ocelot_setup_lag(ocelot, lag); | |
1819 | ocelot_set_aggr_pgids(ocelot); | |
1820 | ||
1821 | return 0; | |
1822 | } | |
1823 | ||
f270dbfa | 1824 | static void ocelot_port_lag_leave(struct ocelot *ocelot, int port, |
dc96ee37 AB |
1825 | struct net_device *bond) |
1826 | { | |
dc96ee37 AB |
1827 | u32 port_cfg; |
1828 | int i; | |
1829 | ||
1830 | /* Remove port from any lag */ | |
1831 | for (i = 0; i < ocelot->num_phys_ports; i++) | |
f270dbfa | 1832 | ocelot->lags[i] &= ~BIT(port); |
dc96ee37 AB |
1833 | |
1834 | /* if it was the logical port of the lag, move the lag config to the | |
1835 | * next port | |
1836 | */ | |
f270dbfa VO |
1837 | if (ocelot->lags[port]) { |
1838 | int n = __ffs(ocelot->lags[port]); | |
dc96ee37 | 1839 | |
f270dbfa VO |
1840 | ocelot->lags[n] = ocelot->lags[port]; |
1841 | ocelot->lags[port] = 0; | |
dc96ee37 AB |
1842 | |
1843 | ocelot_setup_lag(ocelot, n); | |
1844 | } | |
1845 | ||
f270dbfa | 1846 | port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port); |
dc96ee37 | 1847 | port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M; |
f270dbfa VO |
1848 | ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(port), |
1849 | ANA_PORT_PORT_CFG, port); | |
dc96ee37 AB |
1850 | |
1851 | ocelot_set_aggr_pgids(ocelot); | |
1852 | } | |
1853 | ||
a556c76a AB |
1854 | /* Checks if the net_device instance given to us originate from our driver. */ |
1855 | static bool ocelot_netdevice_dev_check(const struct net_device *dev) | |
1856 | { | |
1857 | return dev->netdev_ops == &ocelot_port_netdev_ops; | |
1858 | } | |
1859 | ||
1860 | static int ocelot_netdevice_port_event(struct net_device *dev, | |
1861 | unsigned long event, | |
1862 | struct netdev_notifier_changeupper_info *info) | |
1863 | { | |
004d44f6 VO |
1864 | struct ocelot_port_private *priv = netdev_priv(dev); |
1865 | struct ocelot_port *ocelot_port = &priv->port; | |
f270dbfa | 1866 | struct ocelot *ocelot = ocelot_port->ocelot; |
004d44f6 | 1867 | int port = priv->chip_port; |
a556c76a AB |
1868 | int err = 0; |
1869 | ||
a556c76a AB |
1870 | switch (event) { |
1871 | case NETDEV_CHANGEUPPER: | |
1872 | if (netif_is_bridge_master(info->upper_dev)) { | |
004d44f6 | 1873 | if (info->linking) { |
f270dbfa | 1874 | err = ocelot_port_bridge_join(ocelot, port, |
a556c76a | 1875 | info->upper_dev); |
004d44f6 | 1876 | } else { |
f270dbfa | 1877 | err = ocelot_port_bridge_leave(ocelot, port, |
97bb69e1 | 1878 | info->upper_dev); |
004d44f6 | 1879 | } |
a556c76a | 1880 | } |
dc96ee37 AB |
1881 | if (netif_is_lag_master(info->upper_dev)) { |
1882 | if (info->linking) | |
f270dbfa | 1883 | err = ocelot_port_lag_join(ocelot, port, |
dc96ee37 AB |
1884 | info->upper_dev); |
1885 | else | |
f270dbfa | 1886 | ocelot_port_lag_leave(ocelot, port, |
dc96ee37 AB |
1887 | info->upper_dev); |
1888 | } | |
a556c76a AB |
1889 | break; |
1890 | default: | |
1891 | break; | |
1892 | } | |
1893 | ||
1894 | return err; | |
1895 | } | |
1896 | ||
1897 | static int ocelot_netdevice_event(struct notifier_block *unused, | |
1898 | unsigned long event, void *ptr) | |
1899 | { | |
1900 | struct netdev_notifier_changeupper_info *info = ptr; | |
1901 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | |
2ac0e152 | 1902 | int ret = 0; |
a556c76a | 1903 | |
7afb3e57 CM |
1904 | if (!ocelot_netdevice_dev_check(dev)) |
1905 | return 0; | |
1906 | ||
dc96ee37 AB |
1907 | if (event == NETDEV_PRECHANGEUPPER && |
1908 | netif_is_lag_master(info->upper_dev)) { | |
1909 | struct netdev_lag_upper_info *lag_upper_info = info->upper_info; | |
1910 | struct netlink_ext_ack *extack; | |
1911 | ||
3b3eed8e CM |
1912 | if (lag_upper_info && |
1913 | lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { | |
dc96ee37 AB |
1914 | extack = netdev_notifier_info_to_extack(&info->info); |
1915 | NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type"); | |
1916 | ||
1917 | ret = -EINVAL; | |
1918 | goto notify; | |
1919 | } | |
1920 | } | |
1921 | ||
a556c76a AB |
1922 | if (netif_is_lag_master(dev)) { |
1923 | struct net_device *slave; | |
1924 | struct list_head *iter; | |
1925 | ||
1926 | netdev_for_each_lower_dev(dev, slave, iter) { | |
1927 | ret = ocelot_netdevice_port_event(slave, event, info); | |
1928 | if (ret) | |
1929 | goto notify; | |
1930 | } | |
1931 | } else { | |
1932 | ret = ocelot_netdevice_port_event(dev, event, info); | |
1933 | } | |
1934 | ||
1935 | notify: | |
1936 | return notifier_from_errno(ret); | |
1937 | } | |
1938 | ||
1939 | struct notifier_block ocelot_netdevice_nb __read_mostly = { | |
1940 | .notifier_call = ocelot_netdevice_event, | |
1941 | }; | |
1942 | EXPORT_SYMBOL(ocelot_netdevice_nb); | |
1943 | ||
56da64bc FF |
1944 | static int ocelot_switchdev_event(struct notifier_block *unused, |
1945 | unsigned long event, void *ptr) | |
1946 | { | |
1947 | struct net_device *dev = switchdev_notifier_info_to_dev(ptr); | |
1948 | int err; | |
1949 | ||
1950 | switch (event) { | |
1951 | case SWITCHDEV_PORT_ATTR_SET: | |
1952 | err = switchdev_handle_port_attr_set(dev, ptr, | |
1953 | ocelot_netdevice_dev_check, | |
1954 | ocelot_port_attr_set); | |
1955 | return notifier_from_errno(err); | |
1956 | } | |
1957 | ||
1958 | return NOTIFY_DONE; | |
1959 | } | |
1960 | ||
1961 | struct notifier_block ocelot_switchdev_nb __read_mostly = { | |
1962 | .notifier_call = ocelot_switchdev_event, | |
1963 | }; | |
1964 | EXPORT_SYMBOL(ocelot_switchdev_nb); | |
1965 | ||
0e332c85 PM |
1966 | static int ocelot_switchdev_blocking_event(struct notifier_block *unused, |
1967 | unsigned long event, void *ptr) | |
1968 | { | |
1969 | struct net_device *dev = switchdev_notifier_info_to_dev(ptr); | |
1970 | int err; | |
1971 | ||
1972 | switch (event) { | |
1973 | /* Blocking events. */ | |
1974 | case SWITCHDEV_PORT_OBJ_ADD: | |
1975 | err = switchdev_handle_port_obj_add(dev, ptr, | |
1976 | ocelot_netdevice_dev_check, | |
1977 | ocelot_port_obj_add); | |
1978 | return notifier_from_errno(err); | |
1979 | case SWITCHDEV_PORT_OBJ_DEL: | |
1980 | err = switchdev_handle_port_obj_del(dev, ptr, | |
1981 | ocelot_netdevice_dev_check, | |
1982 | ocelot_port_obj_del); | |
1983 | return notifier_from_errno(err); | |
56da64bc FF |
1984 | case SWITCHDEV_PORT_ATTR_SET: |
1985 | err = switchdev_handle_port_attr_set(dev, ptr, | |
1986 | ocelot_netdevice_dev_check, | |
1987 | ocelot_port_attr_set); | |
1988 | return notifier_from_errno(err); | |
0e332c85 PM |
1989 | } |
1990 | ||
1991 | return NOTIFY_DONE; | |
1992 | } | |
1993 | ||
1994 | struct notifier_block ocelot_switchdev_blocking_nb __read_mostly = { | |
1995 | .notifier_call = ocelot_switchdev_blocking_event, | |
1996 | }; | |
1997 | EXPORT_SYMBOL(ocelot_switchdev_blocking_nb); | |
1998 | ||
4e3b0468 AT |
1999 | int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) |
2000 | { | |
2001 | struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); | |
2002 | unsigned long flags; | |
2003 | time64_t s; | |
2004 | u32 val; | |
2005 | s64 ns; | |
2006 | ||
2007 | spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); | |
2008 | ||
2009 | val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); | |
2010 | val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); | |
2011 | val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE); | |
2012 | ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); | |
2013 | ||
2014 | s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN) & 0xffff; | |
2015 | s <<= 32; | |
2016 | s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); | |
2017 | ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); | |
2018 | ||
2019 | spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); | |
2020 | ||
2021 | /* Deal with negative values */ | |
2022 | if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) { | |
2023 | s--; | |
2024 | ns &= 0xf; | |
2025 | ns += 999999984; | |
2026 | } | |
2027 | ||
2028 | set_normalized_timespec64(ts, s, ns); | |
2029 | return 0; | |
2030 | } | |
2031 | EXPORT_SYMBOL(ocelot_ptp_gettime64); | |
2032 | ||
2033 | static int ocelot_ptp_settime64(struct ptp_clock_info *ptp, | |
2034 | const struct timespec64 *ts) | |
2035 | { | |
2036 | struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); | |
2037 | unsigned long flags; | |
2038 | u32 val; | |
2039 | ||
2040 | spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); | |
2041 | ||
2042 | val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); | |
2043 | val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); | |
2044 | val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); | |
2045 | ||
2046 | ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); | |
2047 | ||
2048 | ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB, | |
2049 | TOD_ACC_PIN); | |
2050 | ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB, | |
2051 | TOD_ACC_PIN); | |
2052 | ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); | |
2053 | ||
2054 | val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); | |
2055 | val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); | |
2056 | val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD); | |
2057 | ||
2058 | ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); | |
2059 | ||
2060 | spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); | |
2061 | return 0; | |
2062 | } | |
2063 | ||
2064 | static int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) | |
2065 | { | |
2066 | if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) { | |
2067 | struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); | |
2068 | unsigned long flags; | |
2069 | u32 val; | |
2070 | ||
2071 | spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); | |
2072 | ||
2073 | val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); | |
2074 | val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); | |
2075 | val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE); | |
2076 | ||
2077 | ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); | |
2078 | ||
2079 | ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN); | |
2080 | ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN); | |
2081 | ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN); | |
2082 | ||
2083 | val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN); | |
2084 | val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM); | |
2085 | val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA); | |
2086 | ||
2087 | ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); | |
2088 | ||
2089 | spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); | |
2090 | } else { | |
2091 | /* Fall back using ocelot_ptp_settime64 which is not exact. */ | |
2092 | struct timespec64 ts; | |
2093 | u64 now; | |
2094 | ||
2095 | ocelot_ptp_gettime64(ptp, &ts); | |
2096 | ||
2097 | now = ktime_to_ns(timespec64_to_ktime(ts)); | |
2098 | ts = ns_to_timespec64(now + delta); | |
2099 | ||
2100 | ocelot_ptp_settime64(ptp, &ts); | |
2101 | } | |
2102 | return 0; | |
2103 | } | |
2104 | ||
2105 | static int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) | |
2106 | { | |
2107 | struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); | |
2108 | u32 unit = 0, direction = 0; | |
2109 | unsigned long flags; | |
2110 | u64 adj = 0; | |
2111 | ||
2112 | spin_lock_irqsave(&ocelot->ptp_clock_lock, flags); | |
2113 | ||
2114 | if (!scaled_ppm) | |
2115 | goto disable_adj; | |
2116 | ||
2117 | if (scaled_ppm < 0) { | |
2118 | direction = PTP_CFG_CLK_ADJ_CFG_DIR; | |
2119 | scaled_ppm = -scaled_ppm; | |
2120 | } | |
2121 | ||
2122 | adj = PSEC_PER_SEC << 16; | |
2123 | do_div(adj, scaled_ppm); | |
2124 | do_div(adj, 1000); | |
2125 | ||
2126 | /* If the adjustment value is too large, use ns instead */ | |
2127 | if (adj >= (1L << 30)) { | |
2128 | unit = PTP_CFG_CLK_ADJ_FREQ_NS; | |
2129 | do_div(adj, 1000); | |
2130 | } | |
2131 | ||
2132 | /* Still too big */ | |
2133 | if (adj >= (1L << 30)) | |
2134 | goto disable_adj; | |
2135 | ||
2136 | ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ); | |
2137 | ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction, | |
2138 | PTP_CLK_CFG_ADJ_CFG); | |
2139 | ||
2140 | spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); | |
2141 | return 0; | |
2142 | ||
2143 | disable_adj: | |
2144 | ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG); | |
2145 | ||
2146 | spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); | |
2147 | return 0; | |
2148 | } | |
2149 | ||
2150 | static struct ptp_clock_info ocelot_ptp_clock_info = { | |
2151 | .owner = THIS_MODULE, | |
2152 | .name = "ocelot ptp", | |
2153 | .max_adj = 0x7fffffff, | |
2154 | .n_alarm = 0, | |
2155 | .n_ext_ts = 0, | |
2156 | .n_per_out = 0, | |
2157 | .n_pins = 0, | |
2158 | .pps = 0, | |
2159 | .gettime64 = ocelot_ptp_gettime64, | |
2160 | .settime64 = ocelot_ptp_settime64, | |
2161 | .adjtime = ocelot_ptp_adjtime, | |
2162 | .adjfine = ocelot_ptp_adjfine, | |
2163 | }; | |
2164 | ||
2165 | static int ocelot_init_timestamp(struct ocelot *ocelot) | |
2166 | { | |
9385973f VO |
2167 | struct ptp_clock *ptp_clock; |
2168 | ||
4e3b0468 | 2169 | ocelot->ptp_info = ocelot_ptp_clock_info; |
9385973f VO |
2170 | ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev); |
2171 | if (IS_ERR(ptp_clock)) | |
2172 | return PTR_ERR(ptp_clock); | |
4e3b0468 | 2173 | /* Check if PHC support is missing at the configuration level */ |
9385973f | 2174 | if (!ptp_clock) |
4e3b0468 AT |
2175 | return 0; |
2176 | ||
9385973f VO |
2177 | ocelot->ptp_clock = ptp_clock; |
2178 | ||
4e3b0468 AT |
2179 | ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG); |
2180 | ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW); | |
2181 | ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH); | |
2182 | ||
2183 | ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC); | |
2184 | ||
2185 | /* There is no device reconfiguration, PTP Rx stamping is always | |
2186 | * enabled. | |
2187 | */ | |
2188 | ocelot->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; | |
2189 | ||
2190 | return 0; | |
2191 | } | |
2192 | ||
a8015ded VO |
2193 | /* Configure the maximum SDU (L2 payload) on RX to the value specified in @sdu. |
2194 | * The length of VLAN tags is accounted for automatically via DEV_MAC_TAGS_CFG. | |
0b912fc9 VO |
2195 | * In the special case that it's the NPI port that we're configuring, the |
2196 | * length of the tag and optional prefix needs to be accounted for privately, | |
2197 | * in order to be able to sustain communication at the requested @sdu. | |
a8015ded | 2198 | */ |
0b912fc9 | 2199 | void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu) |
31350d7f VO |
2200 | { |
2201 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
a8015ded | 2202 | int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN; |
5bc9d2e6 | 2203 | int atop_wm; |
31350d7f | 2204 | |
0b912fc9 VO |
2205 | if (port == ocelot->npi) { |
2206 | maxlen += OCELOT_TAG_LEN; | |
2207 | ||
2208 | if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_SHORT) | |
2209 | maxlen += OCELOT_SHORT_PREFIX_LEN; | |
2210 | else if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_LONG) | |
2211 | maxlen += OCELOT_LONG_PREFIX_LEN; | |
2212 | } | |
2213 | ||
a8015ded | 2214 | ocelot_port_writel(ocelot_port, maxlen, DEV_MAC_MAXLEN_CFG); |
fa914e9c VO |
2215 | |
2216 | /* Set Pause WM hysteresis | |
a8015ded VO |
2217 | * 152 = 6 * maxlen / OCELOT_BUFFER_CELL_SZ |
2218 | * 101 = 4 * maxlen / OCELOT_BUFFER_CELL_SZ | |
fa914e9c VO |
2219 | */ |
2220 | ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | | |
2221 | SYS_PAUSE_CFG_PAUSE_STOP(101) | | |
2222 | SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); | |
2223 | ||
2224 | /* Tail dropping watermark */ | |
a8015ded VO |
2225 | atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) / |
2226 | OCELOT_BUFFER_CELL_SZ; | |
2227 | ocelot_write_rix(ocelot, ocelot_wm_enc(9 * maxlen), | |
fa914e9c VO |
2228 | SYS_ATOP, port); |
2229 | ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); | |
2230 | } | |
0b912fc9 VO |
2231 | EXPORT_SYMBOL(ocelot_port_set_maxlen); |
2232 | ||
2233 | int ocelot_get_max_mtu(struct ocelot *ocelot, int port) | |
2234 | { | |
2235 | int max_mtu = 65535 - ETH_HLEN - ETH_FCS_LEN; | |
2236 | ||
2237 | if (port == ocelot->npi) { | |
2238 | max_mtu -= OCELOT_TAG_LEN; | |
2239 | ||
2240 | if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_SHORT) | |
2241 | max_mtu -= OCELOT_SHORT_PREFIX_LEN; | |
2242 | else if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_LONG) | |
2243 | max_mtu -= OCELOT_LONG_PREFIX_LEN; | |
2244 | } | |
2245 | ||
2246 | return max_mtu; | |
2247 | } | |
2248 | EXPORT_SYMBOL(ocelot_get_max_mtu); | |
fa914e9c | 2249 | |
5e256365 | 2250 | void ocelot_init_port(struct ocelot *ocelot, int port) |
fa914e9c VO |
2251 | { |
2252 | struct ocelot_port *ocelot_port = ocelot->ports[port]; | |
2253 | ||
b049da13 | 2254 | skb_queue_head_init(&ocelot_port->tx_skbs); |
31350d7f VO |
2255 | |
2256 | /* Basic L2 initialization */ | |
2257 | ||
5bc9d2e6 VO |
2258 | /* Set MAC IFG Gaps |
2259 | * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0 | |
2260 | * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5 | |
2261 | */ | |
2262 | ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5), | |
2263 | DEV_MAC_IFG_CFG); | |
2264 | ||
2265 | /* Load seed (0) and set MAC HDX late collision */ | |
2266 | ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) | | |
2267 | DEV_MAC_HDX_CFG_SEED_LOAD, | |
2268 | DEV_MAC_HDX_CFG); | |
2269 | mdelay(1); | |
2270 | ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67), | |
2271 | DEV_MAC_HDX_CFG); | |
2272 | ||
2273 | /* Set Max Length and maximum tags allowed */ | |
a8015ded | 2274 | ocelot_port_set_maxlen(ocelot, port, ETH_DATA_LEN); |
5bc9d2e6 VO |
2275 | ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) | |
2276 | DEV_MAC_TAGS_CFG_VLAN_AWR_ENA | | |
a8015ded | 2277 | DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA | |
5bc9d2e6 VO |
2278 | DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, |
2279 | DEV_MAC_TAGS_CFG); | |
2280 | ||
2281 | /* Set SMAC of Pause frame (00:00:00:00:00:00) */ | |
2282 | ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG); | |
2283 | ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG); | |
2284 | ||
31350d7f VO |
2285 | /* Drop frames with multicast source address */ |
2286 | ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, | |
2287 | ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, | |
2288 | ANA_PORT_DROP_CFG, port); | |
2289 | ||
2290 | /* Set default VLAN and tag type to 8021Q. */ | |
2291 | ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q), | |
2292 | REW_PORT_VLAN_CFG_PORT_TPID_M, | |
2293 | REW_PORT_VLAN_CFG, port); | |
2294 | ||
2295 | /* Enable vcap lookups */ | |
2296 | ocelot_vcap_enable(ocelot, port); | |
2297 | } | |
5e256365 | 2298 | EXPORT_SYMBOL(ocelot_init_port); |
31350d7f | 2299 | |
a556c76a AB |
2300 | int ocelot_probe_port(struct ocelot *ocelot, u8 port, |
2301 | void __iomem *regs, | |
2302 | struct phy_device *phy) | |
2303 | { | |
004d44f6 | 2304 | struct ocelot_port_private *priv; |
a556c76a AB |
2305 | struct ocelot_port *ocelot_port; |
2306 | struct net_device *dev; | |
2307 | int err; | |
2308 | ||
004d44f6 | 2309 | dev = alloc_etherdev(sizeof(struct ocelot_port_private)); |
a556c76a AB |
2310 | if (!dev) |
2311 | return -ENOMEM; | |
2312 | SET_NETDEV_DEV(dev, ocelot->dev); | |
004d44f6 VO |
2313 | priv = netdev_priv(dev); |
2314 | priv->dev = dev; | |
2315 | priv->phy = phy; | |
2316 | priv->chip_port = port; | |
2317 | ocelot_port = &priv->port; | |
a556c76a AB |
2318 | ocelot_port->ocelot = ocelot; |
2319 | ocelot_port->regs = regs; | |
a556c76a AB |
2320 | ocelot->ports[port] = ocelot_port; |
2321 | ||
2322 | dev->netdev_ops = &ocelot_port_netdev_ops; | |
2323 | dev->ethtool_ops = &ocelot_ethtool_ops; | |
a556c76a | 2324 | |
2c1d029a JA |
2325 | dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS | |
2326 | NETIF_F_HW_TC; | |
2327 | dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC; | |
7142529f | 2328 | |
a556c76a AB |
2329 | memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN); |
2330 | dev->dev_addr[ETH_ALEN - 1] += port; | |
2331 | ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid, | |
2332 | ENTRYTYPE_LOCKED); | |
2333 | ||
31350d7f | 2334 | ocelot_init_port(ocelot, port); |
4e3b0468 | 2335 | |
a556c76a AB |
2336 | err = register_netdev(dev); |
2337 | if (err) { | |
2338 | dev_err(ocelot->dev, "register_netdev failed\n"); | |
31350d7f | 2339 | free_netdev(dev); |
a556c76a AB |
2340 | } |
2341 | ||
a556c76a AB |
2342 | return err; |
2343 | } | |
2344 | EXPORT_SYMBOL(ocelot_probe_port); | |
2345 | ||
69df578c VO |
2346 | /* Configure and enable the CPU port module, which is a set of queues. |
2347 | * If @npi contains a valid port index, the CPU port module is connected | |
2348 | * to the Node Processor Interface (NPI). This is the mode through which | |
2349 | * frames can be injected from and extracted to an external CPU, | |
2350 | * over Ethernet. | |
2351 | */ | |
2352 | void ocelot_configure_cpu(struct ocelot *ocelot, int npi, | |
2353 | enum ocelot_tag_prefix injection, | |
2354 | enum ocelot_tag_prefix extraction) | |
21468199 | 2355 | { |
69df578c VO |
2356 | int cpu = ocelot->num_phys_ports; |
2357 | ||
0b912fc9 VO |
2358 | ocelot->npi = npi; |
2359 | ocelot->inj_prefix = injection; | |
2360 | ocelot->xtr_prefix = extraction; | |
2361 | ||
69df578c | 2362 | /* The unicast destination PGID for the CPU port module is unused */ |
21468199 | 2363 | ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); |
69df578c VO |
2364 | /* Instead set up a multicast destination PGID for traffic copied to |
2365 | * the CPU. Whitelisted MAC addresses like the port netdevice MAC | |
2366 | * addresses will be copied to the CPU via this PGID. | |
2367 | */ | |
21468199 VO |
2368 | ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); |
2369 | ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | | |
2370 | ANA_PORT_PORT_CFG_PORTID_VAL(cpu), | |
2371 | ANA_PORT_PORT_CFG, cpu); | |
2372 | ||
69df578c | 2373 | if (npi >= 0 && npi < ocelot->num_phys_ports) { |
21468199 | 2374 | ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | |
69df578c | 2375 | QSYS_EXT_CPU_CFG_EXT_CPU_PORT(npi), |
21468199 | 2376 | QSYS_EXT_CPU_CFG); |
ba551bc3 | 2377 | |
69df578c VO |
2378 | /* Enable NPI port */ |
2379 | ocelot_write_rix(ocelot, | |
2380 | QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | | |
2381 | QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | | |
2382 | QSYS_SWITCH_PORT_MODE_PORT_ENA, | |
2383 | QSYS_SWITCH_PORT_MODE, npi); | |
2384 | /* NPI port Injection/Extraction configuration */ | |
2385 | ocelot_write_rix(ocelot, | |
2386 | SYS_PORT_MODE_INCL_XTR_HDR(extraction) | | |
2387 | SYS_PORT_MODE_INCL_INJ_HDR(injection), | |
2388 | SYS_PORT_MODE, npi); | |
21468199 VO |
2389 | } |
2390 | ||
69df578c | 2391 | /* Enable CPU port module */ |
21468199 VO |
2392 | ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | |
2393 | QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | | |
2394 | QSYS_SWITCH_PORT_MODE_PORT_ENA, | |
2395 | QSYS_SWITCH_PORT_MODE, cpu); | |
69df578c | 2396 | /* CPU port Injection/Extraction configuration */ |
21468199 VO |
2397 | ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(extraction) | |
2398 | SYS_PORT_MODE_INCL_INJ_HDR(injection), | |
2399 | SYS_PORT_MODE, cpu); | |
2400 | ||
2401 | /* Configure the CPU port to be VLAN aware */ | |
2402 | ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) | | |
2403 | ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | | |
2404 | ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1), | |
2405 | ANA_PORT_VLAN_CFG, cpu); | |
21468199 | 2406 | } |
69df578c | 2407 | EXPORT_SYMBOL(ocelot_configure_cpu); |
21468199 | 2408 | |
a556c76a AB |
2409 | int ocelot_init(struct ocelot *ocelot) |
2410 | { | |
a556c76a | 2411 | char queue_name[32]; |
21468199 VO |
2412 | int i, ret; |
2413 | u32 port; | |
a556c76a | 2414 | |
3a77b593 VO |
2415 | if (ocelot->ops->reset) { |
2416 | ret = ocelot->ops->reset(ocelot); | |
2417 | if (ret) { | |
2418 | dev_err(ocelot->dev, "Switch reset failed\n"); | |
2419 | return ret; | |
2420 | } | |
2421 | } | |
2422 | ||
dc96ee37 AB |
2423 | ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, |
2424 | sizeof(u32), GFP_KERNEL); | |
2425 | if (!ocelot->lags) | |
2426 | return -ENOMEM; | |
2427 | ||
a556c76a AB |
2428 | ocelot->stats = devm_kcalloc(ocelot->dev, |
2429 | ocelot->num_phys_ports * ocelot->num_stats, | |
2430 | sizeof(u64), GFP_KERNEL); | |
2431 | if (!ocelot->stats) | |
2432 | return -ENOMEM; | |
2433 | ||
2434 | mutex_init(&ocelot->stats_lock); | |
4e3b0468 AT |
2435 | mutex_init(&ocelot->ptp_lock); |
2436 | spin_lock_init(&ocelot->ptp_clock_lock); | |
a556c76a AB |
2437 | snprintf(queue_name, sizeof(queue_name), "%s-stats", |
2438 | dev_name(ocelot->dev)); | |
2439 | ocelot->stats_queue = create_singlethread_workqueue(queue_name); | |
2440 | if (!ocelot->stats_queue) | |
2441 | return -ENOMEM; | |
2442 | ||
2b120dde | 2443 | INIT_LIST_HEAD(&ocelot->multicast); |
a556c76a AB |
2444 | ocelot_mact_init(ocelot); |
2445 | ocelot_vlan_init(ocelot); | |
b5962294 | 2446 | ocelot_ace_init(ocelot); |
a556c76a AB |
2447 | |
2448 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
2449 | /* Clear all counters (5 groups) */ | |
2450 | ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port) | | |
2451 | SYS_STAT_CFG_STAT_CLEAR_SHOT(0x7f), | |
2452 | SYS_STAT_CFG); | |
2453 | } | |
2454 | ||
2455 | /* Only use S-Tag */ | |
2456 | ocelot_write(ocelot, ETH_P_8021AD, SYS_VLAN_ETYPE_CFG); | |
2457 | ||
2458 | /* Aggregation mode */ | |
2459 | ocelot_write(ocelot, ANA_AGGR_CFG_AC_SMAC_ENA | | |
2460 | ANA_AGGR_CFG_AC_DMAC_ENA | | |
2461 | ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA | | |
2462 | ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, ANA_AGGR_CFG); | |
2463 | ||
2464 | /* Set MAC age time to default value. The entry is aged after | |
2465 | * 2*AGE_PERIOD | |
2466 | */ | |
2467 | ocelot_write(ocelot, | |
2468 | ANA_AUTOAGE_AGE_PERIOD(BR_DEFAULT_AGEING_TIME / 2 / HZ), | |
2469 | ANA_AUTOAGE); | |
2470 | ||
2471 | /* Disable learning for frames discarded by VLAN ingress filtering */ | |
2472 | regmap_field_write(ocelot->regfields[ANA_ADVLEARN_VLAN_CHK], 1); | |
2473 | ||
2474 | /* Setup frame ageing - fixed value "2 sec" - in 6.5 us units */ | |
2475 | ocelot_write(ocelot, SYS_FRM_AGING_AGE_TX_ENA | | |
2476 | SYS_FRM_AGING_MAX_AGE(307692), SYS_FRM_AGING); | |
2477 | ||
2478 | /* Setup flooding PGIDs */ | |
2479 | ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) | | |
2480 | ANA_FLOODING_FLD_BROADCAST(PGID_MC) | | |
2481 | ANA_FLOODING_FLD_UNICAST(PGID_UC), | |
2482 | ANA_FLOODING, 0); | |
2483 | ocelot_write(ocelot, ANA_FLOODING_IPMC_FLD_MC6_DATA(PGID_MCIPV6) | | |
2484 | ANA_FLOODING_IPMC_FLD_MC6_CTRL(PGID_MC) | | |
2485 | ANA_FLOODING_IPMC_FLD_MC4_DATA(PGID_MCIPV4) | | |
2486 | ANA_FLOODING_IPMC_FLD_MC4_CTRL(PGID_MC), | |
2487 | ANA_FLOODING_IPMC); | |
2488 | ||
2489 | for (port = 0; port < ocelot->num_phys_ports; port++) { | |
2490 | /* Transmit the frame to the local port. */ | |
2491 | ocelot_write_rix(ocelot, BIT(port), ANA_PGID_PGID, port); | |
2492 | /* Do not forward BPDU frames to the front ports. */ | |
2493 | ocelot_write_gix(ocelot, | |
2494 | ANA_PORT_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA(0xffff), | |
2495 | ANA_PORT_CPU_FWD_BPDU_CFG, | |
2496 | port); | |
2497 | /* Ensure bridging is disabled */ | |
2498 | ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_SRC + port); | |
2499 | } | |
2500 | ||
a556c76a AB |
2501 | /* Allow broadcast MAC frames. */ |
2502 | for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) { | |
2503 | u32 val = ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports - 1, 0)); | |
2504 | ||
2505 | ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i); | |
2506 | } | |
2507 | ocelot_write_rix(ocelot, | |
2508 | ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)), | |
2509 | ANA_PGID_PGID, PGID_MC); | |
2510 | ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4); | |
2511 | ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6); | |
2512 | ||
a556c76a AB |
2513 | /* Allow manual injection via DEVCPU_QS registers, and byte swap these |
2514 | * registers endianness. | |
2515 | */ | |
2516 | ocelot_write_rix(ocelot, QS_INJ_GRP_CFG_BYTE_SWAP | | |
2517 | QS_INJ_GRP_CFG_MODE(1), QS_INJ_GRP_CFG, 0); | |
2518 | ocelot_write_rix(ocelot, QS_XTR_GRP_CFG_BYTE_SWAP | | |
2519 | QS_XTR_GRP_CFG_MODE(1), QS_XTR_GRP_CFG, 0); | |
2520 | ocelot_write(ocelot, ANA_CPUQ_CFG_CPUQ_MIRROR(2) | | |
2521 | ANA_CPUQ_CFG_CPUQ_LRN(2) | | |
2522 | ANA_CPUQ_CFG_CPUQ_MAC_COPY(2) | | |
2523 | ANA_CPUQ_CFG_CPUQ_SRC_COPY(2) | | |
2524 | ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE(2) | | |
2525 | ANA_CPUQ_CFG_CPUQ_ALLBRIDGE(6) | | |
2526 | ANA_CPUQ_CFG_CPUQ_IPMC_CTRL(6) | | |
2527 | ANA_CPUQ_CFG_CPUQ_IGMP(6) | | |
2528 | ANA_CPUQ_CFG_CPUQ_MLD(6), ANA_CPUQ_CFG); | |
2529 | for (i = 0; i < 16; i++) | |
2530 | ocelot_write_rix(ocelot, ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL(6) | | |
2531 | ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL(6), | |
2532 | ANA_CPUQ_8021_CFG, i); | |
2533 | ||
1e1caa97 | 2534 | INIT_DELAYED_WORK(&ocelot->stats_work, ocelot_check_stats_work); |
a556c76a AB |
2535 | queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work, |
2536 | OCELOT_STATS_CHECK_DELAY); | |
4e3b0468 AT |
2537 | |
2538 | if (ocelot->ptp) { | |
2539 | ret = ocelot_init_timestamp(ocelot); | |
2540 | if (ret) { | |
2541 | dev_err(ocelot->dev, | |
2542 | "Timestamp initialization failed\n"); | |
2543 | return ret; | |
2544 | } | |
2545 | } | |
2546 | ||
a556c76a AB |
2547 | return 0; |
2548 | } | |
2549 | EXPORT_SYMBOL(ocelot_init); | |
2550 | ||
2551 | void ocelot_deinit(struct ocelot *ocelot) | |
2552 | { | |
4e3b0468 | 2553 | struct ocelot_port *port; |
4e3b0468 AT |
2554 | int i; |
2555 | ||
c5d13969 | 2556 | cancel_delayed_work(&ocelot->stats_work); |
a556c76a AB |
2557 | destroy_workqueue(ocelot->stats_queue); |
2558 | mutex_destroy(&ocelot->stats_lock); | |
9385973f VO |
2559 | if (ocelot->ptp_clock) |
2560 | ptp_clock_unregister(ocelot->ptp_clock); | |
4e3b0468 AT |
2561 | |
2562 | for (i = 0; i < ocelot->num_phys_ports; i++) { | |
2563 | port = ocelot->ports[i]; | |
b049da13 | 2564 | skb_queue_purge(&port->tx_skbs); |
4e3b0468 | 2565 | } |
a556c76a AB |
2566 | } |
2567 | EXPORT_SYMBOL(ocelot_deinit); | |
2568 | ||
2569 | MODULE_LICENSE("Dual MIT/GPL"); |