hc
2024-09-20 cf4ce59b3b70238352c7f1729f0f7223214828ad
kernel/drivers/net/dsa/mv88e6060.c
....@@ -1,11 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
34 * Copyright (c) 2008-2009 Marvell Semiconductor
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation; either version 2 of the License, or
8
- * (at your option) any later version.
95 */
106
117 #include <linux/delay.h>
....@@ -18,39 +14,15 @@
1814 #include <net/dsa.h>
1915 #include "mv88e6060.h"
2016
21
-static int reg_read(struct dsa_switch *ds, int addr, int reg)
17
+static int reg_read(struct mv88e6060_priv *priv, int addr, int reg)
2218 {
23
- struct mv88e6060_priv *priv = ds->priv;
24
-
2519 return mdiobus_read_nested(priv->bus, priv->sw_addr + addr, reg);
2620 }
2721
28
-#define REG_READ(addr, reg) \
29
- ({ \
30
- int __ret; \
31
- \
32
- __ret = reg_read(ds, addr, reg); \
33
- if (__ret < 0) \
34
- return __ret; \
35
- __ret; \
36
- })
37
-
38
-
39
-static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
22
+static int reg_write(struct mv88e6060_priv *priv, int addr, int reg, u16 val)
4023 {
41
- struct mv88e6060_priv *priv = ds->priv;
42
-
4324 return mdiobus_write_nested(priv->bus, priv->sw_addr + addr, reg, val);
4425 }
45
-
46
-#define REG_WRITE(addr, reg, val) \
47
- ({ \
48
- int __ret; \
49
- \
50
- __ret = reg_write(ds, addr, reg, val); \
51
- if (__ret < 0) \
52
- return __ret; \
53
- })
5426
5527 static const char *mv88e6060_get_name(struct mii_bus *bus, int sw_addr)
5628 {
....@@ -71,33 +43,13 @@
7143 }
7244
7345 static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds,
74
- int port)
46
+ int port,
47
+ enum dsa_tag_protocol m)
7548 {
7649 return DSA_TAG_PROTO_TRAILER;
7750 }
7851
79
-static const char *mv88e6060_drv_probe(struct device *dsa_dev,
80
- struct device *host_dev, int sw_addr,
81
- void **_priv)
82
-{
83
- struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev);
84
- struct mv88e6060_priv *priv;
85
- const char *name;
86
-
87
- name = mv88e6060_get_name(bus, sw_addr);
88
- if (name) {
89
- priv = devm_kzalloc(dsa_dev, sizeof(*priv), GFP_KERNEL);
90
- if (!priv)
91
- return NULL;
92
- *_priv = priv;
93
- priv->bus = bus;
94
- priv->sw_addr = sw_addr;
95
- }
96
-
97
- return name;
98
-}
99
-
100
-static int mv88e6060_switch_reset(struct dsa_switch *ds)
52
+static int mv88e6060_switch_reset(struct mv88e6060_priv *priv)
10153 {
10254 int i;
10355 int ret;
....@@ -105,23 +57,32 @@
10557
10658 /* Set all ports to the disabled state. */
10759 for (i = 0; i < MV88E6060_PORTS; i++) {
108
- ret = REG_READ(REG_PORT(i), PORT_CONTROL);
109
- REG_WRITE(REG_PORT(i), PORT_CONTROL,
110
- ret & ~PORT_CONTROL_STATE_MASK);
60
+ ret = reg_read(priv, REG_PORT(i), PORT_CONTROL);
61
+ if (ret < 0)
62
+ return ret;
63
+ ret = reg_write(priv, REG_PORT(i), PORT_CONTROL,
64
+ ret & ~PORT_CONTROL_STATE_MASK);
65
+ if (ret)
66
+ return ret;
11167 }
11268
11369 /* Wait for transmit queues to drain. */
11470 usleep_range(2000, 4000);
11571
11672 /* Reset the switch. */
117
- REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
118
- GLOBAL_ATU_CONTROL_SWRESET |
119
- GLOBAL_ATU_CONTROL_LEARNDIS);
73
+ ret = reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL,
74
+ GLOBAL_ATU_CONTROL_SWRESET |
75
+ GLOBAL_ATU_CONTROL_LEARNDIS);
76
+ if (ret)
77
+ return ret;
12078
12179 /* Wait up to one second for reset to complete. */
12280 timeout = jiffies + 1 * HZ;
12381 while (time_before(jiffies, timeout)) {
124
- ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
82
+ ret = reg_read(priv, REG_GLOBAL, GLOBAL_STATUS);
83
+ if (ret < 0)
84
+ return ret;
85
+
12586 if (ret & GLOBAL_STATUS_INIT_READY)
12687 break;
12788
....@@ -133,61 +94,72 @@
13394 return 0;
13495 }
13596
136
-static int mv88e6060_setup_global(struct dsa_switch *ds)
97
+static int mv88e6060_setup_global(struct mv88e6060_priv *priv)
13798 {
99
+ int ret;
100
+
138101 /* Disable discarding of frames with excessive collisions,
139102 * set the maximum frame size to 1536 bytes, and mask all
140103 * interrupt sources.
141104 */
142
- REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536);
105
+ ret = reg_write(priv, REG_GLOBAL, GLOBAL_CONTROL,
106
+ GLOBAL_CONTROL_MAX_FRAME_1536);
107
+ if (ret)
108
+ return ret;
143109
144110 /* Disable automatic address learning.
145111 */
146
- REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
147
- GLOBAL_ATU_CONTROL_LEARNDIS);
148
-
149
- return 0;
112
+ return reg_write(priv, REG_GLOBAL, GLOBAL_ATU_CONTROL,
113
+ GLOBAL_ATU_CONTROL_LEARNDIS);
150114 }
151115
152
-static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
116
+static int mv88e6060_setup_port(struct mv88e6060_priv *priv, int p)
153117 {
154118 int addr = REG_PORT(p);
119
+ int ret;
120
+
121
+ if (dsa_is_unused_port(priv->ds, p))
122
+ return 0;
155123
156124 /* Do not force flow control, disable Ingress and Egress
157125 * Header tagging, disable VLAN tunneling, and set the port
158126 * state to Forwarding. Additionally, if this is the CPU
159127 * port, enable Ingress and Egress Trailer tagging mode.
160128 */
161
- REG_WRITE(addr, PORT_CONTROL,
162
- dsa_is_cpu_port(ds, p) ?
129
+ ret = reg_write(priv, addr, PORT_CONTROL,
130
+ dsa_is_cpu_port(priv->ds, p) ?
163131 PORT_CONTROL_TRAILER |
164132 PORT_CONTROL_INGRESS_MODE |
165133 PORT_CONTROL_STATE_FORWARDING :
166134 PORT_CONTROL_STATE_FORWARDING);
135
+ if (ret)
136
+ return ret;
167137
168138 /* Port based VLAN map: give each port its own address
169139 * database, allow the CPU port to talk to each of the 'real'
170140 * ports, and allow each of the 'real' ports to only talk to
171141 * the CPU port.
172142 */
173
- REG_WRITE(addr, PORT_VLAN_MAP,
174
- ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
175
- (dsa_is_cpu_port(ds, p) ? dsa_user_ports(ds) :
176
- BIT(dsa_to_port(ds, p)->cpu_dp->index)));
143
+ ret = reg_write(priv, addr, PORT_VLAN_MAP,
144
+ ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
145
+ (dsa_is_cpu_port(priv->ds, p) ?
146
+ dsa_user_ports(priv->ds) :
147
+ BIT(dsa_to_port(priv->ds, p)->cpu_dp->index)));
148
+ if (ret)
149
+ return ret;
177150
178151 /* Port Association Vector: when learning source addresses
179152 * of packets, add the address to the address database using
180153 * a port bitmap that has only the bit for this port set and
181154 * the other bits clear.
182155 */
183
- REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p));
184
-
185
- return 0;
156
+ return reg_write(priv, addr, PORT_ASSOC_VECTOR, BIT(p));
186157 }
187158
188
-static int mv88e6060_setup_addr(struct dsa_switch *ds)
159
+static int mv88e6060_setup_addr(struct mv88e6060_priv *priv)
189160 {
190161 u8 addr[ETH_ALEN];
162
+ int ret;
191163 u16 val;
192164
193165 eth_random_addr(addr);
....@@ -199,34 +171,43 @@
199171 */
200172 val &= 0xfeff;
201173
202
- REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, val);
203
- REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
204
- REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
174
+ ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_01, val);
175
+ if (ret)
176
+ return ret;
205177
206
- return 0;
178
+ ret = reg_write(priv, REG_GLOBAL, GLOBAL_MAC_23,
179
+ (addr[2] << 8) | addr[3]);
180
+ if (ret)
181
+ return ret;
182
+
183
+ return reg_write(priv, REG_GLOBAL, GLOBAL_MAC_45,
184
+ (addr[4] << 8) | addr[5]);
207185 }
208186
209187 static int mv88e6060_setup(struct dsa_switch *ds)
210188 {
189
+ struct mv88e6060_priv *priv = ds->priv;
211190 int ret;
212191 int i;
213192
214
- ret = mv88e6060_switch_reset(ds);
193
+ priv->ds = ds;
194
+
195
+ ret = mv88e6060_switch_reset(priv);
215196 if (ret < 0)
216197 return ret;
217198
218199 /* @@@ initialise atu */
219200
220
- ret = mv88e6060_setup_global(ds);
201
+ ret = mv88e6060_setup_global(priv);
221202 if (ret < 0)
222203 return ret;
223204
224
- ret = mv88e6060_setup_addr(ds);
205
+ ret = mv88e6060_setup_addr(priv);
225206 if (ret < 0)
226207 return ret;
227208
228209 for (i = 0; i < MV88E6060_PORTS; i++) {
229
- ret = mv88e6060_setup_port(ds, i);
210
+ ret = mv88e6060_setup_port(priv, i);
230211 if (ret < 0)
231212 return ret;
232213 }
....@@ -243,51 +224,95 @@
243224
244225 static int mv88e6060_phy_read(struct dsa_switch *ds, int port, int regnum)
245226 {
227
+ struct mv88e6060_priv *priv = ds->priv;
246228 int addr;
247229
248230 addr = mv88e6060_port_to_phy_addr(port);
249231 if (addr == -1)
250232 return 0xffff;
251233
252
- return reg_read(ds, addr, regnum);
234
+ return reg_read(priv, addr, regnum);
253235 }
254236
255237 static int
256238 mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
257239 {
240
+ struct mv88e6060_priv *priv = ds->priv;
258241 int addr;
259242
260243 addr = mv88e6060_port_to_phy_addr(port);
261244 if (addr == -1)
262245 return 0xffff;
263246
264
- return reg_write(ds, addr, regnum, val);
247
+ return reg_write(priv, addr, regnum, val);
265248 }
266249
267250 static const struct dsa_switch_ops mv88e6060_switch_ops = {
268251 .get_tag_protocol = mv88e6060_get_tag_protocol,
269
- .probe = mv88e6060_drv_probe,
270252 .setup = mv88e6060_setup,
271253 .phy_read = mv88e6060_phy_read,
272254 .phy_write = mv88e6060_phy_write,
273255 };
274256
275
-static struct dsa_switch_driver mv88e6060_switch_drv = {
276
- .ops = &mv88e6060_switch_ops,
257
+static int mv88e6060_probe(struct mdio_device *mdiodev)
258
+{
259
+ struct device *dev = &mdiodev->dev;
260
+ struct mv88e6060_priv *priv;
261
+ struct dsa_switch *ds;
262
+ const char *name;
263
+
264
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
265
+ if (!priv)
266
+ return -ENOMEM;
267
+
268
+ priv->bus = mdiodev->bus;
269
+ priv->sw_addr = mdiodev->addr;
270
+
271
+ name = mv88e6060_get_name(priv->bus, priv->sw_addr);
272
+ if (!name)
273
+ return -ENODEV;
274
+
275
+ dev_info(dev, "switch %s detected\n", name);
276
+
277
+ ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
278
+ if (!ds)
279
+ return -ENOMEM;
280
+
281
+ ds->dev = dev;
282
+ ds->num_ports = MV88E6060_PORTS;
283
+ ds->priv = priv;
284
+ ds->dev = dev;
285
+ ds->ops = &mv88e6060_switch_ops;
286
+
287
+ dev_set_drvdata(dev, ds);
288
+
289
+ return dsa_register_switch(ds);
290
+}
291
+
292
+static void mv88e6060_remove(struct mdio_device *mdiodev)
293
+{
294
+ struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
295
+
296
+ dsa_unregister_switch(ds);
297
+}
298
+
299
+static const struct of_device_id mv88e6060_of_match[] = {
300
+ {
301
+ .compatible = "marvell,mv88e6060",
302
+ },
303
+ { /* sentinel */ },
277304 };
278305
279
-static int __init mv88e6060_init(void)
280
-{
281
- register_switch_driver(&mv88e6060_switch_drv);
282
- return 0;
283
-}
284
-module_init(mv88e6060_init);
306
+static struct mdio_driver mv88e6060_driver = {
307
+ .probe = mv88e6060_probe,
308
+ .remove = mv88e6060_remove,
309
+ .mdiodrv.driver = {
310
+ .name = "mv88e6060",
311
+ .of_match_table = mv88e6060_of_match,
312
+ },
313
+};
285314
286
-static void __exit mv88e6060_cleanup(void)
287
-{
288
- unregister_switch_driver(&mv88e6060_switch_drv);
289
-}
290
-module_exit(mv88e6060_cleanup);
315
+mdio_module_driver(mv88e6060_driver);
291316
292317 MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
293318 MODULE_DESCRIPTION("Driver for Marvell 88E6060 ethernet switch chip");