Merge tag 'imx-fixes-5.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo...
[sfrench/cifs-2.6.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-2018 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_priv.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 int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
44 {
45         struct ksz_device *dev = ds->priv;
46         u16 val = 0xffff;
47
48         dev->dev_ops->r_phy(dev, addr, reg, &val);
49
50         return val;
51 }
52 EXPORT_SYMBOL_GPL(ksz_phy_read16);
53
54 int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
55 {
56         struct ksz_device *dev = ds->priv;
57
58         dev->dev_ops->w_phy(dev, addr, reg, val);
59
60         return 0;
61 }
62 EXPORT_SYMBOL_GPL(ksz_phy_write16);
63
64 int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
65 {
66         struct ksz_device *dev = ds->priv;
67
68         if (sset != ETH_SS_STATS)
69                 return 0;
70
71         return dev->mib_cnt;
72 }
73 EXPORT_SYMBOL_GPL(ksz_sset_count);
74
75 int ksz_port_bridge_join(struct dsa_switch *ds, int port,
76                          struct net_device *br)
77 {
78         struct ksz_device *dev = ds->priv;
79
80         dev->br_member |= (1 << port);
81
82         /* port_stp_state_set() will be called after to put the port in
83          * appropriate state so there is no need to do anything.
84          */
85
86         return 0;
87 }
88 EXPORT_SYMBOL_GPL(ksz_port_bridge_join);
89
90 void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
91                            struct net_device *br)
92 {
93         struct ksz_device *dev = ds->priv;
94
95         dev->br_member &= ~(1 << port);
96         dev->member &= ~(1 << port);
97
98         /* port_stp_state_set() will be called after to put the port in
99          * forwarding state so there is no need to do anything.
100          */
101 }
102 EXPORT_SYMBOL_GPL(ksz_port_bridge_leave);
103
104 void ksz_port_fast_age(struct dsa_switch *ds, int port)
105 {
106         struct ksz_device *dev = ds->priv;
107
108         dev->dev_ops->flush_dyn_mac_table(dev, port);
109 }
110 EXPORT_SYMBOL_GPL(ksz_port_fast_age);
111
112 int ksz_port_vlan_prepare(struct dsa_switch *ds, int port,
113                           const struct switchdev_obj_port_vlan *vlan)
114 {
115         /* nothing needed */
116
117         return 0;
118 }
119 EXPORT_SYMBOL_GPL(ksz_port_vlan_prepare);
120
121 int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
122                       void *data)
123 {
124         struct ksz_device *dev = ds->priv;
125         int ret = 0;
126         u16 i = 0;
127         u16 entries = 0;
128         u8 timestamp = 0;
129         u8 fid;
130         u8 member;
131         struct alu_struct alu;
132
133         do {
134                 alu.is_static = false;
135                 ret = dev->dev_ops->r_dyn_mac_table(dev, i, alu.mac, &fid,
136                                                     &member, &timestamp,
137                                                     &entries);
138                 if (!ret && (member & BIT(port))) {
139                         ret = cb(alu.mac, alu.fid, alu.is_static, data);
140                         if (ret)
141                                 break;
142                 }
143                 i++;
144         } while (i < entries);
145         if (i >= entries)
146                 ret = 0;
147
148         return ret;
149 }
150 EXPORT_SYMBOL_GPL(ksz_port_fdb_dump);
151
152 int ksz_port_mdb_prepare(struct dsa_switch *ds, int port,
153                          const struct switchdev_obj_port_mdb *mdb)
154 {
155         /* nothing to do */
156         return 0;
157 }
158 EXPORT_SYMBOL_GPL(ksz_port_mdb_prepare);
159
160 void ksz_port_mdb_add(struct dsa_switch *ds, int port,
161                       const struct switchdev_obj_port_mdb *mdb)
162 {
163         struct ksz_device *dev = ds->priv;
164         struct alu_struct alu;
165         int index;
166         int empty = 0;
167
168         alu.port_forward = 0;
169         for (index = 0; index < dev->num_statics; index++) {
170                 if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
171                         /* Found one already in static MAC table. */
172                         if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
173                             alu.fid == mdb->vid)
174                                 break;
175                 /* Remember the first empty entry. */
176                 } else if (!empty) {
177                         empty = index + 1;
178                 }
179         }
180
181         /* no available entry */
182         if (index == dev->num_statics && !empty)
183                 return;
184
185         /* add entry */
186         if (index == dev->num_statics) {
187                 index = empty - 1;
188                 memset(&alu, 0, sizeof(alu));
189                 memcpy(alu.mac, mdb->addr, ETH_ALEN);
190                 alu.is_static = true;
191         }
192         alu.port_forward |= BIT(port);
193         if (mdb->vid) {
194                 alu.is_use_fid = true;
195
196                 /* Need a way to map VID to FID. */
197                 alu.fid = mdb->vid;
198         }
199         dev->dev_ops->w_sta_mac_table(dev, index, &alu);
200 }
201 EXPORT_SYMBOL_GPL(ksz_port_mdb_add);
202
203 int ksz_port_mdb_del(struct dsa_switch *ds, int port,
204                      const struct switchdev_obj_port_mdb *mdb)
205 {
206         struct ksz_device *dev = ds->priv;
207         struct alu_struct alu;
208         int index;
209         int ret = 0;
210
211         for (index = 0; index < dev->num_statics; index++) {
212                 if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
213                         /* Found one already in static MAC table. */
214                         if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
215                             alu.fid == mdb->vid)
216                                 break;
217                 }
218         }
219
220         /* no available entry */
221         if (index == dev->num_statics)
222                 goto exit;
223
224         /* clear port */
225         alu.port_forward &= ~BIT(port);
226         if (!alu.port_forward)
227                 alu.is_static = false;
228         dev->dev_ops->w_sta_mac_table(dev, index, &alu);
229
230 exit:
231         return ret;
232 }
233 EXPORT_SYMBOL_GPL(ksz_port_mdb_del);
234
235 int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
236 {
237         struct ksz_device *dev = ds->priv;
238
239         /* setup slave port */
240         dev->dev_ops->port_setup(dev, port, false);
241
242         /* port_stp_state_set() will be called after to enable the port so
243          * there is no need to do anything.
244          */
245
246         return 0;
247 }
248 EXPORT_SYMBOL_GPL(ksz_enable_port);
249
250 void ksz_disable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
251 {
252         struct ksz_device *dev = ds->priv;
253
254         dev->on_ports &= ~(1 << port);
255         dev->live_ports &= ~(1 << port);
256
257         /* port_stp_state_set() will be called after to disable the port so
258          * there is no need to do anything.
259          */
260 }
261 EXPORT_SYMBOL_GPL(ksz_disable_port);
262
263 struct ksz_device *ksz_switch_alloc(struct device *base,
264                                     const struct ksz_io_ops *ops,
265                                     void *priv)
266 {
267         struct dsa_switch *ds;
268         struct ksz_device *swdev;
269
270         ds = dsa_switch_alloc(base, DSA_MAX_PORTS);
271         if (!ds)
272                 return NULL;
273
274         swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
275         if (!swdev)
276                 return NULL;
277
278         ds->priv = swdev;
279         swdev->dev = base;
280
281         swdev->ds = ds;
282         swdev->priv = priv;
283         swdev->ops = ops;
284
285         return swdev;
286 }
287 EXPORT_SYMBOL(ksz_switch_alloc);
288
289 int ksz_switch_register(struct ksz_device *dev,
290                         const struct ksz_dev_ops *ops)
291 {
292         int ret;
293
294         if (dev->pdata)
295                 dev->chip_id = dev->pdata->chip_id;
296
297         dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset",
298                                                   GPIOD_OUT_LOW);
299         if (IS_ERR(dev->reset_gpio))
300                 return PTR_ERR(dev->reset_gpio);
301
302         if (dev->reset_gpio) {
303                 gpiod_set_value(dev->reset_gpio, 1);
304                 mdelay(10);
305                 gpiod_set_value(dev->reset_gpio, 0);
306         }
307
308         mutex_init(&dev->reg_mutex);
309         mutex_init(&dev->stats_mutex);
310         mutex_init(&dev->alu_mutex);
311         mutex_init(&dev->vlan_mutex);
312
313         dev->dev_ops = ops;
314
315         if (dev->dev_ops->detect(dev))
316                 return -EINVAL;
317
318         ret = dev->dev_ops->init(dev);
319         if (ret)
320                 return ret;
321
322         dev->interface = PHY_INTERFACE_MODE_MII;
323         if (dev->dev->of_node) {
324                 ret = of_get_phy_mode(dev->dev->of_node);
325                 if (ret >= 0)
326                         dev->interface = ret;
327         }
328
329         ret = dsa_register_switch(dev->ds);
330         if (ret) {
331                 dev->dev_ops->exit(dev);
332                 return ret;
333         }
334
335         return 0;
336 }
337 EXPORT_SYMBOL(ksz_switch_register);
338
339 void ksz_switch_remove(struct ksz_device *dev)
340 {
341         dev->dev_ops->exit(dev);
342         dsa_unregister_switch(dev->ds);
343
344         if (dev->reset_gpio)
345                 gpiod_set_value(dev->reset_gpio, 1);
346
347 }
348 EXPORT_SYMBOL(ksz_switch_remove);
349
350 MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
351 MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver");
352 MODULE_LICENSE("GPL");