perf/core: Replace zero-length array with flexible-array
[linux-2.6-microblaze.git] / drivers / net / dsa / dsa_loop.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Distributed Switch Architecture loopback driver
4  *
5  * Copyright (C) 2016, Florian Fainelli <f.fainelli@gmail.com>
6  */
7
8 #include <linux/platform_device.h>
9 #include <linux/netdevice.h>
10 #include <linux/phy.h>
11 #include <linux/phy_fixed.h>
12 #include <linux/export.h>
13 #include <linux/ethtool.h>
14 #include <linux/workqueue.h>
15 #include <linux/module.h>
16 #include <linux/if_bridge.h>
17 #include <net/dsa.h>
18
19 #include "dsa_loop.h"
20
21 struct dsa_loop_vlan {
22         u16 members;
23         u16 untagged;
24 };
25
26 struct dsa_loop_mib_entry {
27         char name[ETH_GSTRING_LEN];
28         unsigned long val;
29 };
30
31 enum dsa_loop_mib_counters {
32         DSA_LOOP_PHY_READ_OK,
33         DSA_LOOP_PHY_READ_ERR,
34         DSA_LOOP_PHY_WRITE_OK,
35         DSA_LOOP_PHY_WRITE_ERR,
36         __DSA_LOOP_CNT_MAX,
37 };
38
39 static struct dsa_loop_mib_entry dsa_loop_mibs[] = {
40         [DSA_LOOP_PHY_READ_OK]  = { "phy_read_ok", },
41         [DSA_LOOP_PHY_READ_ERR] = { "phy_read_err", },
42         [DSA_LOOP_PHY_WRITE_OK] = { "phy_write_ok", },
43         [DSA_LOOP_PHY_WRITE_ERR] = { "phy_write_err", },
44 };
45
46 struct dsa_loop_port {
47         struct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX];
48 };
49
50 #define DSA_LOOP_VLANS  5
51
52 struct dsa_loop_priv {
53         struct mii_bus  *bus;
54         unsigned int    port_base;
55         struct dsa_loop_vlan vlans[DSA_LOOP_VLANS];
56         struct net_device *netdev;
57         struct dsa_loop_port ports[DSA_MAX_PORTS];
58         u16 pvid;
59 };
60
61 static struct phy_device *phydevs[PHY_MAX_ADDR];
62
63 static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,
64                                                    int port,
65                                                    enum dsa_tag_protocol mp)
66 {
67         dev_dbg(ds->dev, "%s: port: %d\n", __func__, port);
68
69         return DSA_TAG_PROTO_NONE;
70 }
71
72 static int dsa_loop_setup(struct dsa_switch *ds)
73 {
74         struct dsa_loop_priv *ps = ds->priv;
75         unsigned int i;
76
77         for (i = 0; i < ds->num_ports; i++)
78                 memcpy(ps->ports[i].mib, dsa_loop_mibs,
79                        sizeof(dsa_loop_mibs));
80
81         dev_dbg(ds->dev, "%s\n", __func__);
82
83         return 0;
84 }
85
86 static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)
87 {
88         if (sset != ETH_SS_STATS && sset != ETH_SS_PHY_STATS)
89                 return 0;
90
91         return __DSA_LOOP_CNT_MAX;
92 }
93
94 static void dsa_loop_get_strings(struct dsa_switch *ds, int port,
95                                  u32 stringset, uint8_t *data)
96 {
97         struct dsa_loop_priv *ps = ds->priv;
98         unsigned int i;
99
100         if (stringset != ETH_SS_STATS && stringset != ETH_SS_PHY_STATS)
101                 return;
102
103         for (i = 0; i < __DSA_LOOP_CNT_MAX; i++)
104                 memcpy(data + i * ETH_GSTRING_LEN,
105                        ps->ports[port].mib[i].name, ETH_GSTRING_LEN);
106 }
107
108 static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,
109                                        uint64_t *data)
110 {
111         struct dsa_loop_priv *ps = ds->priv;
112         unsigned int i;
113
114         for (i = 0; i < __DSA_LOOP_CNT_MAX; i++)
115                 data[i] = ps->ports[port].mib[i].val;
116 }
117
118 static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum)
119 {
120         struct dsa_loop_priv *ps = ds->priv;
121         struct mii_bus *bus = ps->bus;
122         int ret;
123
124         ret = mdiobus_read_nested(bus, ps->port_base + port, regnum);
125         if (ret < 0)
126                 ps->ports[port].mib[DSA_LOOP_PHY_READ_ERR].val++;
127         else
128                 ps->ports[port].mib[DSA_LOOP_PHY_READ_OK].val++;
129
130         return ret;
131 }
132
133 static int dsa_loop_phy_write(struct dsa_switch *ds, int port,
134                               int regnum, u16 value)
135 {
136         struct dsa_loop_priv *ps = ds->priv;
137         struct mii_bus *bus = ps->bus;
138         int ret;
139
140         ret = mdiobus_write_nested(bus, ps->port_base + port, regnum, value);
141         if (ret < 0)
142                 ps->ports[port].mib[DSA_LOOP_PHY_WRITE_ERR].val++;
143         else
144                 ps->ports[port].mib[DSA_LOOP_PHY_WRITE_OK].val++;
145
146         return ret;
147 }
148
149 static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,
150                                      struct net_device *bridge)
151 {
152         dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
153                 __func__, port, bridge->name);
154
155         return 0;
156 }
157
158 static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,
159                                        struct net_device *bridge)
160 {
161         dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
162                 __func__, port, bridge->name);
163 }
164
165 static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,
166                                         u8 state)
167 {
168         dev_dbg(ds->dev, "%s: port: %d, state: %d\n",
169                 __func__, port, state);
170 }
171
172 static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,
173                                         bool vlan_filtering)
174 {
175         dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n",
176                 __func__, port, vlan_filtering);
177
178         return 0;
179 }
180
181 static int
182 dsa_loop_port_vlan_prepare(struct dsa_switch *ds, int port,
183                            const struct switchdev_obj_port_vlan *vlan)
184 {
185         struct dsa_loop_priv *ps = ds->priv;
186         struct mii_bus *bus = ps->bus;
187
188         dev_dbg(ds->dev, "%s: port: %d, vlan: %d-%d",
189                 __func__, port, vlan->vid_begin, vlan->vid_end);
190
191         /* Just do a sleeping operation to make lockdep checks effective */
192         mdiobus_read(bus, ps->port_base + port, MII_BMSR);
193
194         if (vlan->vid_end > DSA_LOOP_VLANS)
195                 return -ERANGE;
196
197         return 0;
198 }
199
200 static void dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,
201                                    const struct switchdev_obj_port_vlan *vlan)
202 {
203         bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
204         bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
205         struct dsa_loop_priv *ps = ds->priv;
206         struct mii_bus *bus = ps->bus;
207         struct dsa_loop_vlan *vl;
208         u16 vid;
209
210         /* Just do a sleeping operation to make lockdep checks effective */
211         mdiobus_read(bus, ps->port_base + port, MII_BMSR);
212
213         for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
214                 vl = &ps->vlans[vid];
215
216                 vl->members |= BIT(port);
217                 if (untagged)
218                         vl->untagged |= BIT(port);
219                 else
220                         vl->untagged &= ~BIT(port);
221
222                 dev_dbg(ds->dev, "%s: port: %d vlan: %d, %stagged, pvid: %d\n",
223                         __func__, port, vid, untagged ? "un" : "", pvid);
224         }
225
226         if (pvid)
227                 ps->pvid = vid;
228 }
229
230 static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,
231                                   const struct switchdev_obj_port_vlan *vlan)
232 {
233         bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
234         struct dsa_loop_priv *ps = ds->priv;
235         struct mii_bus *bus = ps->bus;
236         struct dsa_loop_vlan *vl;
237         u16 vid, pvid = ps->pvid;
238
239         /* Just do a sleeping operation to make lockdep checks effective */
240         mdiobus_read(bus, ps->port_base + port, MII_BMSR);
241
242         for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
243                 vl = &ps->vlans[vid];
244
245                 vl->members &= ~BIT(port);
246                 if (untagged)
247                         vl->untagged &= ~BIT(port);
248
249                 if (pvid == vid)
250                         pvid = 1;
251
252                 dev_dbg(ds->dev, "%s: port: %d vlan: %d, %stagged, pvid: %d\n",
253                         __func__, port, vid, untagged ? "un" : "", pvid);
254         }
255         ps->pvid = pvid;
256
257         return 0;
258 }
259
260 static const struct dsa_switch_ops dsa_loop_driver = {
261         .get_tag_protocol       = dsa_loop_get_protocol,
262         .setup                  = dsa_loop_setup,
263         .get_strings            = dsa_loop_get_strings,
264         .get_ethtool_stats      = dsa_loop_get_ethtool_stats,
265         .get_sset_count         = dsa_loop_get_sset_count,
266         .get_ethtool_phy_stats  = dsa_loop_get_ethtool_stats,
267         .phy_read               = dsa_loop_phy_read,
268         .phy_write              = dsa_loop_phy_write,
269         .port_bridge_join       = dsa_loop_port_bridge_join,
270         .port_bridge_leave      = dsa_loop_port_bridge_leave,
271         .port_stp_state_set     = dsa_loop_port_stp_state_set,
272         .port_vlan_filtering    = dsa_loop_port_vlan_filtering,
273         .port_vlan_prepare      = dsa_loop_port_vlan_prepare,
274         .port_vlan_add          = dsa_loop_port_vlan_add,
275         .port_vlan_del          = dsa_loop_port_vlan_del,
276 };
277
278 static int dsa_loop_drv_probe(struct mdio_device *mdiodev)
279 {
280         struct dsa_loop_pdata *pdata = mdiodev->dev.platform_data;
281         struct dsa_loop_priv *ps;
282         struct dsa_switch *ds;
283
284         if (!pdata)
285                 return -ENODEV;
286
287         dev_info(&mdiodev->dev, "%s: 0x%0x\n",
288                  pdata->name, pdata->enabled_ports);
289
290         ds = devm_kzalloc(&mdiodev->dev, sizeof(*ds), GFP_KERNEL);
291         if (!ds)
292                 return -ENOMEM;
293
294         ds->dev = &mdiodev->dev;
295         ds->num_ports = DSA_MAX_PORTS;
296
297         ps = devm_kzalloc(&mdiodev->dev, sizeof(*ps), GFP_KERNEL);
298         if (!ps)
299                 return -ENOMEM;
300
301         ps->netdev = dev_get_by_name(&init_net, pdata->netdev);
302         if (!ps->netdev)
303                 return -EPROBE_DEFER;
304
305         pdata->cd.netdev[DSA_LOOP_CPU_PORT] = &ps->netdev->dev;
306
307         ds->dev = &mdiodev->dev;
308         ds->ops = &dsa_loop_driver;
309         ds->priv = ps;
310         ps->bus = mdiodev->bus;
311
312         dev_set_drvdata(&mdiodev->dev, ds);
313
314         return dsa_register_switch(ds);
315 }
316
317 static void dsa_loop_drv_remove(struct mdio_device *mdiodev)
318 {
319         struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
320         struct dsa_loop_priv *ps = ds->priv;
321
322         dsa_unregister_switch(ds);
323         dev_put(ps->netdev);
324 }
325
326 static struct mdio_driver dsa_loop_drv = {
327         .mdiodrv.driver = {
328                 .name   = "dsa-loop",
329         },
330         .probe  = dsa_loop_drv_probe,
331         .remove = dsa_loop_drv_remove,
332 };
333
334 #define NUM_FIXED_PHYS  (DSA_LOOP_NUM_PORTS - 2)
335
336 static int __init dsa_loop_init(void)
337 {
338         struct fixed_phy_status status = {
339                 .link = 1,
340                 .speed = SPEED_100,
341                 .duplex = DUPLEX_FULL,
342         };
343         unsigned int i;
344
345         for (i = 0; i < NUM_FIXED_PHYS; i++)
346                 phydevs[i] = fixed_phy_register(PHY_POLL, &status, NULL);
347
348         return mdio_driver_register(&dsa_loop_drv);
349 }
350 module_init(dsa_loop_init);
351
352 static void __exit dsa_loop_exit(void)
353 {
354         unsigned int i;
355
356         mdio_driver_unregister(&dsa_loop_drv);
357         for (i = 0; i < NUM_FIXED_PHYS; i++)
358                 if (!IS_ERR(phydevs[i]))
359                         fixed_phy_unregister(phydevs[i]);
360 }
361 module_exit(dsa_loop_exit);
362
363 MODULE_LICENSE("GPL");
364 MODULE_AUTHOR("Florian Fainelli");
365 MODULE_DESCRIPTION("DSA loopback driver");