Commit | Line | Data |
---|---|---|
e66f840c TH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Microchip KSZ8795 switch driver | |
4 | * | |
5 | * Copyright (C) 2017 Microchip Technology Inc. | |
6 | * Tristram Ha <Tristram.Ha@microchip.com> | |
7 | */ | |
8 | ||
9 | #include <linux/delay.h> | |
10 | #include <linux/export.h> | |
11 | #include <linux/gpio.h> | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/platform_data/microchip-ksz.h> | |
15 | #include <linux/phy.h> | |
16 | #include <linux/etherdevice.h> | |
17 | #include <linux/if_bridge.h> | |
18 | #include <net/dsa.h> | |
19 | #include <net/switchdev.h> | |
20 | ||
e66f840c TH |
21 | #include "ksz_common.h" |
22 | #include "ksz8795_reg.h" | |
23 | ||
24 | static const struct { | |
25 | char string[ETH_GSTRING_LEN]; | |
65fe1acf | 26 | } mib_names[] = { |
e66f840c TH |
27 | { "rx_hi" }, |
28 | { "rx_undersize" }, | |
29 | { "rx_fragments" }, | |
30 | { "rx_oversize" }, | |
31 | { "rx_jabbers" }, | |
32 | { "rx_symbol_err" }, | |
33 | { "rx_crc_err" }, | |
34 | { "rx_align_err" }, | |
35 | { "rx_mac_ctrl" }, | |
36 | { "rx_pause" }, | |
37 | { "rx_bcast" }, | |
38 | { "rx_mcast" }, | |
39 | { "rx_ucast" }, | |
40 | { "rx_64_or_less" }, | |
41 | { "rx_65_127" }, | |
42 | { "rx_128_255" }, | |
43 | { "rx_256_511" }, | |
44 | { "rx_512_1023" }, | |
45 | { "rx_1024_1522" }, | |
46 | { "rx_1523_2000" }, | |
47 | { "rx_2001" }, | |
48 | { "tx_hi" }, | |
49 | { "tx_late_col" }, | |
50 | { "tx_pause" }, | |
51 | { "tx_bcast" }, | |
52 | { "tx_mcast" }, | |
53 | { "tx_ucast" }, | |
54 | { "tx_deferred" }, | |
55 | { "tx_total_col" }, | |
56 | { "tx_exc_col" }, | |
57 | { "tx_single_col" }, | |
58 | { "tx_mult_col" }, | |
59 | { "rx_total" }, | |
60 | { "tx_total" }, | |
61 | { "rx_discards" }, | |
62 | { "tx_discards" }, | |
63 | }; | |
64 | ||
65 | static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) | |
66 | { | |
67 | regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); | |
68 | } | |
69 | ||
70 | static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, | |
71 | bool set) | |
72 | { | |
73 | regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), | |
74 | bits, set ? bits : 0); | |
75 | } | |
76 | ||
77 | static int ksz8795_reset_switch(struct ksz_device *dev) | |
78 | { | |
79 | /* reset switch */ | |
80 | ksz_write8(dev, REG_POWER_MANAGEMENT_1, | |
81 | SW_SOFTWARE_POWER_DOWN << SW_POWER_MANAGEMENT_MODE_S); | |
82 | ksz_write8(dev, REG_POWER_MANAGEMENT_1, 0); | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue) | |
88 | { | |
89 | u8 hi, lo; | |
90 | ||
91 | /* Number of queues can only be 1, 2, or 4. */ | |
92 | switch (queue) { | |
93 | case 4: | |
94 | case 3: | |
95 | queue = PORT_QUEUE_SPLIT_4; | |
96 | break; | |
97 | case 2: | |
98 | queue = PORT_QUEUE_SPLIT_2; | |
99 | break; | |
100 | default: | |
101 | queue = PORT_QUEUE_SPLIT_1; | |
102 | } | |
103 | ksz_pread8(dev, port, REG_PORT_CTRL_0, &lo); | |
104 | ksz_pread8(dev, port, P_DROP_TAG_CTRL, &hi); | |
105 | lo &= ~PORT_QUEUE_SPLIT_L; | |
106 | if (queue & PORT_QUEUE_SPLIT_2) | |
107 | lo |= PORT_QUEUE_SPLIT_L; | |
108 | hi &= ~PORT_QUEUE_SPLIT_H; | |
109 | if (queue & PORT_QUEUE_SPLIT_4) | |
110 | hi |= PORT_QUEUE_SPLIT_H; | |
111 | ksz_pwrite8(dev, port, REG_PORT_CTRL_0, lo); | |
112 | ksz_pwrite8(dev, port, P_DROP_TAG_CTRL, hi); | |
113 | ||
114 | /* Default is port based for egress rate limit. */ | |
115 | if (queue != PORT_QUEUE_SPLIT_1) | |
116 | ksz_cfg(dev, REG_SW_CTRL_19, SW_OUT_RATE_LIMIT_QUEUE_BASED, | |
117 | true); | |
118 | } | |
119 | ||
120 | static void ksz8795_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, | |
121 | u64 *cnt) | |
122 | { | |
123 | u16 ctrl_addr; | |
124 | u32 data; | |
125 | u8 check; | |
126 | int loop; | |
127 | ||
31b62c78 | 128 | ctrl_addr = addr + dev->reg_mib_cnt * port; |
e66f840c TH |
129 | ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); |
130 | ||
131 | mutex_lock(&dev->alu_mutex); | |
132 | ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); | |
133 | ||
134 | /* It is almost guaranteed to always read the valid bit because of | |
135 | * slow SPI speed. | |
136 | */ | |
137 | for (loop = 2; loop > 0; loop--) { | |
138 | ksz_read8(dev, REG_IND_MIB_CHECK, &check); | |
139 | ||
140 | if (check & MIB_COUNTER_VALID) { | |
141 | ksz_read32(dev, REG_IND_DATA_LO, &data); | |
142 | if (check & MIB_COUNTER_OVERFLOW) | |
143 | *cnt += MIB_COUNTER_VALUE + 1; | |
144 | *cnt += data & MIB_COUNTER_VALUE; | |
145 | break; | |
146 | } | |
147 | } | |
148 | mutex_unlock(&dev->alu_mutex); | |
149 | } | |
150 | ||
151 | static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | |
152 | u64 *dropped, u64 *cnt) | |
153 | { | |
154 | u16 ctrl_addr; | |
155 | u32 data; | |
156 | u8 check; | |
157 | int loop; | |
158 | ||
31b62c78 | 159 | addr -= dev->reg_mib_cnt; |
e66f840c TH |
160 | ctrl_addr = (KS_MIB_TOTAL_RX_1 - KS_MIB_TOTAL_RX_0) * port; |
161 | ctrl_addr += addr + KS_MIB_TOTAL_RX_0; | |
162 | ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ); | |
163 | ||
164 | mutex_lock(&dev->alu_mutex); | |
165 | ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); | |
166 | ||
167 | /* It is almost guaranteed to always read the valid bit because of | |
168 | * slow SPI speed. | |
169 | */ | |
170 | for (loop = 2; loop > 0; loop--) { | |
171 | ksz_read8(dev, REG_IND_MIB_CHECK, &check); | |
172 | ||
173 | if (check & MIB_COUNTER_VALID) { | |
174 | ksz_read32(dev, REG_IND_DATA_LO, &data); | |
175 | if (addr < 2) { | |
176 | u64 total; | |
177 | ||
178 | total = check & MIB_TOTAL_BYTES_H; | |
179 | total <<= 32; | |
180 | *cnt += total; | |
181 | *cnt += data; | |
182 | if (check & MIB_COUNTER_OVERFLOW) { | |
183 | total = MIB_TOTAL_BYTES_H + 1; | |
184 | total <<= 32; | |
185 | *cnt += total; | |
186 | } | |
187 | } else { | |
188 | if (check & MIB_COUNTER_OVERFLOW) | |
189 | *cnt += MIB_PACKET_DROPPED + 1; | |
190 | *cnt += data & MIB_PACKET_DROPPED; | |
191 | } | |
192 | break; | |
193 | } | |
194 | } | |
195 | mutex_unlock(&dev->alu_mutex); | |
196 | } | |
197 | ||
198 | static void ksz8795_freeze_mib(struct ksz_device *dev, int port, bool freeze) | |
199 | { | |
200 | /* enable the port for flush/freeze function */ | |
201 | if (freeze) | |
202 | ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); | |
203 | ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FREEZE, freeze); | |
204 | ||
205 | /* disable the port after freeze is done */ | |
206 | if (!freeze) | |
207 | ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false); | |
208 | } | |
209 | ||
210 | static void ksz8795_port_init_cnt(struct ksz_device *dev, int port) | |
211 | { | |
212 | struct ksz_port_mib *mib = &dev->ports[port].mib; | |
213 | ||
214 | /* flush all enabled port MIB counters */ | |
215 | ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), true); | |
216 | ksz_cfg(dev, REG_SW_CTRL_6, SW_MIB_COUNTER_FLUSH, true); | |
217 | ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false); | |
218 | ||
219 | mib->cnt_ptr = 0; | |
220 | ||
221 | /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */ | |
222 | while (mib->cnt_ptr < dev->reg_mib_cnt) { | |
223 | dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr, | |
224 | &mib->counters[mib->cnt_ptr]); | |
225 | ++mib->cnt_ptr; | |
226 | } | |
227 | ||
228 | /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */ | |
229 | while (mib->cnt_ptr < dev->mib_cnt) { | |
230 | dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr, | |
231 | NULL, &mib->counters[mib->cnt_ptr]); | |
232 | ++mib->cnt_ptr; | |
233 | } | |
234 | mib->cnt_ptr = 0; | |
235 | memset(mib->counters, 0, dev->mib_cnt * sizeof(u64)); | |
236 | } | |
237 | ||
238 | static void ksz8795_r_table(struct ksz_device *dev, int table, u16 addr, | |
239 | u64 *data) | |
240 | { | |
241 | u16 ctrl_addr; | |
242 | ||
243 | ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr; | |
244 | ||
245 | mutex_lock(&dev->alu_mutex); | |
246 | ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); | |
247 | ksz_read64(dev, REG_IND_DATA_HI, data); | |
248 | mutex_unlock(&dev->alu_mutex); | |
249 | } | |
250 | ||
251 | static void ksz8795_w_table(struct ksz_device *dev, int table, u16 addr, | |
252 | u64 data) | |
253 | { | |
254 | u16 ctrl_addr; | |
255 | ||
256 | ctrl_addr = IND_ACC_TABLE(table) | addr; | |
257 | ||
258 | mutex_lock(&dev->alu_mutex); | |
259 | ksz_write64(dev, REG_IND_DATA_HI, data); | |
260 | ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); | |
261 | mutex_unlock(&dev->alu_mutex); | |
262 | } | |
263 | ||
264 | static int ksz8795_valid_dyn_entry(struct ksz_device *dev, u8 *data) | |
265 | { | |
266 | int timeout = 100; | |
267 | ||
268 | do { | |
269 | ksz_read8(dev, REG_IND_DATA_CHECK, data); | |
270 | timeout--; | |
271 | } while ((*data & DYNAMIC_MAC_TABLE_NOT_READY) && timeout); | |
272 | ||
273 | /* Entry is not ready for accessing. */ | |
274 | if (*data & DYNAMIC_MAC_TABLE_NOT_READY) { | |
275 | return -EAGAIN; | |
276 | /* Entry is ready for accessing. */ | |
277 | } else { | |
278 | ksz_read8(dev, REG_IND_DATA_8, data); | |
279 | ||
280 | /* There is no valid entry in the table. */ | |
281 | if (*data & DYNAMIC_MAC_TABLE_MAC_EMPTY) | |
282 | return -ENXIO; | |
283 | } | |
284 | return 0; | |
285 | } | |
286 | ||
287 | static int ksz8795_r_dyn_mac_table(struct ksz_device *dev, u16 addr, | |
288 | u8 *mac_addr, u8 *fid, u8 *src_port, | |
289 | u8 *timestamp, u16 *entries) | |
290 | { | |
291 | u32 data_hi, data_lo; | |
292 | u16 ctrl_addr; | |
293 | u8 data; | |
294 | int rc; | |
295 | ||
296 | ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr; | |
297 | ||
298 | mutex_lock(&dev->alu_mutex); | |
299 | ksz_write16(dev, REG_IND_CTRL_0, ctrl_addr); | |
300 | ||
301 | rc = ksz8795_valid_dyn_entry(dev, &data); | |
302 | if (rc == -EAGAIN) { | |
303 | if (addr == 0) | |
304 | *entries = 0; | |
305 | } else if (rc == -ENXIO) { | |
306 | *entries = 0; | |
307 | /* At least one valid entry in the table. */ | |
308 | } else { | |
309 | u64 buf = 0; | |
310 | int cnt; | |
311 | ||
312 | ksz_read64(dev, REG_IND_DATA_HI, &buf); | |
313 | data_hi = (u32)(buf >> 32); | |
314 | data_lo = (u32)buf; | |
315 | ||
316 | /* Check out how many valid entry in the table. */ | |
317 | cnt = data & DYNAMIC_MAC_TABLE_ENTRIES_H; | |
318 | cnt <<= DYNAMIC_MAC_ENTRIES_H_S; | |
319 | cnt |= (data_hi & DYNAMIC_MAC_TABLE_ENTRIES) >> | |
320 | DYNAMIC_MAC_ENTRIES_S; | |
321 | *entries = cnt + 1; | |
322 | ||
323 | *fid = (data_hi & DYNAMIC_MAC_TABLE_FID) >> | |
324 | DYNAMIC_MAC_FID_S; | |
325 | *src_port = (data_hi & DYNAMIC_MAC_TABLE_SRC_PORT) >> | |
326 | DYNAMIC_MAC_SRC_PORT_S; | |
327 | *timestamp = (data_hi & DYNAMIC_MAC_TABLE_TIMESTAMP) >> | |
328 | DYNAMIC_MAC_TIMESTAMP_S; | |
329 | ||
330 | mac_addr[5] = (u8)data_lo; | |
331 | mac_addr[4] = (u8)(data_lo >> 8); | |
332 | mac_addr[3] = (u8)(data_lo >> 16); | |
333 | mac_addr[2] = (u8)(data_lo >> 24); | |
334 | ||
335 | mac_addr[1] = (u8)data_hi; | |
336 | mac_addr[0] = (u8)(data_hi >> 8); | |
337 | rc = 0; | |
338 | } | |
339 | mutex_unlock(&dev->alu_mutex); | |
340 | ||
341 | return rc; | |
342 | } | |
343 | ||
344 | static int ksz8795_r_sta_mac_table(struct ksz_device *dev, u16 addr, | |
345 | struct alu_struct *alu) | |
346 | { | |
347 | u32 data_hi, data_lo; | |
348 | u64 data; | |
349 | ||
350 | ksz8795_r_table(dev, TABLE_STATIC_MAC, addr, &data); | |
351 | data_hi = data >> 32; | |
352 | data_lo = (u32)data; | |
353 | if (data_hi & (STATIC_MAC_TABLE_VALID | STATIC_MAC_TABLE_OVERRIDE)) { | |
354 | alu->mac[5] = (u8)data_lo; | |
355 | alu->mac[4] = (u8)(data_lo >> 8); | |
356 | alu->mac[3] = (u8)(data_lo >> 16); | |
357 | alu->mac[2] = (u8)(data_lo >> 24); | |
358 | alu->mac[1] = (u8)data_hi; | |
359 | alu->mac[0] = (u8)(data_hi >> 8); | |
360 | alu->port_forward = (data_hi & STATIC_MAC_TABLE_FWD_PORTS) >> | |
361 | STATIC_MAC_FWD_PORTS_S; | |
362 | alu->is_override = | |
363 | (data_hi & STATIC_MAC_TABLE_OVERRIDE) ? 1 : 0; | |
364 | data_hi >>= 1; | |
365 | alu->is_use_fid = (data_hi & STATIC_MAC_TABLE_USE_FID) ? 1 : 0; | |
366 | alu->fid = (data_hi & STATIC_MAC_TABLE_FID) >> | |
367 | STATIC_MAC_FID_S; | |
368 | return 0; | |
369 | } | |
370 | return -ENXIO; | |
371 | } | |
372 | ||
373 | static void ksz8795_w_sta_mac_table(struct ksz_device *dev, u16 addr, | |
374 | struct alu_struct *alu) | |
375 | { | |
376 | u32 data_hi, data_lo; | |
377 | u64 data; | |
378 | ||
379 | data_lo = ((u32)alu->mac[2] << 24) | | |
380 | ((u32)alu->mac[3] << 16) | | |
381 | ((u32)alu->mac[4] << 8) | alu->mac[5]; | |
382 | data_hi = ((u32)alu->mac[0] << 8) | alu->mac[1]; | |
383 | data_hi |= (u32)alu->port_forward << STATIC_MAC_FWD_PORTS_S; | |
384 | ||
385 | if (alu->is_override) | |
386 | data_hi |= STATIC_MAC_TABLE_OVERRIDE; | |
387 | if (alu->is_use_fid) { | |
388 | data_hi |= STATIC_MAC_TABLE_USE_FID; | |
389 | data_hi |= (u32)alu->fid << STATIC_MAC_FID_S; | |
390 | } | |
391 | if (alu->is_static) | |
392 | data_hi |= STATIC_MAC_TABLE_VALID; | |
393 | else | |
394 | data_hi &= ~STATIC_MAC_TABLE_OVERRIDE; | |
395 | ||
396 | data = (u64)data_hi << 32 | data_lo; | |
397 | ksz8795_w_table(dev, TABLE_STATIC_MAC, addr, data); | |
398 | } | |
399 | ||
400 | static void ksz8795_from_vlan(u16 vlan, u8 *fid, u8 *member, u8 *valid) | |
401 | { | |
402 | *fid = vlan & VLAN_TABLE_FID; | |
403 | *member = (vlan & VLAN_TABLE_MEMBERSHIP) >> VLAN_TABLE_MEMBERSHIP_S; | |
404 | *valid = !!(vlan & VLAN_TABLE_VALID); | |
405 | } | |
406 | ||
407 | static void ksz8795_to_vlan(u8 fid, u8 member, u8 valid, u16 *vlan) | |
408 | { | |
409 | *vlan = fid; | |
410 | *vlan |= (u16)member << VLAN_TABLE_MEMBERSHIP_S; | |
411 | if (valid) | |
412 | *vlan |= VLAN_TABLE_VALID; | |
413 | } | |
414 | ||
415 | static void ksz8795_r_vlan_entries(struct ksz_device *dev, u16 addr) | |
416 | { | |
417 | u64 data; | |
418 | int i; | |
419 | ||
420 | ksz8795_r_table(dev, TABLE_VLAN, addr, &data); | |
4ce2a984 MG |
421 | addr *= dev->phy_port_cnt; |
422 | for (i = 0; i < dev->phy_port_cnt; i++) { | |
e66f840c TH |
423 | dev->vlan_cache[addr + i].table[0] = (u16)data; |
424 | data >>= VLAN_TABLE_S; | |
425 | } | |
426 | } | |
427 | ||
428 | static void ksz8795_r_vlan_table(struct ksz_device *dev, u16 vid, u16 *vlan) | |
429 | { | |
430 | int index; | |
431 | u16 *data; | |
432 | u16 addr; | |
433 | u64 buf; | |
434 | ||
435 | data = (u16 *)&buf; | |
4ce2a984 | 436 | addr = vid / dev->phy_port_cnt; |
e66f840c TH |
437 | index = vid & 3; |
438 | ksz8795_r_table(dev, TABLE_VLAN, addr, &buf); | |
439 | *vlan = data[index]; | |
440 | } | |
441 | ||
442 | static void ksz8795_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) | |
443 | { | |
444 | int index; | |
445 | u16 *data; | |
446 | u16 addr; | |
447 | u64 buf; | |
448 | ||
449 | data = (u16 *)&buf; | |
4ce2a984 | 450 | addr = vid / dev->phy_port_cnt; |
e66f840c TH |
451 | index = vid & 3; |
452 | ksz8795_r_table(dev, TABLE_VLAN, addr, &buf); | |
453 | data[index] = vlan; | |
454 | dev->vlan_cache[vid].table[0] = vlan; | |
455 | ksz8795_w_table(dev, TABLE_VLAN, addr, buf); | |
456 | } | |
457 | ||
458 | static void ksz8795_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) | |
459 | { | |
460 | u8 restart, speed, ctrl, link; | |
461 | int processed = true; | |
462 | u16 data = 0; | |
463 | u8 p = phy; | |
464 | ||
465 | switch (reg) { | |
466 | case PHY_REG_CTRL: | |
467 | ksz_pread8(dev, p, P_NEG_RESTART_CTRL, &restart); | |
468 | ksz_pread8(dev, p, P_SPEED_STATUS, &speed); | |
469 | ksz_pread8(dev, p, P_FORCE_CTRL, &ctrl); | |
470 | if (restart & PORT_PHY_LOOPBACK) | |
471 | data |= PHY_LOOPBACK; | |
472 | if (ctrl & PORT_FORCE_100_MBIT) | |
473 | data |= PHY_SPEED_100MBIT; | |
474 | if (!(ctrl & PORT_AUTO_NEG_DISABLE)) | |
475 | data |= PHY_AUTO_NEG_ENABLE; | |
476 | if (restart & PORT_POWER_DOWN) | |
477 | data |= PHY_POWER_DOWN; | |
478 | if (restart & PORT_AUTO_NEG_RESTART) | |
479 | data |= PHY_AUTO_NEG_RESTART; | |
480 | if (ctrl & PORT_FORCE_FULL_DUPLEX) | |
481 | data |= PHY_FULL_DUPLEX; | |
482 | if (speed & PORT_HP_MDIX) | |
483 | data |= PHY_HP_MDIX; | |
484 | if (restart & PORT_FORCE_MDIX) | |
485 | data |= PHY_FORCE_MDIX; | |
486 | if (restart & PORT_AUTO_MDIX_DISABLE) | |
487 | data |= PHY_AUTO_MDIX_DISABLE; | |
488 | if (restart & PORT_TX_DISABLE) | |
489 | data |= PHY_TRANSMIT_DISABLE; | |
490 | if (restart & PORT_LED_OFF) | |
491 | data |= PHY_LED_DISABLE; | |
492 | break; | |
493 | case PHY_REG_STATUS: | |
494 | ksz_pread8(dev, p, P_LINK_STATUS, &link); | |
495 | data = PHY_100BTX_FD_CAPABLE | | |
496 | PHY_100BTX_CAPABLE | | |
497 | PHY_10BT_FD_CAPABLE | | |
498 | PHY_10BT_CAPABLE | | |
499 | PHY_AUTO_NEG_CAPABLE; | |
500 | if (link & PORT_AUTO_NEG_COMPLETE) | |
501 | data |= PHY_AUTO_NEG_ACKNOWLEDGE; | |
502 | if (link & PORT_STAT_LINK_GOOD) | |
503 | data |= PHY_LINK_STATUS; | |
504 | break; | |
505 | case PHY_REG_ID_1: | |
506 | data = KSZ8795_ID_HI; | |
507 | break; | |
508 | case PHY_REG_ID_2: | |
509 | data = KSZ8795_ID_LO; | |
510 | break; | |
511 | case PHY_REG_AUTO_NEGOTIATION: | |
512 | ksz_pread8(dev, p, P_LOCAL_CTRL, &ctrl); | |
513 | data = PHY_AUTO_NEG_802_3; | |
514 | if (ctrl & PORT_AUTO_NEG_SYM_PAUSE) | |
515 | data |= PHY_AUTO_NEG_SYM_PAUSE; | |
516 | if (ctrl & PORT_AUTO_NEG_100BTX_FD) | |
517 | data |= PHY_AUTO_NEG_100BTX_FD; | |
518 | if (ctrl & PORT_AUTO_NEG_100BTX) | |
519 | data |= PHY_AUTO_NEG_100BTX; | |
520 | if (ctrl & PORT_AUTO_NEG_10BT_FD) | |
521 | data |= PHY_AUTO_NEG_10BT_FD; | |
522 | if (ctrl & PORT_AUTO_NEG_10BT) | |
523 | data |= PHY_AUTO_NEG_10BT; | |
524 | break; | |
525 | case PHY_REG_REMOTE_CAPABILITY: | |
526 | ksz_pread8(dev, p, P_REMOTE_STATUS, &link); | |
527 | data = PHY_AUTO_NEG_802_3; | |
528 | if (link & PORT_REMOTE_SYM_PAUSE) | |
529 | data |= PHY_AUTO_NEG_SYM_PAUSE; | |
530 | if (link & PORT_REMOTE_100BTX_FD) | |
531 | data |= PHY_AUTO_NEG_100BTX_FD; | |
532 | if (link & PORT_REMOTE_100BTX) | |
533 | data |= PHY_AUTO_NEG_100BTX; | |
534 | if (link & PORT_REMOTE_10BT_FD) | |
535 | data |= PHY_AUTO_NEG_10BT_FD; | |
536 | if (link & PORT_REMOTE_10BT) | |
537 | data |= PHY_AUTO_NEG_10BT; | |
538 | if (data & ~PHY_AUTO_NEG_802_3) | |
539 | data |= PHY_REMOTE_ACKNOWLEDGE_NOT; | |
540 | break; | |
541 | default: | |
542 | processed = false; | |
543 | break; | |
544 | } | |
545 | if (processed) | |
546 | *val = data; | |
547 | } | |
548 | ||
549 | static void ksz8795_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) | |
550 | { | |
551 | u8 p = phy; | |
552 | u8 restart, speed, ctrl, data; | |
553 | ||
554 | switch (reg) { | |
555 | case PHY_REG_CTRL: | |
556 | ||
557 | /* Do not support PHY reset function. */ | |
558 | if (val & PHY_RESET) | |
559 | break; | |
560 | ksz_pread8(dev, p, P_SPEED_STATUS, &speed); | |
561 | data = speed; | |
562 | if (val & PHY_HP_MDIX) | |
563 | data |= PORT_HP_MDIX; | |
564 | else | |
565 | data &= ~PORT_HP_MDIX; | |
566 | if (data != speed) | |
567 | ksz_pwrite8(dev, p, P_SPEED_STATUS, data); | |
568 | ksz_pread8(dev, p, P_FORCE_CTRL, &ctrl); | |
569 | data = ctrl; | |
570 | if (!(val & PHY_AUTO_NEG_ENABLE)) | |
571 | data |= PORT_AUTO_NEG_DISABLE; | |
572 | else | |
573 | data &= ~PORT_AUTO_NEG_DISABLE; | |
574 | ||
575 | /* Fiber port does not support auto-negotiation. */ | |
576 | if (dev->ports[p].fiber) | |
577 | data |= PORT_AUTO_NEG_DISABLE; | |
578 | if (val & PHY_SPEED_100MBIT) | |
579 | data |= PORT_FORCE_100_MBIT; | |
580 | else | |
581 | data &= ~PORT_FORCE_100_MBIT; | |
582 | if (val & PHY_FULL_DUPLEX) | |
583 | data |= PORT_FORCE_FULL_DUPLEX; | |
584 | else | |
585 | data &= ~PORT_FORCE_FULL_DUPLEX; | |
586 | if (data != ctrl) | |
587 | ksz_pwrite8(dev, p, P_FORCE_CTRL, data); | |
588 | ksz_pread8(dev, p, P_NEG_RESTART_CTRL, &restart); | |
589 | data = restart; | |
590 | if (val & PHY_LED_DISABLE) | |
591 | data |= PORT_LED_OFF; | |
592 | else | |
593 | data &= ~PORT_LED_OFF; | |
594 | if (val & PHY_TRANSMIT_DISABLE) | |
595 | data |= PORT_TX_DISABLE; | |
596 | else | |
597 | data &= ~PORT_TX_DISABLE; | |
598 | if (val & PHY_AUTO_NEG_RESTART) | |
599 | data |= PORT_AUTO_NEG_RESTART; | |
600 | else | |
601 | data &= ~(PORT_AUTO_NEG_RESTART); | |
602 | if (val & PHY_POWER_DOWN) | |
603 | data |= PORT_POWER_DOWN; | |
604 | else | |
605 | data &= ~PORT_POWER_DOWN; | |
606 | if (val & PHY_AUTO_MDIX_DISABLE) | |
607 | data |= PORT_AUTO_MDIX_DISABLE; | |
608 | else | |
609 | data &= ~PORT_AUTO_MDIX_DISABLE; | |
610 | if (val & PHY_FORCE_MDIX) | |
611 | data |= PORT_FORCE_MDIX; | |
612 | else | |
613 | data &= ~PORT_FORCE_MDIX; | |
614 | if (val & PHY_LOOPBACK) | |
615 | data |= PORT_PHY_LOOPBACK; | |
616 | else | |
617 | data &= ~PORT_PHY_LOOPBACK; | |
618 | if (data != restart) | |
619 | ksz_pwrite8(dev, p, P_NEG_RESTART_CTRL, data); | |
620 | break; | |
621 | case PHY_REG_AUTO_NEGOTIATION: | |
622 | ksz_pread8(dev, p, P_LOCAL_CTRL, &ctrl); | |
623 | data = ctrl; | |
624 | data &= ~(PORT_AUTO_NEG_SYM_PAUSE | | |
625 | PORT_AUTO_NEG_100BTX_FD | | |
626 | PORT_AUTO_NEG_100BTX | | |
627 | PORT_AUTO_NEG_10BT_FD | | |
628 | PORT_AUTO_NEG_10BT); | |
629 | if (val & PHY_AUTO_NEG_SYM_PAUSE) | |
630 | data |= PORT_AUTO_NEG_SYM_PAUSE; | |
631 | if (val & PHY_AUTO_NEG_100BTX_FD) | |
632 | data |= PORT_AUTO_NEG_100BTX_FD; | |
633 | if (val & PHY_AUTO_NEG_100BTX) | |
634 | data |= PORT_AUTO_NEG_100BTX; | |
635 | if (val & PHY_AUTO_NEG_10BT_FD) | |
636 | data |= PORT_AUTO_NEG_10BT_FD; | |
637 | if (val & PHY_AUTO_NEG_10BT) | |
638 | data |= PORT_AUTO_NEG_10BT; | |
639 | if (data != ctrl) | |
640 | ksz_pwrite8(dev, p, P_LOCAL_CTRL, data); | |
641 | break; | |
642 | default: | |
643 | break; | |
644 | } | |
645 | } | |
646 | ||
647 | static enum dsa_tag_protocol ksz8795_get_tag_protocol(struct dsa_switch *ds, | |
4d776482 FF |
648 | int port, |
649 | enum dsa_tag_protocol mp) | |
e66f840c TH |
650 | { |
651 | return DSA_TAG_PROTO_KSZ8795; | |
652 | } | |
653 | ||
654 | static void ksz8795_get_strings(struct dsa_switch *ds, int port, | |
655 | u32 stringset, uint8_t *buf) | |
656 | { | |
65fe1acf | 657 | struct ksz_device *dev = ds->priv; |
e66f840c TH |
658 | int i; |
659 | ||
65fe1acf | 660 | for (i = 0; i < dev->mib_cnt; i++) { |
e66f840c TH |
661 | memcpy(buf + i * ETH_GSTRING_LEN, mib_names[i].string, |
662 | ETH_GSTRING_LEN); | |
663 | } | |
664 | } | |
665 | ||
666 | static void ksz8795_cfg_port_member(struct ksz_device *dev, int port, | |
667 | u8 member) | |
668 | { | |
669 | u8 data; | |
670 | ||
671 | ksz_pread8(dev, port, P_MIRROR_CTRL, &data); | |
672 | data &= ~PORT_VLAN_MEMBERSHIP; | |
673 | data |= (member & dev->port_mask); | |
674 | ksz_pwrite8(dev, port, P_MIRROR_CTRL, data); | |
675 | dev->ports[port].member = member; | |
676 | } | |
677 | ||
678 | static void ksz8795_port_stp_state_set(struct dsa_switch *ds, int port, | |
679 | u8 state) | |
680 | { | |
681 | struct ksz_device *dev = ds->priv; | |
682 | int forward = dev->member; | |
683 | struct ksz_port *p; | |
684 | int member = -1; | |
685 | u8 data; | |
686 | ||
687 | p = &dev->ports[port]; | |
688 | ||
689 | ksz_pread8(dev, port, P_STP_CTRL, &data); | |
690 | data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); | |
691 | ||
692 | switch (state) { | |
693 | case BR_STATE_DISABLED: | |
694 | data |= PORT_LEARN_DISABLE; | |
4ce2a984 | 695 | if (port < dev->phy_port_cnt) |
e66f840c TH |
696 | member = 0; |
697 | break; | |
698 | case BR_STATE_LISTENING: | |
699 | data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); | |
4ce2a984 | 700 | if (port < dev->phy_port_cnt && |
e66f840c TH |
701 | p->stp_state == BR_STATE_DISABLED) |
702 | member = dev->host_mask | p->vid_member; | |
703 | break; | |
704 | case BR_STATE_LEARNING: | |
705 | data |= PORT_RX_ENABLE; | |
706 | break; | |
707 | case BR_STATE_FORWARDING: | |
708 | data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); | |
709 | ||
710 | /* This function is also used internally. */ | |
711 | if (port == dev->cpu_port) | |
712 | break; | |
713 | ||
714 | /* Port is a member of a bridge. */ | |
715 | if (dev->br_member & BIT(port)) { | |
716 | dev->member |= BIT(port); | |
717 | member = dev->member; | |
718 | } else { | |
719 | member = dev->host_mask | p->vid_member; | |
720 | } | |
721 | break; | |
722 | case BR_STATE_BLOCKING: | |
723 | data |= PORT_LEARN_DISABLE; | |
4ce2a984 | 724 | if (port < dev->phy_port_cnt && |
e66f840c TH |
725 | p->stp_state == BR_STATE_DISABLED) |
726 | member = dev->host_mask | p->vid_member; | |
727 | break; | |
728 | default: | |
729 | dev_err(ds->dev, "invalid STP state: %d\n", state); | |
730 | return; | |
731 | } | |
732 | ||
733 | ksz_pwrite8(dev, port, P_STP_CTRL, data); | |
734 | p->stp_state = state; | |
e66f840c TH |
735 | /* Port membership may share register with STP state. */ |
736 | if (member >= 0 && member != p->member) | |
737 | ksz8795_cfg_port_member(dev, port, (u8)member); | |
738 | ||
739 | /* Check if forwarding needs to be updated. */ | |
740 | if (state != BR_STATE_FORWARDING) { | |
741 | if (dev->br_member & BIT(port)) | |
742 | dev->member &= ~BIT(port); | |
743 | } | |
744 | ||
745 | /* When topology has changed the function ksz_update_port_member | |
746 | * should be called to modify port forwarding behavior. | |
747 | */ | |
748 | if (forward != dev->member) | |
749 | ksz_update_port_member(dev, port); | |
750 | } | |
751 | ||
752 | static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port) | |
753 | { | |
241ed719 | 754 | u8 learn[DSA_MAX_PORTS]; |
e66f840c TH |
755 | int first, index, cnt; |
756 | struct ksz_port *p; | |
757 | ||
241ed719 | 758 | if ((uint)port < dev->port_cnt) { |
e66f840c TH |
759 | first = port; |
760 | cnt = port + 1; | |
761 | } else { | |
762 | /* Flush all ports. */ | |
763 | first = 0; | |
c9f4633b | 764 | cnt = dev->port_cnt; |
e66f840c TH |
765 | } |
766 | for (index = first; index < cnt; index++) { | |
767 | p = &dev->ports[index]; | |
768 | if (!p->on) | |
769 | continue; | |
770 | ksz_pread8(dev, index, P_STP_CTRL, &learn[index]); | |
771 | if (!(learn[index] & PORT_LEARN_DISABLE)) | |
772 | ksz_pwrite8(dev, index, P_STP_CTRL, | |
773 | learn[index] | PORT_LEARN_DISABLE); | |
774 | } | |
775 | ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true); | |
776 | for (index = first; index < cnt; index++) { | |
777 | p = &dev->ports[index]; | |
778 | if (!p->on) | |
779 | continue; | |
780 | if (!(learn[index] & PORT_LEARN_DISABLE)) | |
781 | ksz_pwrite8(dev, index, P_STP_CTRL, learn[index]); | |
782 | } | |
783 | } | |
784 | ||
785 | static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port, | |
89153ed6 VO |
786 | bool flag, |
787 | struct netlink_ext_ack *extack) | |
e66f840c TH |
788 | { |
789 | struct ksz_device *dev = ds->priv; | |
790 | ||
791 | ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag); | |
792 | ||
793 | return 0; | |
794 | } | |
795 | ||
1958d581 | 796 | static int ksz8795_port_vlan_add(struct dsa_switch *ds, int port, |
31046a5f VO |
797 | const struct switchdev_obj_port_vlan *vlan, |
798 | struct netlink_ext_ack *extack) | |
e66f840c TH |
799 | { |
800 | bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; | |
801 | struct ksz_device *dev = ds->priv; | |
b7a9e0da | 802 | u16 data, new_pvid = 0; |
e66f840c TH |
803 | u8 fid, member, valid; |
804 | ||
805 | ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged); | |
806 | ||
b7a9e0da VO |
807 | ksz8795_r_vlan_table(dev, vlan->vid, &data); |
808 | ksz8795_from_vlan(data, &fid, &member, &valid); | |
e66f840c | 809 | |
b7a9e0da VO |
810 | /* First time to setup the VLAN entry. */ |
811 | if (!valid) { | |
812 | /* Need to find a way to map VID to FID. */ | |
813 | fid = 1; | |
814 | valid = 1; | |
815 | } | |
816 | member |= BIT(port); | |
e66f840c | 817 | |
b7a9e0da VO |
818 | ksz8795_to_vlan(fid, member, valid, &data); |
819 | ksz8795_w_vlan_table(dev, vlan->vid, data); | |
e66f840c | 820 | |
b7a9e0da VO |
821 | /* change PVID */ |
822 | if (vlan->flags & BRIDGE_VLAN_INFO_PVID) | |
823 | new_pvid = vlan->vid; | |
e66f840c TH |
824 | |
825 | if (new_pvid) { | |
b7a9e0da VO |
826 | u16 vid; |
827 | ||
e66f840c TH |
828 | ksz_pread16(dev, port, REG_PORT_CTRL_VID, &vid); |
829 | vid &= 0xfff; | |
830 | vid |= new_pvid; | |
831 | ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, vid); | |
832 | } | |
1958d581 VO |
833 | |
834 | return 0; | |
e66f840c TH |
835 | } |
836 | ||
837 | static int ksz8795_port_vlan_del(struct dsa_switch *ds, int port, | |
838 | const struct switchdev_obj_port_vlan *vlan) | |
839 | { | |
840 | bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; | |
841 | struct ksz_device *dev = ds->priv; | |
b7a9e0da | 842 | u16 data, pvid, new_pvid = 0; |
e66f840c TH |
843 | u8 fid, member, valid; |
844 | ||
845 | ksz_pread16(dev, port, REG_PORT_CTRL_VID, &pvid); | |
846 | pvid = pvid & 0xFFF; | |
847 | ||
848 | ksz_port_cfg(dev, port, P_TAG_CTRL, PORT_REMOVE_TAG, untagged); | |
849 | ||
b7a9e0da VO |
850 | ksz8795_r_vlan_table(dev, vlan->vid, &data); |
851 | ksz8795_from_vlan(data, &fid, &member, &valid); | |
e66f840c | 852 | |
b7a9e0da | 853 | member &= ~BIT(port); |
e66f840c | 854 | |
b7a9e0da VO |
855 | /* Invalidate the entry if no more member. */ |
856 | if (!member) { | |
857 | fid = 0; | |
858 | valid = 0; | |
859 | } | |
e66f840c | 860 | |
b7a9e0da VO |
861 | if (pvid == vlan->vid) |
862 | new_pvid = 1; | |
e66f840c | 863 | |
b7a9e0da VO |
864 | ksz8795_to_vlan(fid, member, valid, &data); |
865 | ksz8795_w_vlan_table(dev, vlan->vid, data); | |
e66f840c TH |
866 | |
867 | if (new_pvid != pvid) | |
868 | ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, pvid); | |
869 | ||
870 | return 0; | |
871 | } | |
872 | ||
873 | static int ksz8795_port_mirror_add(struct dsa_switch *ds, int port, | |
874 | struct dsa_mall_mirror_tc_entry *mirror, | |
875 | bool ingress) | |
876 | { | |
877 | struct ksz_device *dev = ds->priv; | |
878 | ||
879 | if (ingress) { | |
880 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); | |
881 | dev->mirror_rx |= BIT(port); | |
882 | } else { | |
883 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); | |
884 | dev->mirror_tx |= BIT(port); | |
885 | } | |
886 | ||
887 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_SNIFFER, false); | |
888 | ||
889 | /* configure mirror port */ | |
890 | if (dev->mirror_rx || dev->mirror_tx) | |
891 | ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, | |
892 | PORT_MIRROR_SNIFFER, true); | |
893 | ||
894 | return 0; | |
895 | } | |
896 | ||
897 | static void ksz8795_port_mirror_del(struct dsa_switch *ds, int port, | |
898 | struct dsa_mall_mirror_tc_entry *mirror) | |
899 | { | |
900 | struct ksz_device *dev = ds->priv; | |
901 | u8 data; | |
902 | ||
903 | if (mirror->ingress) { | |
904 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); | |
905 | dev->mirror_rx &= ~BIT(port); | |
906 | } else { | |
907 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); | |
908 | dev->mirror_tx &= ~BIT(port); | |
909 | } | |
910 | ||
911 | ksz_pread8(dev, port, P_MIRROR_CTRL, &data); | |
912 | ||
913 | if (!dev->mirror_rx && !dev->mirror_tx) | |
914 | ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, | |
915 | PORT_MIRROR_SNIFFER, false); | |
916 | } | |
917 | ||
918 | static void ksz8795_port_setup(struct ksz_device *dev, int port, bool cpu_port) | |
919 | { | |
920 | struct ksz_port *p = &dev->ports[port]; | |
921 | u8 data8, member; | |
922 | ||
923 | /* enable broadcast storm limit */ | |
924 | ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); | |
925 | ||
926 | ksz8795_set_prio_queue(dev, port, 4); | |
927 | ||
928 | /* disable DiffServ priority */ | |
929 | ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_ENABLE, false); | |
930 | ||
931 | /* replace priority */ | |
932 | ksz_port_cfg(dev, port, P_802_1P_CTRL, PORT_802_1P_REMAPPING, false); | |
933 | ||
934 | /* enable 802.1p priority */ | |
935 | ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true); | |
936 | ||
937 | if (cpu_port) { | |
edecfa98 HG |
938 | if (!p->interface && dev->compat_interface) { |
939 | dev_warn(dev->dev, | |
940 | "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. " | |
941 | "Please update your device tree.\n", | |
942 | port); | |
943 | p->interface = dev->compat_interface; | |
944 | } | |
945 | ||
e66f840c TH |
946 | /* Configure MII interface for proper network communication. */ |
947 | ksz_read8(dev, REG_PORT_5_CTRL_6, &data8); | |
948 | data8 &= ~PORT_INTERFACE_TYPE; | |
949 | data8 &= ~PORT_GMII_1GPS_MODE; | |
edecfa98 | 950 | switch (p->interface) { |
e66f840c TH |
951 | case PHY_INTERFACE_MODE_MII: |
952 | p->phydev.speed = SPEED_100; | |
953 | break; | |
954 | case PHY_INTERFACE_MODE_RMII: | |
955 | data8 |= PORT_INTERFACE_RMII; | |
956 | p->phydev.speed = SPEED_100; | |
957 | break; | |
958 | case PHY_INTERFACE_MODE_GMII: | |
959 | data8 |= PORT_GMII_1GPS_MODE; | |
960 | data8 |= PORT_INTERFACE_GMII; | |
961 | p->phydev.speed = SPEED_1000; | |
962 | break; | |
963 | default: | |
964 | data8 &= ~PORT_RGMII_ID_IN_ENABLE; | |
965 | data8 &= ~PORT_RGMII_ID_OUT_ENABLE; | |
edecfa98 HG |
966 | if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || |
967 | p->interface == PHY_INTERFACE_MODE_RGMII_RXID) | |
e66f840c | 968 | data8 |= PORT_RGMII_ID_IN_ENABLE; |
edecfa98 HG |
969 | if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || |
970 | p->interface == PHY_INTERFACE_MODE_RGMII_TXID) | |
e66f840c TH |
971 | data8 |= PORT_RGMII_ID_OUT_ENABLE; |
972 | data8 |= PORT_GMII_1GPS_MODE; | |
973 | data8 |= PORT_INTERFACE_RGMII; | |
974 | p->phydev.speed = SPEED_1000; | |
975 | break; | |
976 | } | |
977 | ksz_write8(dev, REG_PORT_5_CTRL_6, data8); | |
978 | p->phydev.duplex = 1; | |
979 | ||
980 | member = dev->port_mask; | |
e66f840c TH |
981 | } else { |
982 | member = dev->host_mask | p->vid_member; | |
e66f840c TH |
983 | } |
984 | ksz8795_cfg_port_member(dev, port, member); | |
985 | } | |
986 | ||
987 | static void ksz8795_config_cpu_port(struct dsa_switch *ds) | |
988 | { | |
989 | struct ksz_device *dev = ds->priv; | |
990 | struct ksz_port *p; | |
991 | u8 remote; | |
992 | int i; | |
993 | ||
e66f840c TH |
994 | /* Switch marks the maximum frame with extra byte as oversize. */ |
995 | ksz_cfg(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, true); | |
996 | ksz_cfg(dev, S_TAIL_TAG_CTRL, SW_TAIL_TAG_ENABLE, true); | |
997 | ||
998 | p = &dev->ports[dev->cpu_port]; | |
999 | p->vid_member = dev->port_mask; | |
1000 | p->on = 1; | |
1001 | ||
1002 | ksz8795_port_setup(dev, dev->cpu_port, true); | |
1003 | dev->member = dev->host_mask; | |
1004 | ||
4ce2a984 | 1005 | for (i = 0; i < dev->phy_port_cnt; i++) { |
e66f840c TH |
1006 | p = &dev->ports[i]; |
1007 | ||
1008 | /* Initialize to non-zero so that ksz_cfg_port_member() will | |
1009 | * be called. | |
1010 | */ | |
1011 | p->vid_member = BIT(i); | |
1012 | p->member = dev->port_mask; | |
1013 | ksz8795_port_stp_state_set(ds, i, BR_STATE_DISABLED); | |
1014 | ||
1015 | /* Last port may be disabled. */ | |
4ce2a984 | 1016 | if (i == dev->phy_port_cnt) |
e66f840c TH |
1017 | break; |
1018 | p->on = 1; | |
1019 | p->phy = 1; | |
1020 | } | |
1021 | for (i = 0; i < dev->phy_port_cnt; i++) { | |
1022 | p = &dev->ports[i]; | |
1023 | if (!p->on) | |
1024 | continue; | |
1025 | ksz_pread8(dev, i, P_REMOTE_STATUS, &remote); | |
1026 | if (remote & PORT_FIBER_MODE) | |
1027 | p->fiber = 1; | |
1028 | if (p->fiber) | |
1029 | ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL, | |
1030 | true); | |
1031 | else | |
1032 | ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL, | |
1033 | false); | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | static int ksz8795_setup(struct dsa_switch *ds) | |
1038 | { | |
1039 | struct ksz_device *dev = ds->priv; | |
1040 | struct alu_struct alu; | |
1041 | int i, ret = 0; | |
1042 | ||
1043 | dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), | |
1044 | dev->num_vlans, GFP_KERNEL); | |
1045 | if (!dev->vlan_cache) | |
1046 | return -ENOMEM; | |
1047 | ||
1048 | ret = ksz8795_reset_switch(dev); | |
1049 | if (ret) { | |
1050 | dev_err(ds->dev, "failed to reset switch\n"); | |
1051 | return ret; | |
1052 | } | |
1053 | ||
1054 | ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true); | |
1055 | ||
1056 | /* Enable automatic fast aging when link changed detected. */ | |
1057 | ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true); | |
1058 | ||
1059 | /* Enable aggressive back off algorithm in half duplex mode. */ | |
1060 | regmap_update_bits(dev->regmap[0], REG_SW_CTRL_1, | |
1061 | SW_AGGR_BACKOFF, SW_AGGR_BACKOFF); | |
1062 | ||
1063 | /* | |
1064 | * Make sure unicast VLAN boundary is set as default and | |
1065 | * enable no excessive collision drop. | |
1066 | */ | |
1067 | regmap_update_bits(dev->regmap[0], REG_SW_CTRL_2, | |
1068 | UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP, | |
1069 | UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP); | |
1070 | ||
1071 | ksz8795_config_cpu_port(ds); | |
1072 | ||
1073 | ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true); | |
1074 | ||
1075 | ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false); | |
1076 | ||
1077 | ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); | |
1078 | ||
1079 | /* set broadcast storm protection 10% rate */ | |
1080 | regmap_update_bits(dev->regmap[1], S_REPLACE_VID_CTRL, | |
1081 | BROADCAST_STORM_RATE, | |
1082 | (BROADCAST_STORM_VALUE * | |
1083 | BROADCAST_STORM_PROT_RATE) / 100); | |
1084 | ||
02ffbb02 | 1085 | for (i = 0; i < (dev->num_vlans / 4); i++) |
e66f840c TH |
1086 | ksz8795_r_vlan_entries(dev, i); |
1087 | ||
1088 | /* Setup STP address for STP operation. */ | |
1089 | memset(&alu, 0, sizeof(alu)); | |
1090 | ether_addr_copy(alu.mac, eth_stp_addr); | |
1091 | alu.is_static = true; | |
1092 | alu.is_override = true; | |
1093 | alu.port_forward = dev->host_mask; | |
1094 | ||
1095 | ksz8795_w_sta_mac_table(dev, 0, &alu); | |
1096 | ||
1097 | ksz_init_mib_timer(dev); | |
1098 | ||
0ee2af4e VO |
1099 | ds->configure_vlan_while_not_filtering = false; |
1100 | ||
e66f840c TH |
1101 | return 0; |
1102 | } | |
1103 | ||
1104 | static const struct dsa_switch_ops ksz8795_switch_ops = { | |
1105 | .get_tag_protocol = ksz8795_get_tag_protocol, | |
1106 | .setup = ksz8795_setup, | |
1107 | .phy_read = ksz_phy_read16, | |
1108 | .phy_write = ksz_phy_write16, | |
143a102e | 1109 | .phylink_mac_link_down = ksz_mac_link_down, |
e66f840c | 1110 | .port_enable = ksz_enable_port, |
e66f840c TH |
1111 | .get_strings = ksz8795_get_strings, |
1112 | .get_ethtool_stats = ksz_get_ethtool_stats, | |
1113 | .get_sset_count = ksz_sset_count, | |
1114 | .port_bridge_join = ksz_port_bridge_join, | |
1115 | .port_bridge_leave = ksz_port_bridge_leave, | |
1116 | .port_stp_state_set = ksz8795_port_stp_state_set, | |
1117 | .port_fast_age = ksz_port_fast_age, | |
1118 | .port_vlan_filtering = ksz8795_port_vlan_filtering, | |
e66f840c TH |
1119 | .port_vlan_add = ksz8795_port_vlan_add, |
1120 | .port_vlan_del = ksz8795_port_vlan_del, | |
1121 | .port_fdb_dump = ksz_port_fdb_dump, | |
e66f840c TH |
1122 | .port_mdb_add = ksz_port_mdb_add, |
1123 | .port_mdb_del = ksz_port_mdb_del, | |
1124 | .port_mirror_add = ksz8795_port_mirror_add, | |
1125 | .port_mirror_del = ksz8795_port_mirror_del, | |
1126 | }; | |
1127 | ||
1128 | static u32 ksz8795_get_port_addr(int port, int offset) | |
1129 | { | |
1130 | return PORT_CTRL_ADDR(port, offset); | |
1131 | } | |
1132 | ||
1133 | static int ksz8795_switch_detect(struct ksz_device *dev) | |
1134 | { | |
1135 | u8 id1, id2; | |
1136 | u16 id16; | |
1137 | int ret; | |
1138 | ||
1139 | /* read chip id */ | |
1140 | ret = ksz_read16(dev, REG_CHIP_ID0, &id16); | |
1141 | if (ret) | |
1142 | return ret; | |
1143 | ||
1144 | id1 = id16 >> 8; | |
1145 | id2 = id16 & SW_CHIP_ID_M; | |
1146 | if (id1 != FAMILY_ID || | |
1147 | (id2 != CHIP_ID_94 && id2 != CHIP_ID_95)) | |
1148 | return -ENODEV; | |
1149 | ||
e66f840c TH |
1150 | if (id2 == CHIP_ID_95) { |
1151 | u8 val; | |
1152 | ||
1153 | id2 = 0x95; | |
1154 | ksz_read8(dev, REG_PORT_1_STATUS_0, &val); | |
1155 | if (val & PORT_FIBER_MODE) | |
1156 | id2 = 0x65; | |
1157 | } else if (id2 == CHIP_ID_94) { | |
e66f840c TH |
1158 | id2 = 0x94; |
1159 | } | |
1160 | id16 &= ~0xff; | |
1161 | id16 |= id2; | |
1162 | dev->chip_id = id16; | |
1163 | ||
e66f840c TH |
1164 | return 0; |
1165 | } | |
1166 | ||
1167 | struct ksz_chip_data { | |
1168 | u16 chip_id; | |
1169 | const char *dev_name; | |
1170 | int num_vlans; | |
1171 | int num_alus; | |
1172 | int num_statics; | |
1173 | int cpu_ports; | |
1174 | int port_cnt; | |
1175 | }; | |
1176 | ||
1177 | static const struct ksz_chip_data ksz8795_switch_chips[] = { | |
1178 | { | |
1179 | .chip_id = 0x8795, | |
1180 | .dev_name = "KSZ8795", | |
1181 | .num_vlans = 4096, | |
1182 | .num_alus = 0, | |
1183 | .num_statics = 8, | |
1184 | .cpu_ports = 0x10, /* can be configured as cpu port */ | |
94374dd1 | 1185 | .port_cnt = 5, /* total cpu and user ports */ |
e66f840c TH |
1186 | }, |
1187 | { | |
c369d7fc MV |
1188 | /* |
1189 | * WARNING | |
1190 | * ======= | |
1191 | * KSZ8794 is similar to KSZ8795, except the port map | |
1192 | * contains a gap between external and CPU ports, the | |
1193 | * port map is NOT continuous. The per-port register | |
1194 | * map is shifted accordingly too, i.e. registers at | |
1195 | * offset 0x40 are NOT used on KSZ8794 and they ARE | |
1196 | * used on KSZ8795 for external port 3. | |
1197 | * external cpu | |
1198 | * KSZ8794 0,1,2 4 | |
1199 | * KSZ8795 0,1,2,3 4 | |
1200 | * KSZ8765 0,1,2,3 4 | |
1201 | */ | |
e66f840c TH |
1202 | .chip_id = 0x8794, |
1203 | .dev_name = "KSZ8794", | |
1204 | .num_vlans = 4096, | |
1205 | .num_alus = 0, | |
1206 | .num_statics = 8, | |
1207 | .cpu_ports = 0x10, /* can be configured as cpu port */ | |
94374dd1 | 1208 | .port_cnt = 4, /* total cpu and user ports */ |
e66f840c TH |
1209 | }, |
1210 | { | |
1211 | .chip_id = 0x8765, | |
1212 | .dev_name = "KSZ8765", | |
1213 | .num_vlans = 4096, | |
1214 | .num_alus = 0, | |
1215 | .num_statics = 8, | |
1216 | .cpu_ports = 0x10, /* can be configured as cpu port */ | |
94374dd1 | 1217 | .port_cnt = 5, /* total cpu and user ports */ |
e66f840c TH |
1218 | }, |
1219 | }; | |
1220 | ||
1221 | static int ksz8795_switch_init(struct ksz_device *dev) | |
1222 | { | |
1223 | int i; | |
1224 | ||
e66f840c TH |
1225 | dev->ds->ops = &ksz8795_switch_ops; |
1226 | ||
1227 | for (i = 0; i < ARRAY_SIZE(ksz8795_switch_chips); i++) { | |
1228 | const struct ksz_chip_data *chip = &ksz8795_switch_chips[i]; | |
1229 | ||
1230 | if (dev->chip_id == chip->chip_id) { | |
1231 | dev->name = chip->dev_name; | |
1232 | dev->num_vlans = chip->num_vlans; | |
1233 | dev->num_alus = chip->num_alus; | |
1234 | dev->num_statics = chip->num_statics; | |
c369d7fc MV |
1235 | dev->port_cnt = fls(chip->cpu_ports); |
1236 | dev->cpu_port = fls(chip->cpu_ports) - 1; | |
1237 | dev->phy_port_cnt = dev->port_cnt - 1; | |
e66f840c | 1238 | dev->cpu_ports = chip->cpu_ports; |
c369d7fc MV |
1239 | dev->host_mask = chip->cpu_ports; |
1240 | dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | | |
1241 | chip->cpu_ports; | |
e66f840c TH |
1242 | break; |
1243 | } | |
1244 | } | |
1245 | ||
1246 | /* no switch found */ | |
1247 | if (!dev->cpu_ports) | |
1248 | return -ENODEV; | |
1249 | ||
31b62c78 | 1250 | dev->reg_mib_cnt = KSZ8795_COUNTER_NUM; |
65fe1acf | 1251 | dev->mib_cnt = ARRAY_SIZE(mib_names); |
e66f840c | 1252 | |
c9f4633b MG |
1253 | dev->ports = devm_kzalloc(dev->dev, |
1254 | dev->port_cnt * sizeof(struct ksz_port), | |
e66f840c TH |
1255 | GFP_KERNEL); |
1256 | if (!dev->ports) | |
1257 | return -ENOMEM; | |
c9f4633b | 1258 | for (i = 0; i < dev->port_cnt; i++) { |
e66f840c TH |
1259 | mutex_init(&dev->ports[i].mib.cnt_mutex); |
1260 | dev->ports[i].mib.counters = | |
1261 | devm_kzalloc(dev->dev, | |
1262 | sizeof(u64) * | |
65fe1acf | 1263 | (dev->mib_cnt + 1), |
e66f840c TH |
1264 | GFP_KERNEL); |
1265 | if (!dev->ports[i].mib.counters) | |
1266 | return -ENOMEM; | |
1267 | } | |
1268 | ||
af199a1a | 1269 | /* set the real number of ports */ |
94374dd1 | 1270 | dev->ds->num_ports = dev->port_cnt; |
af199a1a | 1271 | |
e66f840c TH |
1272 | return 0; |
1273 | } | |
1274 | ||
1275 | static void ksz8795_switch_exit(struct ksz_device *dev) | |
1276 | { | |
1277 | ksz8795_reset_switch(dev); | |
1278 | } | |
1279 | ||
1280 | static const struct ksz_dev_ops ksz8795_dev_ops = { | |
1281 | .get_port_addr = ksz8795_get_port_addr, | |
1282 | .cfg_port_member = ksz8795_cfg_port_member, | |
1283 | .flush_dyn_mac_table = ksz8795_flush_dyn_mac_table, | |
1284 | .port_setup = ksz8795_port_setup, | |
1285 | .r_phy = ksz8795_r_phy, | |
1286 | .w_phy = ksz8795_w_phy, | |
1287 | .r_dyn_mac_table = ksz8795_r_dyn_mac_table, | |
1288 | .r_sta_mac_table = ksz8795_r_sta_mac_table, | |
1289 | .w_sta_mac_table = ksz8795_w_sta_mac_table, | |
1290 | .r_mib_cnt = ksz8795_r_mib_cnt, | |
1291 | .r_mib_pkt = ksz8795_r_mib_pkt, | |
1292 | .freeze_mib = ksz8795_freeze_mib, | |
1293 | .port_init_cnt = ksz8795_port_init_cnt, | |
1294 | .shutdown = ksz8795_reset_switch, | |
1295 | .detect = ksz8795_switch_detect, | |
1296 | .init = ksz8795_switch_init, | |
1297 | .exit = ksz8795_switch_exit, | |
1298 | }; | |
1299 | ||
1300 | int ksz8795_switch_register(struct ksz_device *dev) | |
1301 | { | |
1302 | return ksz_switch_register(dev, &ksz8795_dev_ops); | |
1303 | } | |
1304 | EXPORT_SYMBOL(ksz8795_switch_register); | |
1305 | ||
1306 | MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); | |
1307 | MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver"); | |
1308 | MODULE_LICENSE("GPL"); |