Commit | Line | Data |
---|---|---|
c2e86691 TH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Microchip KSZ9477 switch driver main logic | |
4 | * | |
42fc6a4c | 5 | * Copyright (C) 2017-2019 Microchip Technology Inc. |
c2e86691 TH |
6 | */ |
7 | ||
c2e86691 TH |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> | |
7c6ff470 | 10 | #include <linux/iopoll.h> |
c2e86691 TH |
11 | #include <linux/platform_data/microchip-ksz.h> |
12 | #include <linux/phy.h> | |
c2e86691 | 13 | #include <linux/if_bridge.h> |
e18058ea | 14 | #include <linux/if_vlan.h> |
c2e86691 TH |
15 | #include <net/dsa.h> |
16 | #include <net/switchdev.h> | |
17 | ||
84bd1908 | 18 | #include "ksz9477_reg.h" |
7c6ff470 | 19 | #include "ksz_common.h" |
c2e86691 | 20 | |
8c29bebb TH |
21 | /* Used with variable features to indicate capabilities. */ |
22 | #define GBIT_SUPPORT BIT(0) | |
23 | #define NEW_XMII BIT(1) | |
24 | #define IS_9893 BIT(2) | |
25 | ||
bafea01f MV |
26 | static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) |
27 | { | |
d4bcd99c | 28 | regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); |
bafea01f MV |
29 | } |
30 | ||
31 | static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, | |
32 | bool set) | |
33 | { | |
d4bcd99c MV |
34 | regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), |
35 | bits, set ? bits : 0); | |
bafea01f MV |
36 | } |
37 | ||
c2e86691 TH |
38 | static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) |
39 | { | |
d4bcd99c | 40 | regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0); |
c2e86691 TH |
41 | } |
42 | ||
43 | static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, | |
44 | u32 bits, bool set) | |
45 | { | |
d4bcd99c MV |
46 | regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset), |
47 | bits, set ? bits : 0); | |
c2e86691 TH |
48 | } |
49 | ||
e18058ea OR |
50 | static int ksz9477_change_mtu(struct dsa_switch *ds, int port, int mtu) |
51 | { | |
52 | struct ksz_device *dev = ds->priv; | |
53 | u16 frame_size, max_frame = 0; | |
54 | int i; | |
55 | ||
56 | frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; | |
57 | ||
58 | /* Cache the per-port MTU setting */ | |
59 | dev->ports[port].max_frame = frame_size; | |
60 | ||
462d5250 | 61 | for (i = 0; i < dev->info->port_cnt; i++) |
e18058ea OR |
62 | max_frame = max(max_frame, dev->ports[i].max_frame); |
63 | ||
64 | return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, | |
65 | REG_SW_MTU_MASK, max_frame); | |
66 | } | |
67 | ||
68 | static int ksz9477_max_mtu(struct dsa_switch *ds, int port) | |
69 | { | |
70 | return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; | |
71 | } | |
72 | ||
0f9c36e3 | 73 | static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) |
c2e86691 | 74 | { |
0f9c36e3 | 75 | unsigned int val; |
c2e86691 | 76 | |
0f9c36e3 MV |
77 | return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL, |
78 | val, !(val & VLAN_START), 10, 1000); | |
c2e86691 TH |
79 | } |
80 | ||
81 | static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid, | |
82 | u32 *vlan_table) | |
83 | { | |
84 | int ret; | |
85 | ||
86 | mutex_lock(&dev->vlan_mutex); | |
87 | ||
88 | ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); | |
89 | ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START); | |
90 | ||
91 | /* wait to be cleared */ | |
0f9c36e3 MV |
92 | ret = ksz9477_wait_vlan_ctrl_ready(dev); |
93 | if (ret) { | |
c2e86691 TH |
94 | dev_dbg(dev->dev, "Failed to read vlan table\n"); |
95 | goto exit; | |
96 | } | |
97 | ||
98 | ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &vlan_table[0]); | |
99 | ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, &vlan_table[1]); | |
100 | ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, &vlan_table[2]); | |
101 | ||
102 | ksz_write8(dev, REG_SW_VLAN_CTRL, 0); | |
103 | ||
104 | exit: | |
105 | mutex_unlock(&dev->vlan_mutex); | |
106 | ||
107 | return ret; | |
108 | } | |
109 | ||
110 | static int ksz9477_set_vlan_table(struct ksz_device *dev, u16 vid, | |
111 | u32 *vlan_table) | |
112 | { | |
113 | int ret; | |
114 | ||
115 | mutex_lock(&dev->vlan_mutex); | |
116 | ||
117 | ksz_write32(dev, REG_SW_VLAN_ENTRY__4, vlan_table[0]); | |
118 | ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, vlan_table[1]); | |
119 | ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_table[2]); | |
120 | ||
121 | ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M); | |
122 | ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE); | |
123 | ||
124 | /* wait to be cleared */ | |
0f9c36e3 MV |
125 | ret = ksz9477_wait_vlan_ctrl_ready(dev); |
126 | if (ret) { | |
c2e86691 TH |
127 | dev_dbg(dev->dev, "Failed to write vlan table\n"); |
128 | goto exit; | |
129 | } | |
130 | ||
131 | ksz_write8(dev, REG_SW_VLAN_CTRL, 0); | |
132 | ||
133 | /* update vlan cache table */ | |
134 | dev->vlan_cache[vid].table[0] = vlan_table[0]; | |
135 | dev->vlan_cache[vid].table[1] = vlan_table[1]; | |
136 | dev->vlan_cache[vid].table[2] = vlan_table[2]; | |
137 | ||
138 | exit: | |
139 | mutex_unlock(&dev->vlan_mutex); | |
140 | ||
141 | return ret; | |
142 | } | |
143 | ||
144 | static void ksz9477_read_table(struct ksz_device *dev, u32 *table) | |
145 | { | |
146 | ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]); | |
147 | ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]); | |
148 | ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]); | |
149 | ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]); | |
150 | } | |
151 | ||
152 | static void ksz9477_write_table(struct ksz_device *dev, u32 *table) | |
153 | { | |
154 | ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]); | |
155 | ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]); | |
156 | ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]); | |
157 | ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]); | |
158 | } | |
159 | ||
ef534195 | 160 | static int ksz9477_wait_alu_ready(struct ksz_device *dev) |
c2e86691 | 161 | { |
ef534195 | 162 | unsigned int val; |
c2e86691 | 163 | |
ef534195 MV |
164 | return regmap_read_poll_timeout(dev->regmap[2], REG_SW_ALU_CTRL__4, |
165 | val, !(val & ALU_START), 10, 1000); | |
c2e86691 TH |
166 | } |
167 | ||
3371efbc | 168 | static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev) |
c2e86691 | 169 | { |
3371efbc | 170 | unsigned int val; |
c2e86691 | 171 | |
3371efbc MV |
172 | return regmap_read_poll_timeout(dev->regmap[2], |
173 | REG_SW_ALU_STAT_CTRL__4, | |
174 | val, !(val & ALU_STAT_START), | |
175 | 10, 1000); | |
c2e86691 TH |
176 | } |
177 | ||
178 | static int ksz9477_reset_switch(struct ksz_device *dev) | |
179 | { | |
180 | u8 data8; | |
c2e86691 TH |
181 | u32 data32; |
182 | ||
183 | /* reset switch */ | |
184 | ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true); | |
185 | ||
186 | /* turn off SPI DO Edge select */ | |
ee353e45 MV |
187 | regmap_update_bits(dev->regmap[0], REG_SW_GLOBAL_SERIAL_CTRL_0, |
188 | SPI_AUTO_EDGE_DETECTION, 0); | |
c2e86691 TH |
189 | |
190 | /* default configuration */ | |
191 | ksz_read8(dev, REG_SW_LUE_CTRL_1, &data8); | |
192 | data8 = SW_AGING_ENABLE | SW_LINK_AUTO_AGING | | |
193 | SW_SRC_ADDR_FILTER | SW_FLUSH_STP_TABLE | SW_FLUSH_MSTP_TABLE; | |
194 | ksz_write8(dev, REG_SW_LUE_CTRL_1, data8); | |
195 | ||
196 | /* disable interrupts */ | |
197 | ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK); | |
198 | ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F); | |
199 | ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32); | |
200 | ||
201 | /* set broadcast storm protection 10% rate */ | |
ee353e45 MV |
202 | regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2, |
203 | BROADCAST_STORM_RATE, | |
204 | (BROADCAST_STORM_VALUE * | |
205 | BROADCAST_STORM_PROT_RATE) / 100); | |
c2e86691 | 206 | |
48bf8b8a RH |
207 | data8 = SW_ENABLE_REFCLKO; |
208 | if (dev->synclko_disable) | |
209 | data8 = 0; | |
210 | else if (dev->synclko_125) | |
211 | data8 = SW_ENABLE_REFCLKO | SW_REFCLKO_IS_125MHZ; | |
212 | ksz_write8(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1, data8); | |
79c8bd15 | 213 | |
c2e86691 TH |
214 | return 0; |
215 | } | |
216 | ||
7c6ff470 TH |
217 | static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, |
218 | u64 *cnt) | |
219 | { | |
7c6ff470 | 220 | struct ksz_port *p = &dev->ports[port]; |
1c1eb580 | 221 | unsigned int val; |
7c6ff470 TH |
222 | u32 data; |
223 | int ret; | |
224 | ||
225 | /* retain the flush/freeze bit */ | |
226 | data = p->freeze ? MIB_COUNTER_FLUSH_FREEZE : 0; | |
227 | data |= MIB_COUNTER_READ; | |
228 | data |= (addr << MIB_COUNTER_INDEX_S); | |
229 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); | |
230 | ||
1c1eb580 MV |
231 | ret = regmap_read_poll_timeout(dev->regmap[2], |
232 | PORT_CTRL_ADDR(port, REG_PORT_MIB_CTRL_STAT__4), | |
233 | val, !(val & MIB_COUNTER_READ), 10, 1000); | |
7c6ff470 | 234 | /* failed to read MIB. get out of loop */ |
1c1eb580 | 235 | if (ret) { |
7c6ff470 TH |
236 | dev_dbg(dev->dev, "Failed to get MIB\n"); |
237 | return; | |
238 | } | |
239 | ||
240 | /* count resets upon read */ | |
241 | ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data); | |
242 | *cnt += data; | |
243 | } | |
244 | ||
245 | static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr, | |
246 | u64 *dropped, u64 *cnt) | |
247 | { | |
a530e6f2 | 248 | addr = dev->info->mib_names[addr].index; |
7c6ff470 TH |
249 | ksz9477_r_mib_cnt(dev, port, addr, cnt); |
250 | } | |
251 | ||
252 | static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze) | |
253 | { | |
254 | u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0; | |
255 | struct ksz_port *p = &dev->ports[port]; | |
256 | ||
257 | /* enable/disable the port for flush/freeze function */ | |
258 | mutex_lock(&p->mib.cnt_mutex); | |
259 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, val); | |
260 | ||
261 | /* used by MIB counter reading code to know freeze is enabled */ | |
262 | p->freeze = freeze; | |
263 | mutex_unlock(&p->mib.cnt_mutex); | |
264 | } | |
265 | ||
266 | static void ksz9477_port_init_cnt(struct ksz_device *dev, int port) | |
267 | { | |
268 | struct ksz_port_mib *mib = &dev->ports[port].mib; | |
269 | ||
270 | /* flush all enabled port MIB counters */ | |
271 | mutex_lock(&mib->cnt_mutex); | |
272 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, | |
273 | MIB_COUNTER_FLUSH_FREEZE); | |
274 | ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH); | |
275 | ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0); | |
276 | mutex_unlock(&mib->cnt_mutex); | |
7c6ff470 TH |
277 | } |
278 | ||
c2e86691 TH |
279 | static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg) |
280 | { | |
281 | struct ksz_device *dev = ds->priv; | |
282 | u16 val = 0xffff; | |
283 | ||
284 | /* No real PHY after this. Simulate the PHY. | |
285 | * A fixed PHY can be setup in the device tree, but this function is | |
286 | * still called for that port during initialization. | |
287 | * For RGMII PHY there is no way to access it so the fixed PHY should | |
288 | * be used. For SGMII PHY the supporting code will be added later. | |
289 | */ | |
290 | if (addr >= dev->phy_port_cnt) { | |
291 | struct ksz_port *p = &dev->ports[addr]; | |
292 | ||
293 | switch (reg) { | |
294 | case MII_BMCR: | |
295 | val = 0x1140; | |
296 | break; | |
297 | case MII_BMSR: | |
298 | val = 0x796d; | |
299 | break; | |
300 | case MII_PHYSID1: | |
301 | val = 0x0022; | |
302 | break; | |
303 | case MII_PHYSID2: | |
304 | val = 0x1631; | |
305 | break; | |
306 | case MII_ADVERTISE: | |
307 | val = 0x05e1; | |
308 | break; | |
309 | case MII_LPA: | |
310 | val = 0xc5e1; | |
311 | break; | |
312 | case MII_CTRL1000: | |
313 | val = 0x0700; | |
314 | break; | |
315 | case MII_STAT1000: | |
316 | if (p->phydev.speed == SPEED_1000) | |
317 | val = 0x3800; | |
318 | else | |
319 | val = 0; | |
320 | break; | |
321 | } | |
322 | } else { | |
323 | ksz_pread16(dev, addr, 0x100 + (reg << 1), &val); | |
324 | } | |
325 | ||
326 | return val; | |
327 | } | |
328 | ||
329 | static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg, | |
330 | u16 val) | |
331 | { | |
332 | struct ksz_device *dev = ds->priv; | |
333 | ||
334 | /* No real PHY after this. */ | |
335 | if (addr >= dev->phy_port_cnt) | |
336 | return 0; | |
8c29bebb TH |
337 | |
338 | /* No gigabit support. Do not write to this register. */ | |
339 | if (!(dev->features & GBIT_SUPPORT) && reg == MII_CTRL1000) | |
340 | return 0; | |
c2e86691 TH |
341 | ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
c2e86691 TH |
346 | static void ksz9477_cfg_port_member(struct ksz_device *dev, int port, |
347 | u8 member) | |
348 | { | |
349 | ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member); | |
c2e86691 TH |
350 | } |
351 | ||
352 | static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port, | |
353 | u8 state) | |
354 | { | |
de6dd626 | 355 | ksz_port_stp_state_set(ds, port, state, P_STP_CTRL); |
c2e86691 TH |
356 | } |
357 | ||
358 | static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) | |
359 | { | |
360 | u8 data; | |
361 | ||
ee353e45 MV |
362 | regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2, |
363 | SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S, | |
364 | SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S); | |
365 | ||
462d5250 | 366 | if (port < dev->info->port_cnt) { |
c2e86691 TH |
367 | /* flush individual port */ |
368 | ksz_pread8(dev, port, P_STP_CTRL, &data); | |
369 | if (!(data & PORT_LEARN_DISABLE)) | |
370 | ksz_pwrite8(dev, port, P_STP_CTRL, | |
371 | data | PORT_LEARN_DISABLE); | |
372 | ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true); | |
373 | ksz_pwrite8(dev, port, P_STP_CTRL, data); | |
374 | } else { | |
375 | /* flush all */ | |
376 | ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_STP_TABLE, true); | |
377 | } | |
378 | } | |
379 | ||
380 | static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port, | |
89153ed6 VO |
381 | bool flag, |
382 | struct netlink_ext_ack *extack) | |
c2e86691 TH |
383 | { |
384 | struct ksz_device *dev = ds->priv; | |
385 | ||
386 | if (flag) { | |
387 | ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, | |
388 | PORT_VLAN_LOOKUP_VID_0, true); | |
c2e86691 TH |
389 | ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true); |
390 | } else { | |
391 | ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false); | |
c2e86691 TH |
392 | ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL, |
393 | PORT_VLAN_LOOKUP_VID_0, false); | |
394 | } | |
395 | ||
396 | return 0; | |
397 | } | |
398 | ||
1958d581 | 399 | static int ksz9477_port_vlan_add(struct dsa_switch *ds, int port, |
31046a5f VO |
400 | const struct switchdev_obj_port_vlan *vlan, |
401 | struct netlink_ext_ack *extack) | |
c2e86691 TH |
402 | { |
403 | struct ksz_device *dev = ds->priv; | |
404 | u32 vlan_table[3]; | |
c2e86691 | 405 | bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; |
1958d581 | 406 | int err; |
c2e86691 | 407 | |
1958d581 VO |
408 | err = ksz9477_get_vlan_table(dev, vlan->vid, vlan_table); |
409 | if (err) { | |
31046a5f | 410 | NL_SET_ERR_MSG_MOD(extack, "Failed to get vlan table"); |
1958d581 | 411 | return err; |
b7a9e0da | 412 | } |
c2e86691 | 413 | |
b7a9e0da VO |
414 | vlan_table[0] = VLAN_VALID | (vlan->vid & VLAN_FID_M); |
415 | if (untagged) | |
416 | vlan_table[1] |= BIT(port); | |
417 | else | |
418 | vlan_table[1] &= ~BIT(port); | |
419 | vlan_table[1] &= ~(BIT(dev->cpu_port)); | |
c2e86691 | 420 | |
b7a9e0da | 421 | vlan_table[2] |= BIT(port) | BIT(dev->cpu_port); |
c2e86691 | 422 | |
1958d581 VO |
423 | err = ksz9477_set_vlan_table(dev, vlan->vid, vlan_table); |
424 | if (err) { | |
31046a5f | 425 | NL_SET_ERR_MSG_MOD(extack, "Failed to set vlan table"); |
1958d581 | 426 | return err; |
c2e86691 | 427 | } |
b7a9e0da VO |
428 | |
429 | /* change PVID */ | |
430 | if (vlan->flags & BRIDGE_VLAN_INFO_PVID) | |
431 | ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vlan->vid); | |
1958d581 VO |
432 | |
433 | return 0; | |
c2e86691 TH |
434 | } |
435 | ||
436 | static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port, | |
437 | const struct switchdev_obj_port_vlan *vlan) | |
438 | { | |
439 | struct ksz_device *dev = ds->priv; | |
440 | bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; | |
441 | u32 vlan_table[3]; | |
c2e86691 TH |
442 | u16 pvid; |
443 | ||
444 | ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid); | |
445 | pvid = pvid & 0xFFF; | |
446 | ||
b7a9e0da VO |
447 | if (ksz9477_get_vlan_table(dev, vlan->vid, vlan_table)) { |
448 | dev_dbg(dev->dev, "Failed to get vlan table\n"); | |
449 | return -ETIMEDOUT; | |
450 | } | |
c2e86691 | 451 | |
b7a9e0da | 452 | vlan_table[2] &= ~BIT(port); |
c2e86691 | 453 | |
b7a9e0da VO |
454 | if (pvid == vlan->vid) |
455 | pvid = 1; | |
c2e86691 | 456 | |
b7a9e0da VO |
457 | if (untagged) |
458 | vlan_table[1] &= ~BIT(port); | |
c2e86691 | 459 | |
b7a9e0da VO |
460 | if (ksz9477_set_vlan_table(dev, vlan->vid, vlan_table)) { |
461 | dev_dbg(dev->dev, "Failed to set vlan table\n"); | |
462 | return -ETIMEDOUT; | |
c2e86691 TH |
463 | } |
464 | ||
465 | ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid); | |
466 | ||
467 | return 0; | |
468 | } | |
469 | ||
470 | static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port, | |
c2693363 VO |
471 | const unsigned char *addr, u16 vid, |
472 | struct dsa_db db) | |
c2e86691 TH |
473 | { |
474 | struct ksz_device *dev = ds->priv; | |
475 | u32 alu_table[4]; | |
476 | u32 data; | |
477 | int ret = 0; | |
478 | ||
479 | mutex_lock(&dev->alu_mutex); | |
480 | ||
481 | /* find any entry with mac & vid */ | |
482 | data = vid << ALU_FID_INDEX_S; | |
483 | data |= ((addr[0] << 8) | addr[1]); | |
484 | ksz_write32(dev, REG_SW_ALU_INDEX_0, data); | |
485 | ||
486 | data = ((addr[2] << 24) | (addr[3] << 16)); | |
487 | data |= ((addr[4] << 8) | addr[5]); | |
488 | ksz_write32(dev, REG_SW_ALU_INDEX_1, data); | |
489 | ||
490 | /* start read operation */ | |
491 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); | |
492 | ||
493 | /* wait to be finished */ | |
ef534195 MV |
494 | ret = ksz9477_wait_alu_ready(dev); |
495 | if (ret) { | |
c2e86691 TH |
496 | dev_dbg(dev->dev, "Failed to read ALU\n"); |
497 | goto exit; | |
498 | } | |
499 | ||
500 | /* read ALU entry */ | |
501 | ksz9477_read_table(dev, alu_table); | |
502 | ||
503 | /* update ALU entry */ | |
504 | alu_table[0] = ALU_V_STATIC_VALID; | |
505 | alu_table[1] |= BIT(port); | |
506 | if (vid) | |
507 | alu_table[1] |= ALU_V_USE_FID; | |
508 | alu_table[2] = (vid << ALU_V_FID_S); | |
509 | alu_table[2] |= ((addr[0] << 8) | addr[1]); | |
510 | alu_table[3] = ((addr[2] << 24) | (addr[3] << 16)); | |
511 | alu_table[3] |= ((addr[4] << 8) | addr[5]); | |
512 | ||
513 | ksz9477_write_table(dev, alu_table); | |
514 | ||
515 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); | |
516 | ||
517 | /* wait to be finished */ | |
ef534195 MV |
518 | ret = ksz9477_wait_alu_ready(dev); |
519 | if (ret) | |
c2e86691 TH |
520 | dev_dbg(dev->dev, "Failed to write ALU\n"); |
521 | ||
522 | exit: | |
523 | mutex_unlock(&dev->alu_mutex); | |
524 | ||
525 | return ret; | |
526 | } | |
527 | ||
528 | static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port, | |
c2693363 VO |
529 | const unsigned char *addr, u16 vid, |
530 | struct dsa_db db) | |
c2e86691 TH |
531 | { |
532 | struct ksz_device *dev = ds->priv; | |
533 | u32 alu_table[4]; | |
534 | u32 data; | |
535 | int ret = 0; | |
536 | ||
537 | mutex_lock(&dev->alu_mutex); | |
538 | ||
539 | /* read any entry with mac & vid */ | |
540 | data = vid << ALU_FID_INDEX_S; | |
541 | data |= ((addr[0] << 8) | addr[1]); | |
542 | ksz_write32(dev, REG_SW_ALU_INDEX_0, data); | |
543 | ||
544 | data = ((addr[2] << 24) | (addr[3] << 16)); | |
545 | data |= ((addr[4] << 8) | addr[5]); | |
546 | ksz_write32(dev, REG_SW_ALU_INDEX_1, data); | |
547 | ||
548 | /* start read operation */ | |
549 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START); | |
550 | ||
551 | /* wait to be finished */ | |
ef534195 MV |
552 | ret = ksz9477_wait_alu_ready(dev); |
553 | if (ret) { | |
c2e86691 TH |
554 | dev_dbg(dev->dev, "Failed to read ALU\n"); |
555 | goto exit; | |
556 | } | |
557 | ||
558 | ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]); | |
559 | if (alu_table[0] & ALU_V_STATIC_VALID) { | |
560 | ksz_read32(dev, REG_SW_ALU_VAL_B, &alu_table[1]); | |
561 | ksz_read32(dev, REG_SW_ALU_VAL_C, &alu_table[2]); | |
562 | ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]); | |
563 | ||
564 | /* clear forwarding port */ | |
565 | alu_table[2] &= ~BIT(port); | |
566 | ||
567 | /* if there is no port to forward, clear table */ | |
568 | if ((alu_table[2] & ALU_V_PORT_MAP) == 0) { | |
569 | alu_table[0] = 0; | |
570 | alu_table[1] = 0; | |
571 | alu_table[2] = 0; | |
572 | alu_table[3] = 0; | |
573 | } | |
574 | } else { | |
575 | alu_table[0] = 0; | |
576 | alu_table[1] = 0; | |
577 | alu_table[2] = 0; | |
578 | alu_table[3] = 0; | |
579 | } | |
580 | ||
581 | ksz9477_write_table(dev, alu_table); | |
582 | ||
583 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START); | |
584 | ||
585 | /* wait to be finished */ | |
ef534195 MV |
586 | ret = ksz9477_wait_alu_ready(dev); |
587 | if (ret) | |
c2e86691 TH |
588 | dev_dbg(dev->dev, "Failed to write ALU\n"); |
589 | ||
590 | exit: | |
591 | mutex_unlock(&dev->alu_mutex); | |
592 | ||
593 | return ret; | |
594 | } | |
595 | ||
596 | static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table) | |
597 | { | |
598 | alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID); | |
599 | alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER); | |
600 | alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER); | |
601 | alu->prio_age = (alu_table[0] >> ALU_V_PRIO_AGE_CNT_S) & | |
602 | ALU_V_PRIO_AGE_CNT_M; | |
603 | alu->mstp = alu_table[0] & ALU_V_MSTP_M; | |
604 | ||
605 | alu->is_override = !!(alu_table[1] & ALU_V_OVERRIDE); | |
606 | alu->is_use_fid = !!(alu_table[1] & ALU_V_USE_FID); | |
607 | alu->port_forward = alu_table[1] & ALU_V_PORT_MAP; | |
608 | ||
609 | alu->fid = (alu_table[2] >> ALU_V_FID_S) & ALU_V_FID_M; | |
610 | ||
611 | alu->mac[0] = (alu_table[2] >> 8) & 0xFF; | |
612 | alu->mac[1] = alu_table[2] & 0xFF; | |
613 | alu->mac[2] = (alu_table[3] >> 24) & 0xFF; | |
614 | alu->mac[3] = (alu_table[3] >> 16) & 0xFF; | |
615 | alu->mac[4] = (alu_table[3] >> 8) & 0xFF; | |
616 | alu->mac[5] = alu_table[3] & 0xFF; | |
617 | } | |
618 | ||
619 | static int ksz9477_port_fdb_dump(struct dsa_switch *ds, int port, | |
620 | dsa_fdb_dump_cb_t *cb, void *data) | |
621 | { | |
622 | struct ksz_device *dev = ds->priv; | |
623 | int ret = 0; | |
624 | u32 ksz_data; | |
625 | u32 alu_table[4]; | |
626 | struct alu_struct alu; | |
627 | int timeout; | |
628 | ||
629 | mutex_lock(&dev->alu_mutex); | |
630 | ||
631 | /* start ALU search */ | |
632 | ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_START | ALU_SEARCH); | |
633 | ||
634 | do { | |
635 | timeout = 1000; | |
636 | do { | |
637 | ksz_read32(dev, REG_SW_ALU_CTRL__4, &ksz_data); | |
638 | if ((ksz_data & ALU_VALID) || !(ksz_data & ALU_START)) | |
639 | break; | |
640 | usleep_range(1, 10); | |
641 | } while (timeout-- > 0); | |
642 | ||
643 | if (!timeout) { | |
644 | dev_dbg(dev->dev, "Failed to search ALU\n"); | |
645 | ret = -ETIMEDOUT; | |
646 | goto exit; | |
647 | } | |
648 | ||
649 | /* read ALU table */ | |
650 | ksz9477_read_table(dev, alu_table); | |
651 | ||
652 | ksz9477_convert_alu(&alu, alu_table); | |
653 | ||
654 | if (alu.port_forward & BIT(port)) { | |
655 | ret = cb(alu.mac, alu.fid, alu.is_static, data); | |
656 | if (ret) | |
657 | goto exit; | |
658 | } | |
659 | } while (ksz_data & ALU_START); | |
660 | ||
661 | exit: | |
662 | ||
663 | /* stop ALU search */ | |
664 | ksz_write32(dev, REG_SW_ALU_CTRL__4, 0); | |
665 | ||
666 | mutex_unlock(&dev->alu_mutex); | |
667 | ||
668 | return ret; | |
669 | } | |
670 | ||
a52b2da7 | 671 | static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port, |
c2693363 VO |
672 | const struct switchdev_obj_port_mdb *mdb, |
673 | struct dsa_db db) | |
c2e86691 TH |
674 | { |
675 | struct ksz_device *dev = ds->priv; | |
676 | u32 static_table[4]; | |
677 | u32 data; | |
678 | int index; | |
679 | u32 mac_hi, mac_lo; | |
a52b2da7 | 680 | int err = 0; |
c2e86691 TH |
681 | |
682 | mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); | |
683 | mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); | |
684 | mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); | |
685 | ||
686 | mutex_lock(&dev->alu_mutex); | |
687 | ||
462d5250 | 688 | for (index = 0; index < dev->info->num_statics; index++) { |
c2e86691 TH |
689 | /* find empty slot first */ |
690 | data = (index << ALU_STAT_INDEX_S) | | |
691 | ALU_STAT_READ | ALU_STAT_START; | |
692 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
693 | ||
694 | /* wait to be finished */ | |
a52b2da7 VO |
695 | err = ksz9477_wait_alu_sta_ready(dev); |
696 | if (err) { | |
c2e86691 TH |
697 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); |
698 | goto exit; | |
699 | } | |
700 | ||
701 | /* read ALU static table */ | |
702 | ksz9477_read_table(dev, static_table); | |
703 | ||
704 | if (static_table[0] & ALU_V_STATIC_VALID) { | |
705 | /* check this has same vid & mac address */ | |
706 | if (((static_table[2] >> ALU_V_FID_S) == mdb->vid) && | |
707 | ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && | |
708 | static_table[3] == mac_lo) { | |
709 | /* found matching one */ | |
710 | break; | |
711 | } | |
712 | } else { | |
713 | /* found empty one */ | |
714 | break; | |
715 | } | |
716 | } | |
717 | ||
718 | /* no available entry */ | |
462d5250 | 719 | if (index == dev->info->num_statics) { |
a52b2da7 | 720 | err = -ENOSPC; |
c2e86691 | 721 | goto exit; |
a52b2da7 | 722 | } |
c2e86691 TH |
723 | |
724 | /* add entry */ | |
725 | static_table[0] = ALU_V_STATIC_VALID; | |
726 | static_table[1] |= BIT(port); | |
727 | if (mdb->vid) | |
728 | static_table[1] |= ALU_V_USE_FID; | |
729 | static_table[2] = (mdb->vid << ALU_V_FID_S); | |
730 | static_table[2] |= mac_hi; | |
731 | static_table[3] = mac_lo; | |
732 | ||
733 | ksz9477_write_table(dev, static_table); | |
734 | ||
735 | data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; | |
736 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
737 | ||
738 | /* wait to be finished */ | |
3371efbc | 739 | if (ksz9477_wait_alu_sta_ready(dev)) |
c2e86691 TH |
740 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); |
741 | ||
742 | exit: | |
743 | mutex_unlock(&dev->alu_mutex); | |
a52b2da7 | 744 | return err; |
c2e86691 TH |
745 | } |
746 | ||
747 | static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port, | |
c2693363 VO |
748 | const struct switchdev_obj_port_mdb *mdb, |
749 | struct dsa_db db) | |
c2e86691 TH |
750 | { |
751 | struct ksz_device *dev = ds->priv; | |
752 | u32 static_table[4]; | |
753 | u32 data; | |
754 | int index; | |
755 | int ret = 0; | |
756 | u32 mac_hi, mac_lo; | |
757 | ||
758 | mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]); | |
759 | mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16)); | |
760 | mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]); | |
761 | ||
762 | mutex_lock(&dev->alu_mutex); | |
763 | ||
462d5250 | 764 | for (index = 0; index < dev->info->num_statics; index++) { |
c2e86691 TH |
765 | /* find empty slot first */ |
766 | data = (index << ALU_STAT_INDEX_S) | | |
767 | ALU_STAT_READ | ALU_STAT_START; | |
768 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
769 | ||
770 | /* wait to be finished */ | |
3371efbc MV |
771 | ret = ksz9477_wait_alu_sta_ready(dev); |
772 | if (ret) { | |
c2e86691 TH |
773 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); |
774 | goto exit; | |
775 | } | |
776 | ||
777 | /* read ALU static table */ | |
778 | ksz9477_read_table(dev, static_table); | |
779 | ||
780 | if (static_table[0] & ALU_V_STATIC_VALID) { | |
781 | /* check this has same vid & mac address */ | |
782 | ||
783 | if (((static_table[2] >> ALU_V_FID_S) == mdb->vid) && | |
784 | ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) && | |
785 | static_table[3] == mac_lo) { | |
786 | /* found matching one */ | |
787 | break; | |
788 | } | |
789 | } | |
790 | } | |
791 | ||
792 | /* no available entry */ | |
462d5250 | 793 | if (index == dev->info->num_statics) |
c2e86691 TH |
794 | goto exit; |
795 | ||
796 | /* clear port */ | |
797 | static_table[1] &= ~BIT(port); | |
798 | ||
799 | if ((static_table[1] & ALU_V_PORT_MAP) == 0) { | |
800 | /* delete entry */ | |
801 | static_table[0] = 0; | |
802 | static_table[1] = 0; | |
803 | static_table[2] = 0; | |
804 | static_table[3] = 0; | |
805 | } | |
806 | ||
807 | ksz9477_write_table(dev, static_table); | |
808 | ||
809 | data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START; | |
810 | ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data); | |
811 | ||
812 | /* wait to be finished */ | |
3371efbc MV |
813 | ret = ksz9477_wait_alu_sta_ready(dev); |
814 | if (ret) | |
c2e86691 TH |
815 | dev_dbg(dev->dev, "Failed to read ALU STATIC\n"); |
816 | ||
817 | exit: | |
818 | mutex_unlock(&dev->alu_mutex); | |
819 | ||
820 | return ret; | |
821 | } | |
822 | ||
823 | static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port, | |
824 | struct dsa_mall_mirror_tc_entry *mirror, | |
0148bb50 | 825 | bool ingress, struct netlink_ext_ack *extack) |
c2e86691 TH |
826 | { |
827 | struct ksz_device *dev = ds->priv; | |
fee34dd1 AR |
828 | u8 data; |
829 | int p; | |
830 | ||
831 | /* Limit to one sniffer port | |
832 | * Check if any of the port is already set for sniffing | |
833 | * If yes, instruct the user to remove the previous entry & exit | |
834 | */ | |
462d5250 | 835 | for (p = 0; p < dev->info->port_cnt; p++) { |
fee34dd1 AR |
836 | /* Skip the current sniffing port */ |
837 | if (p == mirror->to_local_port) | |
838 | continue; | |
839 | ||
840 | ksz_pread8(dev, p, P_MIRROR_CTRL, &data); | |
841 | ||
842 | if (data & PORT_MIRROR_SNIFFER) { | |
843 | NL_SET_ERR_MSG_MOD(extack, | |
844 | "Sniffer port is already configured, delete existing rules & retry"); | |
845 | return -EBUSY; | |
846 | } | |
847 | } | |
c2e86691 TH |
848 | |
849 | if (ingress) | |
850 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true); | |
851 | else | |
852 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true); | |
853 | ||
c2e86691 TH |
854 | /* configure mirror port */ |
855 | ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, | |
856 | PORT_MIRROR_SNIFFER, true); | |
857 | ||
858 | ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false); | |
859 | ||
860 | return 0; | |
861 | } | |
862 | ||
863 | static void ksz9477_port_mirror_del(struct dsa_switch *ds, int port, | |
864 | struct dsa_mall_mirror_tc_entry *mirror) | |
865 | { | |
866 | struct ksz_device *dev = ds->priv; | |
fee34dd1 | 867 | bool in_use = false; |
c2e86691 | 868 | u8 data; |
fee34dd1 | 869 | int p; |
c2e86691 TH |
870 | |
871 | if (mirror->ingress) | |
872 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false); | |
873 | else | |
874 | ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false); | |
875 | ||
c2e86691 | 876 | |
fee34dd1 | 877 | /* Check if any of the port is still referring to sniffer port */ |
462d5250 | 878 | for (p = 0; p < dev->info->port_cnt; p++) { |
fee34dd1 AR |
879 | ksz_pread8(dev, p, P_MIRROR_CTRL, &data); |
880 | ||
881 | if ((data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) { | |
882 | in_use = true; | |
883 | break; | |
884 | } | |
885 | } | |
886 | ||
887 | /* delete sniffing if there are no other mirroring rules */ | |
888 | if (!in_use) | |
c2e86691 TH |
889 | ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL, |
890 | PORT_MIRROR_SNIFFER, false); | |
891 | } | |
892 | ||
8c29bebb TH |
893 | static bool ksz9477_get_gbit(struct ksz_device *dev, u8 data) |
894 | { | |
895 | bool gbit; | |
896 | ||
897 | if (dev->features & NEW_XMII) | |
898 | gbit = !(data & PORT_MII_NOT_1GBIT); | |
899 | else | |
900 | gbit = !!(data & PORT_MII_1000MBIT_S1); | |
901 | return gbit; | |
902 | } | |
903 | ||
904 | static void ksz9477_set_gbit(struct ksz_device *dev, bool gbit, u8 *data) | |
905 | { | |
906 | if (dev->features & NEW_XMII) { | |
907 | if (gbit) | |
908 | *data &= ~PORT_MII_NOT_1GBIT; | |
909 | else | |
910 | *data |= PORT_MII_NOT_1GBIT; | |
911 | } else { | |
912 | if (gbit) | |
913 | *data |= PORT_MII_1000MBIT_S1; | |
914 | else | |
915 | *data &= ~PORT_MII_1000MBIT_S1; | |
916 | } | |
917 | } | |
918 | ||
919 | static int ksz9477_get_xmii(struct ksz_device *dev, u8 data) | |
920 | { | |
921 | int mode; | |
922 | ||
923 | if (dev->features & NEW_XMII) { | |
924 | switch (data & PORT_MII_SEL_M) { | |
925 | case PORT_MII_SEL: | |
926 | mode = 0; | |
927 | break; | |
928 | case PORT_RMII_SEL: | |
929 | mode = 1; | |
930 | break; | |
931 | case PORT_GMII_SEL: | |
932 | mode = 2; | |
933 | break; | |
934 | default: | |
935 | mode = 3; | |
936 | } | |
937 | } else { | |
938 | switch (data & PORT_MII_SEL_M) { | |
939 | case PORT_MII_SEL_S1: | |
940 | mode = 0; | |
941 | break; | |
942 | case PORT_RMII_SEL_S1: | |
943 | mode = 1; | |
944 | break; | |
945 | case PORT_GMII_SEL_S1: | |
946 | mode = 2; | |
947 | break; | |
948 | default: | |
949 | mode = 3; | |
950 | } | |
951 | } | |
952 | return mode; | |
953 | } | |
954 | ||
955 | static void ksz9477_set_xmii(struct ksz_device *dev, int mode, u8 *data) | |
956 | { | |
957 | u8 xmii; | |
958 | ||
959 | if (dev->features & NEW_XMII) { | |
960 | switch (mode) { | |
961 | case 0: | |
962 | xmii = PORT_MII_SEL; | |
963 | break; | |
964 | case 1: | |
965 | xmii = PORT_RMII_SEL; | |
966 | break; | |
967 | case 2: | |
968 | xmii = PORT_GMII_SEL; | |
969 | break; | |
970 | default: | |
971 | xmii = PORT_RGMII_SEL; | |
972 | break; | |
973 | } | |
974 | } else { | |
975 | switch (mode) { | |
976 | case 0: | |
977 | xmii = PORT_MII_SEL_S1; | |
978 | break; | |
979 | case 1: | |
980 | xmii = PORT_RMII_SEL_S1; | |
981 | break; | |
982 | case 2: | |
983 | xmii = PORT_GMII_SEL_S1; | |
984 | break; | |
985 | default: | |
986 | xmii = PORT_RGMII_SEL_S1; | |
987 | break; | |
988 | } | |
989 | } | |
990 | *data &= ~PORT_MII_SEL_M; | |
991 | *data |= xmii; | |
992 | } | |
993 | ||
994 | static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port) | |
995 | { | |
996 | phy_interface_t interface; | |
997 | bool gbit; | |
998 | int mode; | |
999 | u8 data8; | |
1000 | ||
1001 | if (port < dev->phy_port_cnt) | |
1002 | return PHY_INTERFACE_MODE_NA; | |
1003 | ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); | |
1004 | gbit = ksz9477_get_gbit(dev, data8); | |
1005 | mode = ksz9477_get_xmii(dev, data8); | |
1006 | switch (mode) { | |
1007 | case 2: | |
1008 | interface = PHY_INTERFACE_MODE_GMII; | |
1009 | if (gbit) | |
1010 | break; | |
df561f66 | 1011 | fallthrough; |
8c29bebb TH |
1012 | case 0: |
1013 | interface = PHY_INTERFACE_MODE_MII; | |
1014 | break; | |
1015 | case 1: | |
1016 | interface = PHY_INTERFACE_MODE_RMII; | |
1017 | break; | |
1018 | default: | |
1019 | interface = PHY_INTERFACE_MODE_RGMII; | |
1020 | if (data8 & PORT_RGMII_ID_EG_ENABLE) | |
1021 | interface = PHY_INTERFACE_MODE_RGMII_TXID; | |
1022 | if (data8 & PORT_RGMII_ID_IG_ENABLE) { | |
1023 | interface = PHY_INTERFACE_MODE_RGMII_RXID; | |
1024 | if (data8 & PORT_RGMII_ID_EG_ENABLE) | |
1025 | interface = PHY_INTERFACE_MODE_RGMII_ID; | |
1026 | } | |
1027 | break; | |
42fc6a4c | 1028 | } |
8c29bebb | 1029 | return interface; |
42fc6a4c TH |
1030 | } |
1031 | ||
1fc33199 RH |
1032 | static void ksz9477_port_mmd_write(struct ksz_device *dev, int port, |
1033 | u8 dev_addr, u16 reg_addr, u16 val) | |
1034 | { | |
1035 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP, | |
1036 | MMD_SETUP(PORT_MMD_OP_INDEX, dev_addr)); | |
1037 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, reg_addr); | |
1038 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP, | |
1039 | MMD_SETUP(PORT_MMD_OP_DATA_NO_INCR, dev_addr)); | |
1040 | ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, val); | |
1041 | } | |
1042 | ||
1043 | static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) | |
1044 | { | |
1045 | /* Apply PHY settings to address errata listed in | |
1046 | * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565 | |
1047 | * Silicon Errata and Data Sheet Clarification documents: | |
1048 | * | |
1049 | * Register settings are needed to improve PHY receive performance | |
1050 | */ | |
1051 | ksz9477_port_mmd_write(dev, port, 0x01, 0x6f, 0xdd0b); | |
1052 | ksz9477_port_mmd_write(dev, port, 0x01, 0x8f, 0x6032); | |
1053 | ksz9477_port_mmd_write(dev, port, 0x01, 0x9d, 0x248c); | |
1054 | ksz9477_port_mmd_write(dev, port, 0x01, 0x75, 0x0060); | |
1055 | ksz9477_port_mmd_write(dev, port, 0x01, 0xd3, 0x7777); | |
1056 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x06, 0x3008); | |
1057 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x08, 0x2001); | |
1058 | ||
1059 | /* Transmit waveform amplitude can be improved | |
1060 | * (1000BASE-T, 100BASE-TX, 10BASE-Te) | |
1061 | */ | |
1062 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x04, 0x00d0); | |
1063 | ||
1064 | /* Energy Efficient Ethernet (EEE) feature select must | |
1065 | * be manually disabled (except on KSZ8565 which is 100Mbit) | |
1066 | */ | |
1067 | if (dev->features & GBIT_SUPPORT) | |
1068 | ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000); | |
1069 | ||
1070 | /* Register settings are required to meet data sheet | |
1071 | * supply current specifications | |
1072 | */ | |
1073 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x13, 0x6eff); | |
1074 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x14, 0xe6ff); | |
1075 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x15, 0x6eff); | |
1076 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x16, 0xe6ff); | |
1077 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x17, 0x00ff); | |
1078 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x18, 0x43ff); | |
1079 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x19, 0xc3ff); | |
1080 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1a, 0x6fff); | |
1081 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1b, 0x07ff); | |
1082 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1c, 0x0fff); | |
1083 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1d, 0xe7ff); | |
1084 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x1e, 0xefff); | |
1085 | ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee); | |
1086 | } | |
1087 | ||
65ac79e1 AR |
1088 | static void ksz9477_get_caps(struct dsa_switch *ds, int port, |
1089 | struct phylink_config *config) | |
1090 | { | |
1091 | ksz_phylink_get_caps(ds, port, config); | |
1092 | ||
1093 | config->mac_capabilities = MAC_10 | MAC_100 | MAC_1000FD | | |
1094 | MAC_ASYM_PAUSE | MAC_SYM_PAUSE; | |
1095 | } | |
1096 | ||
c2e86691 TH |
1097 | static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) |
1098 | { | |
c2e86691 | 1099 | struct ksz_port *p = &dev->ports[port]; |
b3612ccd OR |
1100 | struct dsa_switch *ds = dev->ds; |
1101 | u8 data8, member; | |
1102 | u16 data16; | |
c2e86691 TH |
1103 | |
1104 | /* enable tag tail for host port */ | |
1105 | if (cpu_port) | |
1106 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE, | |
1107 | true); | |
1108 | ||
1109 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false); | |
1110 | ||
1111 | /* set back pressure */ | |
1112 | ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true); | |
1113 | ||
1114 | /* enable broadcast storm limit */ | |
1115 | ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true); | |
1116 | ||
1117 | /* disable DiffServ priority */ | |
1118 | ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false); | |
1119 | ||
1120 | /* replace priority */ | |
1121 | ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING, | |
1122 | false); | |
1123 | ksz9477_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4, | |
1124 | MTI_PVID_REPLACE, false); | |
1125 | ||
1126 | /* enable 802.1p priority */ | |
1127 | ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); | |
1128 | ||
1129 | if (port < dev->phy_port_cnt) { | |
1130 | /* do not force flow control */ | |
1131 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, | |
1132 | PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, | |
1133 | false); | |
1134 | ||
462d5250 | 1135 | if (dev->info->phy_errata_9477) |
1fc33199 | 1136 | ksz9477_phy_errata_setup(dev, port); |
c2e86691 TH |
1137 | } else { |
1138 | /* force flow control */ | |
1139 | ksz_port_cfg(dev, port, REG_PORT_CTRL_0, | |
1140 | PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, | |
1141 | true); | |
1142 | ||
1143 | /* configure MAC to 1G & RGMII mode */ | |
1144 | ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); | |
edecfa98 | 1145 | switch (p->interface) { |
c2e86691 | 1146 | case PHY_INTERFACE_MODE_MII: |
8c29bebb TH |
1147 | ksz9477_set_xmii(dev, 0, &data8); |
1148 | ksz9477_set_gbit(dev, false, &data8); | |
c2e86691 TH |
1149 | p->phydev.speed = SPEED_100; |
1150 | break; | |
1151 | case PHY_INTERFACE_MODE_RMII: | |
8c29bebb TH |
1152 | ksz9477_set_xmii(dev, 1, &data8); |
1153 | ksz9477_set_gbit(dev, false, &data8); | |
c2e86691 TH |
1154 | p->phydev.speed = SPEED_100; |
1155 | break; | |
1156 | case PHY_INTERFACE_MODE_GMII: | |
8c29bebb TH |
1157 | ksz9477_set_xmii(dev, 2, &data8); |
1158 | ksz9477_set_gbit(dev, true, &data8); | |
c2e86691 TH |
1159 | p->phydev.speed = SPEED_1000; |
1160 | break; | |
1161 | default: | |
8c29bebb TH |
1162 | ksz9477_set_xmii(dev, 3, &data8); |
1163 | ksz9477_set_gbit(dev, true, &data8); | |
c2e86691 TH |
1164 | data8 &= ~PORT_RGMII_ID_IG_ENABLE; |
1165 | data8 &= ~PORT_RGMII_ID_EG_ENABLE; | |
edecfa98 HG |
1166 | if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || |
1167 | p->interface == PHY_INTERFACE_MODE_RGMII_RXID) | |
c2e86691 | 1168 | data8 |= PORT_RGMII_ID_IG_ENABLE; |
edecfa98 HG |
1169 | if (p->interface == PHY_INTERFACE_MODE_RGMII_ID || |
1170 | p->interface == PHY_INTERFACE_MODE_RGMII_TXID) | |
c2e86691 | 1171 | data8 |= PORT_RGMII_ID_EG_ENABLE; |
ade64eb5 PB |
1172 | /* On KSZ9893, disable RGMII in-band status support */ |
1173 | if (dev->features & IS_9893) | |
1174 | data8 &= ~PORT_MII_MAC_MODE; | |
c2e86691 TH |
1175 | p->phydev.speed = SPEED_1000; |
1176 | break; | |
1177 | } | |
1178 | ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); | |
1179 | p->phydev.duplex = 1; | |
1180 | } | |
b3612ccd | 1181 | |
b20a6b29 | 1182 | if (cpu_port) |
b3612ccd | 1183 | member = dsa_user_ports(ds); |
b20a6b29 | 1184 | else |
b3612ccd OR |
1185 | member = BIT(dsa_upstream_port(ds, port)); |
1186 | ||
c2e86691 TH |
1187 | ksz9477_cfg_port_member(dev, port, member); |
1188 | ||
1189 | /* clear pending interrupts */ | |
1190 | if (port < dev->phy_port_cnt) | |
1191 | ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16); | |
1192 | } | |
1193 | ||
1194 | static void ksz9477_config_cpu_port(struct dsa_switch *ds) | |
1195 | { | |
1196 | struct ksz_device *dev = ds->priv; | |
1197 | struct ksz_port *p; | |
1198 | int i; | |
1199 | ||
462d5250 AR |
1200 | for (i = 0; i < dev->info->port_cnt; i++) { |
1201 | if (dsa_is_cpu_port(ds, i) && | |
1202 | (dev->info->cpu_ports & (1 << i))) { | |
8c29bebb | 1203 | phy_interface_t interface; |
805a7e6f PB |
1204 | const char *prev_msg; |
1205 | const char *prev_mode; | |
8c29bebb | 1206 | |
c2e86691 | 1207 | dev->cpu_port = i; |
edecfa98 | 1208 | p = &dev->ports[i]; |
c2e86691 | 1209 | |
8c29bebb TH |
1210 | /* Read from XMII register to determine host port |
1211 | * interface. If set specifically in device tree | |
1212 | * note the difference to help debugging. | |
1213 | */ | |
1214 | interface = ksz9477_get_interface(dev, i); | |
edecfa98 HG |
1215 | if (!p->interface) { |
1216 | if (dev->compat_interface) { | |
1217 | dev_warn(dev->dev, | |
1218 | "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. " | |
1219 | "Please update your device tree.\n", | |
1220 | i); | |
1221 | p->interface = dev->compat_interface; | |
1222 | } else { | |
1223 | p->interface = interface; | |
1224 | } | |
1225 | } | |
3ab0a7a0 | 1226 | if (interface && interface != p->interface) { |
805a7e6f PB |
1227 | prev_msg = " instead of "; |
1228 | prev_mode = phy_modes(interface); | |
1229 | } else { | |
1230 | prev_msg = ""; | |
1231 | prev_mode = ""; | |
1232 | } | |
1233 | dev_info(dev->dev, | |
1234 | "Port%d: using phy mode %s%s%s\n", | |
1235 | i, | |
3ab0a7a0 | 1236 | phy_modes(p->interface), |
805a7e6f PB |
1237 | prev_msg, |
1238 | prev_mode); | |
8c29bebb | 1239 | |
c2e86691 TH |
1240 | /* enable cpu port */ |
1241 | ksz9477_port_setup(dev, i, true); | |
c2e86691 TH |
1242 | p->on = 1; |
1243 | } | |
1244 | } | |
1245 | ||
462d5250 | 1246 | for (i = 0; i < dev->info->port_cnt; i++) { |
c2e86691 TH |
1247 | if (i == dev->cpu_port) |
1248 | continue; | |
1249 | p = &dev->ports[i]; | |
1250 | ||
c2e86691 TH |
1251 | ksz9477_port_stp_state_set(ds, i, BR_STATE_DISABLED); |
1252 | p->on = 1; | |
1253 | if (i < dev->phy_port_cnt) | |
1254 | p->phy = 1; | |
1255 | if (dev->chip_id == 0x00947700 && i == 6) { | |
1256 | p->sgmii = 1; | |
1257 | ||
1258 | /* SGMII PHY detection code is not implemented yet. */ | |
1259 | p->phy = 0; | |
1260 | } | |
1261 | } | |
1262 | } | |
1263 | ||
1264 | static int ksz9477_setup(struct dsa_switch *ds) | |
1265 | { | |
1266 | struct ksz_device *dev = ds->priv; | |
1267 | int ret = 0; | |
1268 | ||
1269 | dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), | |
462d5250 | 1270 | dev->info->num_vlans, GFP_KERNEL); |
c2e86691 TH |
1271 | if (!dev->vlan_cache) |
1272 | return -ENOMEM; | |
1273 | ||
1274 | ret = ksz9477_reset_switch(dev); | |
1275 | if (ret) { | |
1276 | dev_err(ds->dev, "failed to reset switch\n"); | |
1277 | return ret; | |
1278 | } | |
1279 | ||
962ad710 TH |
1280 | /* Required for port partitioning. */ |
1281 | ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY, | |
1282 | true); | |
1283 | ||
8c29bebb TH |
1284 | /* Do not work correctly with tail tagging. */ |
1285 | ksz_cfg(dev, REG_SW_MAC_CTRL_0, SW_CHECK_LENGTH, false); | |
1286 | ||
e18058ea OR |
1287 | /* Enable REG_SW_MTU__2 reg by setting SW_JUMBO_PACKET */ |
1288 | ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_JUMBO_PACKET, true); | |
1289 | ||
1290 | /* Now we can configure default MTU value */ | |
1291 | ret = regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, REG_SW_MTU_MASK, | |
1292 | VLAN_ETH_FRAME_LEN + ETH_FCS_LEN); | |
1293 | if (ret) | |
1294 | return ret; | |
c2e86691 TH |
1295 | |
1296 | ksz9477_config_cpu_port(ds); | |
1297 | ||
1298 | ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true); | |
1299 | ||
1300 | /* queue based egress rate limit */ | |
1301 | ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true); | |
1302 | ||
7c6ff470 TH |
1303 | /* enable global MIB counter freeze function */ |
1304 | ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true); | |
1305 | ||
c2e86691 TH |
1306 | /* start switch */ |
1307 | ksz_cfg(dev, REG_SW_OPERATION, SW_START, true); | |
1308 | ||
7c6ff470 TH |
1309 | ksz_init_mib_timer(dev); |
1310 | ||
0ee2af4e VO |
1311 | ds->configure_vlan_while_not_filtering = false; |
1312 | ||
c2e86691 TH |
1313 | return 0; |
1314 | } | |
1315 | ||
1316 | static const struct dsa_switch_ops ksz9477_switch_ops = { | |
534a0431 | 1317 | .get_tag_protocol = ksz_get_tag_protocol, |
c2e86691 TH |
1318 | .setup = ksz9477_setup, |
1319 | .phy_read = ksz9477_phy_read16, | |
1320 | .phy_write = ksz9477_phy_write16, | |
143a102e | 1321 | .phylink_mac_link_down = ksz_mac_link_down, |
65ac79e1 | 1322 | .phylink_get_caps = ksz9477_get_caps, |
c2e86691 | 1323 | .port_enable = ksz_enable_port, |
997d2126 | 1324 | .get_strings = ksz_get_strings, |
c2e86691 TH |
1325 | .get_ethtool_stats = ksz_get_ethtool_stats, |
1326 | .get_sset_count = ksz_sset_count, | |
1327 | .port_bridge_join = ksz_port_bridge_join, | |
1328 | .port_bridge_leave = ksz_port_bridge_leave, | |
1329 | .port_stp_state_set = ksz9477_port_stp_state_set, | |
1330 | .port_fast_age = ksz_port_fast_age, | |
1331 | .port_vlan_filtering = ksz9477_port_vlan_filtering, | |
c2e86691 TH |
1332 | .port_vlan_add = ksz9477_port_vlan_add, |
1333 | .port_vlan_del = ksz9477_port_vlan_del, | |
1334 | .port_fdb_dump = ksz9477_port_fdb_dump, | |
1335 | .port_fdb_add = ksz9477_port_fdb_add, | |
1336 | .port_fdb_del = ksz9477_port_fdb_del, | |
c2e86691 TH |
1337 | .port_mdb_add = ksz9477_port_mdb_add, |
1338 | .port_mdb_del = ksz9477_port_mdb_del, | |
1339 | .port_mirror_add = ksz9477_port_mirror_add, | |
1340 | .port_mirror_del = ksz9477_port_mirror_del, | |
c6101dd7 | 1341 | .get_stats64 = ksz_get_stats64, |
e18058ea OR |
1342 | .port_change_mtu = ksz9477_change_mtu, |
1343 | .port_max_mtu = ksz9477_max_mtu, | |
c2e86691 TH |
1344 | }; |
1345 | ||
1346 | static u32 ksz9477_get_port_addr(int port, int offset) | |
1347 | { | |
1348 | return PORT_CTRL_ADDR(port, offset); | |
1349 | } | |
1350 | ||
27faa0aa AR |
1351 | static int ksz9477_switch_init(struct ksz_device *dev) |
1352 | { | |
1353 | u8 data8; | |
1354 | int ret; | |
1355 | ||
1356 | dev->ds->ops = &ksz9477_switch_ops; | |
1357 | ||
1358 | dev->port_mask = (1 << dev->info->port_cnt) - 1; | |
1359 | ||
c2e86691 TH |
1360 | /* turn off SPI DO Edge select */ |
1361 | ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8); | |
1362 | if (ret) | |
1363 | return ret; | |
1364 | ||
1365 | data8 &= ~SPI_AUTO_EDGE_DETECTION; | |
1366 | ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8); | |
1367 | if (ret) | |
1368 | return ret; | |
1369 | ||
8c29bebb | 1370 | ret = ksz_read8(dev, REG_GLOBAL_OPTIONS, &data8); |
c2e86691 TH |
1371 | if (ret) |
1372 | return ret; | |
1373 | ||
1374 | /* Number of ports can be reduced depending on chip. */ | |
c2e86691 TH |
1375 | dev->phy_port_cnt = 5; |
1376 | ||
8c29bebb TH |
1377 | /* Default capability is gigabit capable. */ |
1378 | dev->features = GBIT_SUPPORT; | |
1379 | ||
27faa0aa | 1380 | if (dev->chip_id == KSZ9893_CHIP_ID) { |
8c29bebb TH |
1381 | dev->features |= IS_9893; |
1382 | ||
1383 | /* Chip does not support gigabit. */ | |
1384 | if (data8 & SW_QW_ABLE) | |
1385 | dev->features &= ~GBIT_SUPPORT; | |
8c29bebb TH |
1386 | dev->phy_port_cnt = 2; |
1387 | } else { | |
1388 | /* Chip uses new XMII register definitions. */ | |
1389 | dev->features |= NEW_XMII; | |
1390 | ||
1391 | /* Chip does not support gigabit. */ | |
1392 | if (!(data8 & SW_GIGABIT_ABLE)) | |
1393 | dev->features &= ~GBIT_SUPPORT; | |
1394 | } | |
c2e86691 TH |
1395 | return 0; |
1396 | } | |
1397 | ||
1398 | static void ksz9477_switch_exit(struct ksz_device *dev) | |
1399 | { | |
1400 | ksz9477_reset_switch(dev); | |
1401 | } | |
1402 | ||
1403 | static const struct ksz_dev_ops ksz9477_dev_ops = { | |
1404 | .get_port_addr = ksz9477_get_port_addr, | |
1405 | .cfg_port_member = ksz9477_cfg_port_member, | |
1406 | .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, | |
1407 | .port_setup = ksz9477_port_setup, | |
7c6ff470 TH |
1408 | .r_mib_cnt = ksz9477_r_mib_cnt, |
1409 | .r_mib_pkt = ksz9477_r_mib_pkt, | |
c6101dd7 | 1410 | .r_mib_stat64 = ksz_r_mib_stats64, |
7c6ff470 TH |
1411 | .freeze_mib = ksz9477_freeze_mib, |
1412 | .port_init_cnt = ksz9477_port_init_cnt, | |
c2e86691 | 1413 | .shutdown = ksz9477_reset_switch, |
c2e86691 TH |
1414 | .init = ksz9477_switch_init, |
1415 | .exit = ksz9477_switch_exit, | |
1416 | }; | |
1417 | ||
1418 | int ksz9477_switch_register(struct ksz_device *dev) | |
1419 | { | |
3506b2f4 HG |
1420 | int ret, i; |
1421 | struct phy_device *phydev; | |
1422 | ||
1423 | ret = ksz_switch_register(dev, &ksz9477_dev_ops); | |
1424 | if (ret) | |
1425 | return ret; | |
1426 | ||
1427 | for (i = 0; i < dev->phy_port_cnt; ++i) { | |
1428 | if (!dsa_is_user_port(dev->ds, i)) | |
1429 | continue; | |
1430 | ||
1431 | phydev = dsa_to_port(dev->ds, i)->slave->phydev; | |
1432 | ||
1433 | /* The MAC actually cannot run in 1000 half-duplex mode. */ | |
1434 | phy_remove_link_mode(phydev, | |
1435 | ETHTOOL_LINK_MODE_1000baseT_Half_BIT); | |
1436 | ||
1437 | /* PHY does not support gigabit. */ | |
1438 | if (!(dev->features & GBIT_SUPPORT)) | |
1439 | phy_remove_link_mode(phydev, | |
1440 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT); | |
1441 | } | |
1442 | return ret; | |
c2e86691 TH |
1443 | } |
1444 | EXPORT_SYMBOL(ksz9477_switch_register); | |
1445 | ||
1446 | MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); | |
1447 | MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch DSA Driver"); | |
1448 | MODULE_LICENSE("GPL"); |