Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / drivers / net / dsa / microchip / ksz_common.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Microchip switch driver main logic
4  *
5  * Copyright (C) 2017-2019 Microchip Technology Inc.
6  */
7
8 #include <linux/delay.h>
9 #include <linux/export.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/platform_data/microchip-ksz.h>
14 #include <linux/phy.h>
15 #include <linux/etherdevice.h>
16 #include <linux/if_bridge.h>
17 #include <linux/of_net.h>
18 #include <net/dsa.h>
19 #include <net/switchdev.h>
20
21 #include "ksz_common.h"
22
23 void ksz_update_port_member(struct ksz_device *dev, int port)
24 {
25         struct ksz_port *p;
26         int i;
27
28         for (i = 0; i < dev->port_cnt; i++) {
29                 if (i == port || i == dev->cpu_port)
30                         continue;
31                 p = &dev->ports[i];
32                 if (!(dev->member & (1 << i)))
33                         continue;
34
35                 /* Port is a member of the bridge and is forwarding. */
36                 if (p->stp_state == BR_STATE_FORWARDING &&
37                     p->member != dev->member)
38                         dev->dev_ops->cfg_port_member(dev, i, dev->member);
39         }
40 }
41 EXPORT_SYMBOL_GPL(ksz_update_port_member);
42
43 static void port_r_cnt(struct ksz_device *dev, int port)
44 {
45         struct ksz_port_mib *mib = &dev->ports[port].mib;
46         u64 *dropped;
47
48         /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
49         while (mib->cnt_ptr < dev->reg_mib_cnt) {
50                 dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
51                                         &mib->counters[mib->cnt_ptr]);
52                 ++mib->cnt_ptr;
53         }
54
55         /* last one in storage */
56         dropped = &mib->counters[dev->mib_cnt];
57
58         /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
59         while (mib->cnt_ptr < dev->mib_cnt) {
60                 dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
61                                         dropped, &mib->counters[mib->cnt_ptr]);
62                 ++mib->cnt_ptr;
63         }
64         mib->cnt_ptr = 0;
65 }
66
67 static void ksz_mib_read_work(struct work_struct *work)
68 {
69         struct ksz_device *dev = container_of(work, struct ksz_device,
70                                               mib_read.work);
71         struct ksz_port_mib *mib;
72         struct ksz_port *p;
73         int i;
74
75         for (i = 0; i < dev->mib_port_cnt; i++) {
76                 if (dsa_is_unused_port(dev->ds, i))
77                         continue;
78
79                 p = &dev->ports[i];
80                 mib = &p->mib;
81                 mutex_lock(&mib->cnt_mutex);
82
83                 /* Only read MIB counters when the port is told to do.
84                  * If not, read only dropped counters when link is not up.
85                  */
86                 if (!p->read) {
87                         const struct dsa_port *dp = dsa_to_port(dev->ds, i);
88
89                         if (!netif_carrier_ok(dp->slave))
90                                 mib->cnt_ptr = dev->reg_mib_cnt;
91                 }
92                 port_r_cnt(dev, i);
93                 p->read = false;
94                 mutex_unlock(&mib->cnt_mutex);
95         }
96
97         schedule_delayed_work(&dev->mib_read, dev->mib_read_interval);
98 }
99
100 void ksz_init_mib_timer(struct ksz_device *dev)
101 {
102         int i;
103
104         INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work);
105
106         /* Read MIB counters every 30 seconds to avoid overflow. */
107         dev->mib_read_interval = msecs_to_jiffies(30000);
108
109         for (i = 0; i < dev->mib_port_cnt; i++)
110                 dev->dev_ops->port_init_cnt(dev, i);
111
112         /* Start the timer 2 seconds later. */
113         schedule_delayed_work(&dev->mib_read, msecs_to_jiffies(2000));
114 }
115 EXPORT_SYMBOL_GPL(ksz_init_mib_timer);
116
117 int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
118 {
119         struct ksz_device *dev = ds->priv;
120         u16 val = 0xffff;
121
122         dev->dev_ops->r_phy(dev, addr, reg, &val);
123
124         return val;
125 }
126 EXPORT_SYMBOL_GPL(ksz_phy_read16);
127
128 int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
129 {
130         struct ksz_device *dev = ds->priv;
131
132         dev->dev_ops->w_phy(dev, addr, reg, val);
133
134         return 0;
135 }
136 EXPORT_SYMBOL_GPL(ksz_phy_write16);
137
138 void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
139                        phy_interface_t interface)
140 {
141         struct ksz_device *dev = ds->priv;
142         struct ksz_port *p = &dev->ports[port];
143
144         /* Read all MIB counters when the link is going down. */
145         p->read = true;
146         schedule_delayed_work(&dev->mib_read, 0);
147 }
148 EXPORT_SYMBOL_GPL(ksz_mac_link_down);
149
150 int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
151 {
152         struct ksz_device *dev = ds->priv;
153
154         if (sset != ETH_SS_STATS)
155                 return 0;
156
157         return dev->mib_cnt;
158 }
159 EXPORT_SYMBOL_GPL(ksz_sset_count);
160
161 void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
162 {
163         const struct dsa_port *dp = dsa_to_port(ds, port);
164         struct ksz_device *dev = ds->priv;
165         struct ksz_port_mib *mib;
166
167         mib = &dev->ports[port].mib;
168         mutex_lock(&mib->cnt_mutex);
169
170         /* Only read dropped counters if no link. */
171         if (!netif_carrier_ok(dp->slave))
172                 mib->cnt_ptr = dev->reg_mib_cnt;
173         port_r_cnt(dev, port);
174         memcpy(buf, mib->counters, dev->mib_cnt * sizeof(u64));
175         mutex_unlock(&mib->cnt_mutex);
176 }
177 EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
178
179 int ksz_port_bridge_join(struct dsa_switch *ds, int port,
180                          struct net_device *br)
181 {
182         struct ksz_device *dev = ds->priv;
183
184         mutex_lock(&dev->dev_mutex);
185         dev->br_member |= (1 << port);
186         mutex_unlock(&dev->dev_mutex);
187
188         /* port_stp_state_set() will be called after to put the port in
189          * appropriate state so there is no need to do anything.
190          */
191
192         return 0;
193 }
194 EXPORT_SYMBOL_GPL(ksz_port_bridge_join);
195
196 void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
197                            struct net_device *br)
198 {
199         struct ksz_device *dev = ds->priv;
200
201         mutex_lock(&dev->dev_mutex);
202         dev->br_member &= ~(1 << port);
203         dev->member &= ~(1 << port);
204         mutex_unlock(&dev->dev_mutex);
205
206         /* port_stp_state_set() will be called after to put the port in
207          * forwarding state so there is no need to do anything.
208          */
209 }
210 EXPORT_SYMBOL_GPL(ksz_port_bridge_leave);
211
212 void ksz_port_fast_age(struct dsa_switch *ds, int port)
213 {
214         struct ksz_device *dev = ds->priv;
215
216         dev->dev_ops->flush_dyn_mac_table(dev, port);
217 }
218 EXPORT_SYMBOL_GPL(ksz_port_fast_age);
219
220 int ksz_port_vlan_prepare(struct dsa_switch *ds, int port,
221                           const struct switchdev_obj_port_vlan *vlan)
222 {
223         /* nothing needed */
224
225         return 0;
226 }
227 EXPORT_SYMBOL_GPL(ksz_port_vlan_prepare);
228
229 int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
230                       void *data)
231 {
232         struct ksz_device *dev = ds->priv;
233         int ret = 0;
234         u16 i = 0;
235         u16 entries = 0;
236         u8 timestamp = 0;
237         u8 fid;
238         u8 member;
239         struct alu_struct alu;
240
241         do {
242                 alu.is_static = false;
243                 ret = dev->dev_ops->r_dyn_mac_table(dev, i, alu.mac, &fid,
244                                                     &member, &timestamp,
245                                                     &entries);
246                 if (!ret && (member & BIT(port))) {
247                         ret = cb(alu.mac, alu.fid, alu.is_static, data);
248                         if (ret)
249                                 break;
250                 }
251                 i++;
252         } while (i < entries);
253         if (i >= entries)
254                 ret = 0;
255
256         return ret;
257 }
258 EXPORT_SYMBOL_GPL(ksz_port_fdb_dump);
259
260 int ksz_port_mdb_prepare(struct dsa_switch *ds, int port,
261                          const struct switchdev_obj_port_mdb *mdb)
262 {
263         /* nothing to do */
264         return 0;
265 }
266 EXPORT_SYMBOL_GPL(ksz_port_mdb_prepare);
267
268 void ksz_port_mdb_add(struct dsa_switch *ds, int port,
269                       const struct switchdev_obj_port_mdb *mdb)
270 {
271         struct ksz_device *dev = ds->priv;
272         struct alu_struct alu;
273         int index;
274         int empty = 0;
275
276         alu.port_forward = 0;
277         for (index = 0; index < dev->num_statics; index++) {
278                 if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
279                         /* Found one already in static MAC table. */
280                         if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
281                             alu.fid == mdb->vid)
282                                 break;
283                 /* Remember the first empty entry. */
284                 } else if (!empty) {
285                         empty = index + 1;
286                 }
287         }
288
289         /* no available entry */
290         if (index == dev->num_statics && !empty)
291                 return;
292
293         /* add entry */
294         if (index == dev->num_statics) {
295                 index = empty - 1;
296                 memset(&alu, 0, sizeof(alu));
297                 memcpy(alu.mac, mdb->addr, ETH_ALEN);
298                 alu.is_static = true;
299         }
300         alu.port_forward |= BIT(port);
301         if (mdb->vid) {
302                 alu.is_use_fid = true;
303
304                 /* Need a way to map VID to FID. */
305                 alu.fid = mdb->vid;
306         }
307         dev->dev_ops->w_sta_mac_table(dev, index, &alu);
308 }
309 EXPORT_SYMBOL_GPL(ksz_port_mdb_add);
310
311 int ksz_port_mdb_del(struct dsa_switch *ds, int port,
312                      const struct switchdev_obj_port_mdb *mdb)
313 {
314         struct ksz_device *dev = ds->priv;
315         struct alu_struct alu;
316         int index;
317         int ret = 0;
318
319         for (index = 0; index < dev->num_statics; index++) {
320                 if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
321                         /* Found one already in static MAC table. */
322                         if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
323                             alu.fid == mdb->vid)
324                                 break;
325                 }
326         }
327
328         /* no available entry */
329         if (index == dev->num_statics)
330                 goto exit;
331
332         /* clear port */
333         alu.port_forward &= ~BIT(port);
334         if (!alu.port_forward)
335                 alu.is_static = false;
336         dev->dev_ops->w_sta_mac_table(dev, index, &alu);
337
338 exit:
339         return ret;
340 }
341 EXPORT_SYMBOL_GPL(ksz_port_mdb_del);
342
343 int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
344 {
345         struct ksz_device *dev = ds->priv;
346
347         if (!dsa_is_user_port(ds, port))
348                 return 0;
349
350         /* setup slave port */
351         dev->dev_ops->port_setup(dev, port, false);
352
353         /* port_stp_state_set() will be called after to enable the port so
354          * there is no need to do anything.
355          */
356
357         return 0;
358 }
359 EXPORT_SYMBOL_GPL(ksz_enable_port);
360
361 struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
362 {
363         struct dsa_switch *ds;
364         struct ksz_device *swdev;
365
366         ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL);
367         if (!ds)
368                 return NULL;
369
370         ds->dev = base;
371         ds->num_ports = DSA_MAX_PORTS;
372
373         swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
374         if (!swdev)
375                 return NULL;
376
377         ds->priv = swdev;
378         swdev->dev = base;
379
380         swdev->ds = ds;
381         swdev->priv = priv;
382
383         return swdev;
384 }
385 EXPORT_SYMBOL(ksz_switch_alloc);
386
387 int ksz_switch_register(struct ksz_device *dev,
388                         const struct ksz_dev_ops *ops)
389 {
390         struct device_node *port, *ports;
391         phy_interface_t interface;
392         unsigned int port_num;
393         int ret;
394
395         if (dev->pdata)
396                 dev->chip_id = dev->pdata->chip_id;
397
398         dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset",
399                                                   GPIOD_OUT_LOW);
400         if (IS_ERR(dev->reset_gpio))
401                 return PTR_ERR(dev->reset_gpio);
402
403         if (dev->reset_gpio) {
404                 gpiod_set_value_cansleep(dev->reset_gpio, 1);
405                 usleep_range(10000, 12000);
406                 gpiod_set_value_cansleep(dev->reset_gpio, 0);
407                 usleep_range(100, 1000);
408         }
409
410         mutex_init(&dev->dev_mutex);
411         mutex_init(&dev->regmap_mutex);
412         mutex_init(&dev->alu_mutex);
413         mutex_init(&dev->vlan_mutex);
414
415         dev->dev_ops = ops;
416
417         if (dev->dev_ops->detect(dev))
418                 return -EINVAL;
419
420         ret = dev->dev_ops->init(dev);
421         if (ret)
422                 return ret;
423
424         /* Host port interface will be self detected, or specifically set in
425          * device tree.
426          */
427         for (port_num = 0; port_num < dev->port_cnt; ++port_num)
428                 dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA;
429         if (dev->dev->of_node) {
430                 ret = of_get_phy_mode(dev->dev->of_node, &interface);
431                 if (ret == 0)
432                         dev->compat_interface = interface;
433                 ports = of_get_child_by_name(dev->dev->of_node, "ports");
434                 if (ports)
435                         for_each_available_child_of_node(ports, port) {
436                                 if (of_property_read_u32(port, "reg",
437                                                          &port_num))
438                                         continue;
439                                 if (port_num >= dev->port_cnt)
440                                         return -EINVAL;
441                                 of_get_phy_mode(port,
442                                                 &dev->ports[port_num].interface);
443                         }
444                 dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
445                                                          "microchip,synclko-125");
446         }
447
448         ret = dsa_register_switch(dev->ds);
449         if (ret) {
450                 dev->dev_ops->exit(dev);
451                 return ret;
452         }
453
454         return 0;
455 }
456 EXPORT_SYMBOL(ksz_switch_register);
457
458 void ksz_switch_remove(struct ksz_device *dev)
459 {
460         /* timer started */
461         if (dev->mib_read_interval)
462                 cancel_delayed_work_sync(&dev->mib_read);
463
464         dev->dev_ops->exit(dev);
465         dsa_unregister_switch(dev->ds);
466
467         if (dev->reset_gpio)
468                 gpiod_set_value_cansleep(dev->reset_gpio, 1);
469
470 }
471 EXPORT_SYMBOL(ksz_switch_remove);
472
473 MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
474 MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver");
475 MODULE_LICENSE("GPL");