]> git.ipfire.org Git - thirdparty/linux.git/blame - drivers/net/dsa/dsa_loop.c
Merge tag 'io_uring-5.7-2020-05-22' of git://git.kernel.dk/linux-block
[thirdparty/linux.git] / drivers / net / dsa / dsa_loop.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
98cd1552
FF
2/*
3 * Distributed Switch Architecture loopback driver
4 *
5 * Copyright (C) 2016, Florian Fainelli <f.fainelli@gmail.com>
98cd1552
FF
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>
484c0172 13#include <linux/ethtool.h>
98cd1552
FF
14#include <linux/workqueue.h>
15#include <linux/module.h>
16#include <linux/if_bridge.h>
98cd1552
FF
17#include <net/dsa.h>
18
19#include "dsa_loop.h"
20
21struct dsa_loop_vlan {
22 u16 members;
23 u16 untagged;
24};
25
484c0172
FF
26struct dsa_loop_mib_entry {
27 char name[ETH_GSTRING_LEN];
28 unsigned long val;
29};
30
31enum 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
39static 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
46struct dsa_loop_port {
47 struct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX];
48};
49
98cd1552
FF
50#define DSA_LOOP_VLANS 5
51
52struct 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;
484c0172 57 struct dsa_loop_port ports[DSA_MAX_PORTS];
98cd1552
FF
58 u16 pvid;
59};
60
61static struct phy_device *phydevs[PHY_MAX_ADDR];
62
5ed4e3eb 63static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,
4d776482
FF
64 int port,
65 enum dsa_tag_protocol mp)
98cd1552 66{
e52cde71 67 dev_dbg(ds->dev, "%s: port: %d\n", __func__, port);
98cd1552
FF
68
69 return DSA_TAG_PROTO_NONE;
70}
71
72static int dsa_loop_setup(struct dsa_switch *ds)
73{
484c0172
FF
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
98cd1552
FF
81 dev_dbg(ds->dev, "%s\n", __func__);
82
83 return 0;
84}
85
89f09048 86static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)
484c0172 87{
96cbddcd 88 if (sset != ETH_SS_STATS && sset != ETH_SS_PHY_STATS)
89f09048
FF
89 return 0;
90
484c0172
FF
91 return __DSA_LOOP_CNT_MAX;
92}
93
89f09048
FF
94static void dsa_loop_get_strings(struct dsa_switch *ds, int port,
95 u32 stringset, uint8_t *data)
484c0172
FF
96{
97 struct dsa_loop_priv *ps = ds->priv;
98 unsigned int i;
99
96cbddcd 100 if (stringset != ETH_SS_STATS && stringset != ETH_SS_PHY_STATS)
89f09048
FF
101 return;
102
484c0172
FF
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
108static 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
98cd1552
FF
118static 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;
484c0172 122 int ret;
98cd1552 123
484c0172
FF
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;
98cd1552
FF
131}
132
133static 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;
484c0172 138 int ret;
98cd1552 139
484c0172
FF
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;
98cd1552
FF
147}
148
149static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,
150 struct net_device *bridge)
151{
e52cde71
FF
152 dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
153 __func__, port, bridge->name);
98cd1552
FF
154
155 return 0;
156}
157
158static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,
159 struct net_device *bridge)
160{
e52cde71
FF
161 dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
162 __func__, port, bridge->name);
98cd1552
FF
163}
164
165static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,
166 u8 state)
167{
e52cde71
FF
168 dev_dbg(ds->dev, "%s: port: %d, state: %d\n",
169 __func__, port, state);
98cd1552
FF
170}
171
172static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,
173 bool vlan_filtering)
174{
e52cde71
FF
175 dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n",
176 __func__, port, vlan_filtering);
98cd1552
FF
177
178 return 0;
179}
180
80e02360
VD
181static int
182dsa_loop_port_vlan_prepare(struct dsa_switch *ds, int port,
183 const struct switchdev_obj_port_vlan *vlan)
98cd1552
FF
184{
185 struct dsa_loop_priv *ps = ds->priv;
186 struct mii_bus *bus = ps->bus;
187
e52cde71
FF
188 dev_dbg(ds->dev, "%s: port: %d, vlan: %d-%d",
189 __func__, port, vlan->vid_begin, vlan->vid_end);
98cd1552
FF
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
200static void dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,
80e02360 201 const struct switchdev_obj_port_vlan *vlan)
98cd1552
FF
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
98cd1552
FF
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);
e52cde71
FF
221
222 dev_dbg(ds->dev, "%s: port: %d vlan: %d, %stagged, pvid: %d\n",
223 __func__, port, vid, untagged ? "un" : "", pvid);
98cd1552
FF
224 }
225
226 if (pvid)
227 ps->pvid = vid;
228}
229
230static 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;
5865ccce 237 u16 vid, pvid = ps->pvid;
98cd1552 238
98cd1552
FF
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;
e52cde71
FF
251
252 dev_dbg(ds->dev, "%s: port: %d vlan: %d, %stagged, pvid: %d\n",
253 __func__, port, vid, untagged ? "un" : "", pvid);
98cd1552
FF
254 }
255 ps->pvid = pvid;
256
257 return 0;
258}
259
d78d6776 260static const struct dsa_switch_ops dsa_loop_driver = {
98cd1552
FF
261 .get_tag_protocol = dsa_loop_get_protocol,
262 .setup = dsa_loop_setup,
484c0172
FF
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,
96cbddcd 266 .get_ethtool_phy_stats = dsa_loop_get_ethtool_stats,
98cd1552
FF
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,
98cd1552
FF
276};
277
278static 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
7e99e347 290 ds = devm_kzalloc(&mdiodev->dev, sizeof(*ds), GFP_KERNEL);
98cd1552
FF
291 if (!ds)
292 return -ENOMEM;
293
7e99e347
VD
294 ds->dev = &mdiodev->dev;
295 ds->num_ports = DSA_MAX_PORTS;
296
98cd1552 297 ps = devm_kzalloc(&mdiodev->dev, sizeof(*ps), GFP_KERNEL);
8ce7aaaa
CJ
298 if (!ps)
299 return -ENOMEM;
300
98cd1552
FF
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
23c9ee49 314 return dsa_register_switch(ds);
98cd1552
FF
315}
316
317static 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
326static 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
98cd1552
FF
336static 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++)
5468e82f 346 phydevs[i] = fixed_phy_register(PHY_POLL, &status, NULL);
98cd1552
FF
347
348 return mdio_driver_register(&dsa_loop_drv);
349}
350module_init(dsa_loop_init);
351
352static void __exit dsa_loop_exit(void)
353{
3407dc8e
FF
354 unsigned int i;
355
98cd1552 356 mdio_driver_unregister(&dsa_loop_drv);
3407dc8e 357 for (i = 0; i < NUM_FIXED_PHYS; i++)
6d9c153a 358 if (!IS_ERR(phydevs[i]))
3407dc8e 359 fixed_phy_unregister(phydevs[i]);
98cd1552
FF
360}
361module_exit(dsa_loop_exit);
362
3047211c 363MODULE_SOFTDEP("pre: dsa_loop_bdinfo");
98cd1552
FF
364MODULE_LICENSE("GPL");
365MODULE_AUTHOR("Florian Fainelli");
366MODULE_DESCRIPTION("DSA loopback driver");