diff options
author | Andrew Lunn <andrew@lunn.ch> | 2019-04-27 20:56:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-04-30 23:15:35 -0400 |
commit | 93e86b3bc842c159a60e6987444bf3952adcd4db (patch) | |
tree | 8eaf6bda037dcc454785d16414cecbdcf069b335 | |
parent | 2f8e7ece4a624b07e4ff3846adbf6484ee632f59 (diff) |
net: dsa: Remove legacy probing support
Now that all drivers can be probed using more traditional methods,
remove the legacy probe code.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/dsa.h | 23 | ||||
-rw-r--r-- | net/dsa/Kconfig | 9 | ||||
-rw-r--r-- | net/dsa/Makefile | 1 | ||||
-rw-r--r-- | net/dsa/dsa.c | 5 | ||||
-rw-r--r-- | net/dsa/dsa_priv.h | 12 | ||||
-rw-r--r-- | net/dsa/legacy.c | 747 |
6 files changed, 0 insertions, 797 deletions
diff --git a/include/net/dsa.h b/include/net/dsa.h index 1e6b4efc80b9..18db7b8e7a8e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h | |||
@@ -318,15 +318,6 @@ static inline bool dsa_port_is_vlan_filtering(const struct dsa_port *dp) | |||
318 | typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid, | 318 | typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid, |
319 | bool is_static, void *data); | 319 | bool is_static, void *data); |
320 | struct dsa_switch_ops { | 320 | struct dsa_switch_ops { |
321 | #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) | ||
322 | /* | ||
323 | * Legacy probing. | ||
324 | */ | ||
325 | const char *(*probe)(struct device *dsa_dev, | ||
326 | struct device *host_dev, int sw_addr, | ||
327 | void **priv); | ||
328 | #endif | ||
329 | |||
330 | enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds, | 321 | enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds, |
331 | int port); | 322 | int port); |
332 | 323 | ||
@@ -516,20 +507,6 @@ struct dsa_switch_driver { | |||
516 | const struct dsa_switch_ops *ops; | 507 | const struct dsa_switch_ops *ops; |
517 | }; | 508 | }; |
518 | 509 | ||
519 | #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) | ||
520 | /* Legacy driver registration */ | ||
521 | void register_switch_driver(struct dsa_switch_driver *type); | ||
522 | void unregister_switch_driver(struct dsa_switch_driver *type); | ||
523 | struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev); | ||
524 | |||
525 | #else | ||
526 | static inline void register_switch_driver(struct dsa_switch_driver *type) { } | ||
527 | static inline void unregister_switch_driver(struct dsa_switch_driver *type) { } | ||
528 | static inline struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev) | ||
529 | { | ||
530 | return NULL; | ||
531 | } | ||
532 | #endif | ||
533 | struct net_device *dsa_dev_to_net_device(struct device *dev); | 510 | struct net_device *dsa_dev_to_net_device(struct device *dev); |
534 | 511 | ||
535 | /* Keep inline for faster access in hot path */ | 512 | /* Keep inline for faster access in hot path */ |
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 1f48642089ea..c0734028c7dc 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig | |||
@@ -17,15 +17,6 @@ menuconfig NET_DSA | |||
17 | 17 | ||
18 | if NET_DSA | 18 | if NET_DSA |
19 | 19 | ||
20 | config NET_DSA_LEGACY | ||
21 | bool "Support for older platform device and Device Tree registration" | ||
22 | default y | ||
23 | ---help--- | ||
24 | Say Y if you want to enable support for the older platform device and | ||
25 | deprecated Device Tree binding registration. | ||
26 | |||
27 | This feature is scheduled for removal in 4.17. | ||
28 | |||
29 | config NET_DSA_TAG_BRCM_COMMON | 20 | config NET_DSA_TAG_BRCM_COMMON |
30 | tristate | 21 | tristate |
31 | default n | 22 | default n |
diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 717ac1618100..8a737b6ee94c 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile | |||
@@ -2,7 +2,6 @@ | |||
2 | # the core | 2 | # the core |
3 | obj-$(CONFIG_NET_DSA) += dsa_core.o | 3 | obj-$(CONFIG_NET_DSA) += dsa_core.o |
4 | dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o | 4 | dsa_core-y += dsa.o dsa2.o master.o port.o slave.o switch.o |
5 | dsa_core-$(CONFIG_NET_DSA_LEGACY) += legacy.o | ||
6 | 5 | ||
7 | # tagging formats | 6 | # tagging formats |
8 | obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o | 7 | obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o |
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ba04c78633be..9e1fc0b08290 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
@@ -346,10 +346,6 @@ static int __init dsa_init_module(void) | |||
346 | if (rc) | 346 | if (rc) |
347 | return rc; | 347 | return rc; |
348 | 348 | ||
349 | rc = dsa_legacy_register(); | ||
350 | if (rc) | ||
351 | return rc; | ||
352 | |||
353 | dev_add_pack(&dsa_pack_type); | 349 | dev_add_pack(&dsa_pack_type); |
354 | 350 | ||
355 | dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops), | 351 | dsa_tag_driver_register(&DSA_TAG_DRIVER_NAME(none_ops), |
@@ -365,7 +361,6 @@ static void __exit dsa_cleanup_module(void) | |||
365 | 361 | ||
366 | dsa_slave_unregister_notifier(); | 362 | dsa_slave_unregister_notifier(); |
367 | dev_remove_pack(&dsa_pack_type); | 363 | dev_remove_pack(&dsa_pack_type); |
368 | dsa_legacy_unregister(); | ||
369 | destroy_workqueue(dsa_owq); | 364 | destroy_workqueue(dsa_owq); |
370 | } | 365 | } |
371 | module_exit(dsa_cleanup_module); | 366 | module_exit(dsa_cleanup_module); |
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 37751b505572..b434f5ff55ab 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h | |||
@@ -90,18 +90,6 @@ void dsa_tag_driver_put(const struct dsa_device_ops *ops); | |||
90 | bool dsa_schedule_work(struct work_struct *work); | 90 | bool dsa_schedule_work(struct work_struct *work); |
91 | const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops); | 91 | const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops); |
92 | 92 | ||
93 | /* legacy.c */ | ||
94 | #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) | ||
95 | int dsa_legacy_register(void); | ||
96 | void dsa_legacy_unregister(void); | ||
97 | #else | ||
98 | static inline int dsa_legacy_register(void) | ||
99 | { | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static inline void dsa_legacy_unregister(void) { } | ||
104 | #endif | ||
105 | int dsa_legacy_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | 93 | int dsa_legacy_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], |
106 | struct net_device *dev, | 94 | struct net_device *dev, |
107 | const unsigned char *addr, u16 vid, | 95 | const unsigned char *addr, u16 vid, |
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c deleted file mode 100644 index 219f4fa7ff4b..000000000000 --- a/net/dsa/legacy.c +++ /dev/null | |||
@@ -1,747 +0,0 @@ | |||
1 | /* | ||
2 | * net/dsa/legacy.c - Hardware switch handling | ||
3 | * Copyright (c) 2008-2009 Marvell Semiconductor | ||
4 | * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/device.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_mdio.h> | ||
19 | #include <linux/of_platform.h> | ||
20 | #include <linux/of_net.h> | ||
21 | #include <linux/netdevice.h> | ||
22 | #include <linux/sysfs.h> | ||
23 | #include <linux/phy_fixed.h> | ||
24 | #include <linux/etherdevice.h> | ||
25 | |||
26 | #include "dsa_priv.h" | ||
27 | |||
28 | /* switch driver registration ***********************************************/ | ||
29 | static DEFINE_MUTEX(dsa_switch_drivers_mutex); | ||
30 | static LIST_HEAD(dsa_switch_drivers); | ||
31 | |||
32 | void register_switch_driver(struct dsa_switch_driver *drv) | ||
33 | { | ||
34 | mutex_lock(&dsa_switch_drivers_mutex); | ||
35 | list_add_tail(&drv->list, &dsa_switch_drivers); | ||
36 | mutex_unlock(&dsa_switch_drivers_mutex); | ||
37 | } | ||
38 | EXPORT_SYMBOL_GPL(register_switch_driver); | ||
39 | |||
40 | void unregister_switch_driver(struct dsa_switch_driver *drv) | ||
41 | { | ||
42 | mutex_lock(&dsa_switch_drivers_mutex); | ||
43 | list_del_init(&drv->list); | ||
44 | mutex_unlock(&dsa_switch_drivers_mutex); | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(unregister_switch_driver); | ||
47 | |||
48 | static const struct dsa_switch_ops * | ||
49 | dsa_switch_probe(struct device *parent, struct device *host_dev, int sw_addr, | ||
50 | const char **_name, void **priv) | ||
51 | { | ||
52 | const struct dsa_switch_ops *ret; | ||
53 | struct list_head *list; | ||
54 | const char *name; | ||
55 | |||
56 | ret = NULL; | ||
57 | name = NULL; | ||
58 | |||
59 | mutex_lock(&dsa_switch_drivers_mutex); | ||
60 | list_for_each(list, &dsa_switch_drivers) { | ||
61 | const struct dsa_switch_ops *ops; | ||
62 | struct dsa_switch_driver *drv; | ||
63 | |||
64 | drv = list_entry(list, struct dsa_switch_driver, list); | ||
65 | ops = drv->ops; | ||
66 | |||
67 | name = ops->probe(parent, host_dev, sw_addr, priv); | ||
68 | if (name != NULL) { | ||
69 | ret = ops; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | mutex_unlock(&dsa_switch_drivers_mutex); | ||
74 | |||
75 | *_name = name; | ||
76 | |||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | /* basic switch operations **************************************************/ | ||
81 | static int dsa_cpu_dsa_setups(struct dsa_switch *ds) | ||
82 | { | ||
83 | int ret, port; | ||
84 | |||
85 | for (port = 0; port < ds->num_ports; port++) { | ||
86 | if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) | ||
87 | continue; | ||
88 | |||
89 | ret = dsa_port_link_register_of(&ds->ports[port]); | ||
90 | if (ret) | ||
91 | return ret; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int dsa_switch_setup_one(struct dsa_switch *ds, | ||
97 | struct net_device *master) | ||
98 | { | ||
99 | const struct dsa_switch_ops *ops = ds->ops; | ||
100 | struct dsa_switch_tree *dst = ds->dst; | ||
101 | struct dsa_chip_data *cd = ds->cd; | ||
102 | bool valid_name_found = false; | ||
103 | int index = ds->index; | ||
104 | struct dsa_port *dp; | ||
105 | int i, ret; | ||
106 | |||
107 | /* | ||
108 | * Validate supplied switch configuration. | ||
109 | */ | ||
110 | for (i = 0; i < ds->num_ports; i++) { | ||
111 | char *name; | ||
112 | |||
113 | dp = &ds->ports[i]; | ||
114 | |||
115 | name = cd->port_names[i]; | ||
116 | if (name == NULL) | ||
117 | continue; | ||
118 | dp->name = name; | ||
119 | |||
120 | if (!strcmp(name, "cpu")) { | ||
121 | if (dst->cpu_dp) { | ||
122 | netdev_err(master, | ||
123 | "multiple cpu ports?!\n"); | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | dst->cpu_dp = &ds->ports[i]; | ||
127 | dst->cpu_dp->master = master; | ||
128 | dp->type = DSA_PORT_TYPE_CPU; | ||
129 | } else if (!strcmp(name, "dsa")) { | ||
130 | dp->type = DSA_PORT_TYPE_DSA; | ||
131 | } else { | ||
132 | dp->type = DSA_PORT_TYPE_USER; | ||
133 | } | ||
134 | valid_name_found = true; | ||
135 | } | ||
136 | |||
137 | if (!valid_name_found && i == ds->num_ports) | ||
138 | return -EINVAL; | ||
139 | |||
140 | /* Make the built-in MII bus mask match the number of ports, | ||
141 | * switch drivers can override this later | ||
142 | */ | ||
143 | ds->phys_mii_mask |= dsa_user_ports(ds); | ||
144 | |||
145 | /* | ||
146 | * If the CPU connects to this switch, set the switch tree | ||
147 | * tagging protocol to the preferred tagging format of this | ||
148 | * switch. | ||
149 | */ | ||
150 | if (dst->cpu_dp->ds == ds) { | ||
151 | const struct dsa_device_ops *tag_ops; | ||
152 | enum dsa_tag_protocol tag_protocol; | ||
153 | |||
154 | tag_protocol = ops->get_tag_protocol(ds, dst->cpu_dp->index); | ||
155 | tag_ops = dsa_tag_driver_get(tag_protocol); | ||
156 | if (IS_ERR(tag_ops)) | ||
157 | return PTR_ERR(tag_ops); | ||
158 | |||
159 | dst->cpu_dp->tag_ops = tag_ops; | ||
160 | |||
161 | /* Few copies for faster access in master receive hot path */ | ||
162 | dst->cpu_dp->rcv = dst->cpu_dp->tag_ops->rcv; | ||
163 | dst->cpu_dp->dst = dst; | ||
164 | } | ||
165 | |||
166 | dsa_tag_driver_put(dst->cpu_dp->tag_ops); | ||
167 | |||
168 | memcpy(ds->rtable, cd->rtable, sizeof(ds->rtable)); | ||
169 | |||
170 | /* | ||
171 | * Do basic register setup. | ||
172 | */ | ||
173 | ret = ops->setup(ds); | ||
174 | if (ret < 0) | ||
175 | return ret; | ||
176 | |||
177 | ret = dsa_switch_register_notifier(ds); | ||
178 | if (ret) | ||
179 | return ret; | ||
180 | |||
181 | if (!ds->slave_mii_bus && ops->phy_read) { | ||
182 | ds->slave_mii_bus = devm_mdiobus_alloc(ds->dev); | ||
183 | if (!ds->slave_mii_bus) | ||
184 | return -ENOMEM; | ||
185 | dsa_slave_mii_bus_init(ds); | ||
186 | |||
187 | ret = mdiobus_register(ds->slave_mii_bus); | ||
188 | if (ret < 0) | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * Create network devices for physical switch ports. | ||
194 | */ | ||
195 | for (i = 0; i < ds->num_ports; i++) { | ||
196 | ds->ports[i].dn = cd->port_dn[i]; | ||
197 | ds->ports[i].cpu_dp = dst->cpu_dp; | ||
198 | |||
199 | if (!dsa_is_user_port(ds, i)) | ||
200 | continue; | ||
201 | |||
202 | ret = dsa_slave_create(&ds->ports[i]); | ||
203 | if (ret < 0) | ||
204 | netdev_err(master, "[%d]: can't create dsa slave device for port %d(%s): %d\n", | ||
205 | index, i, cd->port_names[i], ret); | ||
206 | } | ||
207 | |||
208 | /* Perform configuration of the CPU and DSA ports */ | ||
209 | ret = dsa_cpu_dsa_setups(ds); | ||
210 | if (ret < 0) | ||
211 | netdev_err(master, "[%d] : can't configure CPU and DSA ports\n", | ||
212 | index); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static struct dsa_switch * | ||
218 | dsa_switch_setup(struct dsa_switch_tree *dst, struct net_device *master, | ||
219 | int index, struct device *parent, struct device *host_dev) | ||
220 | { | ||
221 | struct dsa_chip_data *cd = dst->pd->chip + index; | ||
222 | const struct dsa_switch_ops *ops; | ||
223 | struct dsa_switch *ds; | ||
224 | int ret; | ||
225 | const char *name; | ||
226 | void *priv; | ||
227 | |||
228 | /* | ||
229 | * Probe for switch model. | ||
230 | */ | ||
231 | ops = dsa_switch_probe(parent, host_dev, cd->sw_addr, &name, &priv); | ||
232 | if (!ops) { | ||
233 | netdev_err(master, "[%d]: could not detect attached switch\n", | ||
234 | index); | ||
235 | return ERR_PTR(-EINVAL); | ||
236 | } | ||
237 | netdev_info(master, "[%d]: detected a %s switch\n", | ||
238 | index, name); | ||
239 | |||
240 | |||
241 | /* | ||
242 | * Allocate and initialise switch state. | ||
243 | */ | ||
244 | ds = dsa_switch_alloc(parent, DSA_MAX_PORTS); | ||
245 | if (!ds) | ||
246 | return ERR_PTR(-ENOMEM); | ||
247 | |||
248 | ds->dst = dst; | ||
249 | ds->index = index; | ||
250 | ds->cd = cd; | ||
251 | ds->ops = ops; | ||
252 | ds->priv = priv; | ||
253 | |||
254 | ret = dsa_switch_setup_one(ds, master); | ||
255 | if (ret) | ||
256 | return ERR_PTR(ret); | ||
257 | |||
258 | return ds; | ||
259 | } | ||
260 | |||
261 | static void dsa_switch_destroy(struct dsa_switch *ds) | ||
262 | { | ||
263 | int port; | ||
264 | |||
265 | /* Destroy network devices for physical switch ports. */ | ||
266 | for (port = 0; port < ds->num_ports; port++) { | ||
267 | if (!dsa_is_user_port(ds, port)) | ||
268 | continue; | ||
269 | |||
270 | if (!ds->ports[port].slave) | ||
271 | continue; | ||
272 | |||
273 | dsa_slave_destroy(ds->ports[port].slave); | ||
274 | } | ||
275 | |||
276 | /* Disable configuration of the CPU and DSA ports */ | ||
277 | for (port = 0; port < ds->num_ports; port++) { | ||
278 | if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) | ||
279 | continue; | ||
280 | dsa_port_link_unregister_of(&ds->ports[port]); | ||
281 | } | ||
282 | |||
283 | if (ds->slave_mii_bus && ds->ops->phy_read) | ||
284 | mdiobus_unregister(ds->slave_mii_bus); | ||
285 | |||
286 | dsa_switch_unregister_notifier(ds); | ||
287 | } | ||
288 | |||
289 | /* platform driver init and cleanup *****************************************/ | ||
290 | static int dev_is_class(struct device *dev, void *class) | ||
291 | { | ||
292 | if (dev->class != NULL && !strcmp(dev->class->name, class)) | ||
293 | return 1; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static struct device *dev_find_class(struct device *parent, char *class) | ||
299 | { | ||
300 | if (dev_is_class(parent, class)) { | ||
301 | get_device(parent); | ||
302 | return parent; | ||
303 | } | ||
304 | |||
305 | return device_find_child(parent, class, dev_is_class); | ||
306 | } | ||
307 | |||
308 | struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev) | ||
309 | { | ||
310 | struct device *d; | ||
311 | |||
312 | d = dev_find_class(dev, "mdio_bus"); | ||
313 | if (d != NULL) { | ||
314 | struct mii_bus *bus; | ||
315 | |||
316 | bus = to_mii_bus(d); | ||
317 | put_device(d); | ||
318 | |||
319 | return bus; | ||
320 | } | ||
321 | |||
322 | return NULL; | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(dsa_host_dev_to_mii_bus); | ||
325 | |||
326 | #ifdef CONFIG_OF | ||
327 | static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, | ||
328 | struct dsa_chip_data *cd, | ||
329 | int chip_index, int port_index, | ||
330 | struct device_node *link) | ||
331 | { | ||
332 | const __be32 *reg; | ||
333 | int link_sw_addr; | ||
334 | struct device_node *parent_sw; | ||
335 | int len; | ||
336 | |||
337 | parent_sw = of_get_parent(link); | ||
338 | if (!parent_sw) | ||
339 | return -EINVAL; | ||
340 | |||
341 | reg = of_get_property(parent_sw, "reg", &len); | ||
342 | if (!reg || (len != sizeof(*reg) * 2)) | ||
343 | return -EINVAL; | ||
344 | |||
345 | /* | ||
346 | * Get the destination switch number from the second field of its 'reg' | ||
347 | * property, i.e. for "reg = <0x19 1>" sw_addr is '1'. | ||
348 | */ | ||
349 | link_sw_addr = be32_to_cpup(reg + 1); | ||
350 | |||
351 | if (link_sw_addr >= pd->nr_chips) | ||
352 | return -EINVAL; | ||
353 | |||
354 | cd->rtable[link_sw_addr] = port_index; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int dsa_of_probe_links(struct dsa_platform_data *pd, | ||
360 | struct dsa_chip_data *cd, | ||
361 | int chip_index, int port_index, | ||
362 | struct device_node *port, | ||
363 | const char *port_name) | ||
364 | { | ||
365 | struct device_node *link; | ||
366 | int link_index; | ||
367 | int ret; | ||
368 | |||
369 | for (link_index = 0;; link_index++) { | ||
370 | link = of_parse_phandle(port, "link", link_index); | ||
371 | if (!link) | ||
372 | break; | ||
373 | |||
374 | if (!strcmp(port_name, "dsa") && pd->nr_chips > 1) { | ||
375 | ret = dsa_of_setup_routing_table(pd, cd, chip_index, | ||
376 | port_index, link); | ||
377 | if (ret) | ||
378 | return ret; | ||
379 | } | ||
380 | } | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static void dsa_of_free_platform_data(struct dsa_platform_data *pd) | ||
385 | { | ||
386 | int i; | ||
387 | int port_index; | ||
388 | |||
389 | for (i = 0; i < pd->nr_chips; i++) { | ||
390 | port_index = 0; | ||
391 | while (port_index < DSA_MAX_PORTS) { | ||
392 | kfree(pd->chip[i].port_names[port_index]); | ||
393 | port_index++; | ||
394 | } | ||
395 | |||
396 | /* Drop our reference to the MDIO bus device */ | ||
397 | put_device(pd->chip[i].host_dev); | ||
398 | } | ||
399 | kfree(pd->chip); | ||
400 | } | ||
401 | |||
402 | static int dsa_of_probe(struct device *dev) | ||
403 | { | ||
404 | struct device_node *np = dev->of_node; | ||
405 | struct device_node *child, *mdio, *ethernet, *port; | ||
406 | struct mii_bus *mdio_bus, *mdio_bus_switch; | ||
407 | struct net_device *ethernet_dev; | ||
408 | struct dsa_platform_data *pd; | ||
409 | struct dsa_chip_data *cd; | ||
410 | const char *port_name; | ||
411 | int chip_index, port_index; | ||
412 | const unsigned int *sw_addr, *port_reg; | ||
413 | u32 eeprom_len; | ||
414 | int ret; | ||
415 | |||
416 | mdio = of_parse_phandle(np, "dsa,mii-bus", 0); | ||
417 | if (!mdio) | ||
418 | return -EINVAL; | ||
419 | |||
420 | mdio_bus = of_mdio_find_bus(mdio); | ||
421 | if (!mdio_bus) | ||
422 | return -EPROBE_DEFER; | ||
423 | |||
424 | ethernet = of_parse_phandle(np, "dsa,ethernet", 0); | ||
425 | if (!ethernet) { | ||
426 | ret = -EINVAL; | ||
427 | goto out_put_mdio; | ||
428 | } | ||
429 | |||
430 | ethernet_dev = of_find_net_device_by_node(ethernet); | ||
431 | if (!ethernet_dev) { | ||
432 | ret = -EPROBE_DEFER; | ||
433 | goto out_put_mdio; | ||
434 | } | ||
435 | |||
436 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | ||
437 | if (!pd) { | ||
438 | ret = -ENOMEM; | ||
439 | goto out_put_ethernet; | ||
440 | } | ||
441 | |||
442 | dev->platform_data = pd; | ||
443 | pd->of_netdev = ethernet_dev; | ||
444 | pd->nr_chips = of_get_available_child_count(np); | ||
445 | if (pd->nr_chips > DSA_MAX_SWITCHES) | ||
446 | pd->nr_chips = DSA_MAX_SWITCHES; | ||
447 | |||
448 | pd->chip = kcalloc(pd->nr_chips, sizeof(struct dsa_chip_data), | ||
449 | GFP_KERNEL); | ||
450 | if (!pd->chip) { | ||
451 | ret = -ENOMEM; | ||
452 | goto out_free; | ||
453 | } | ||
454 | |||
455 | chip_index = -1; | ||
456 | for_each_available_child_of_node(np, child) { | ||
457 | int i; | ||
458 | |||
459 | chip_index++; | ||
460 | cd = &pd->chip[chip_index]; | ||
461 | |||
462 | cd->of_node = child; | ||
463 | |||
464 | /* Initialize the routing table */ | ||
465 | for (i = 0; i < DSA_MAX_SWITCHES; ++i) | ||
466 | cd->rtable[i] = DSA_RTABLE_NONE; | ||
467 | |||
468 | /* When assigning the host device, increment its refcount */ | ||
469 | cd->host_dev = get_device(&mdio_bus->dev); | ||
470 | |||
471 | sw_addr = of_get_property(child, "reg", NULL); | ||
472 | if (!sw_addr) | ||
473 | continue; | ||
474 | |||
475 | cd->sw_addr = be32_to_cpup(sw_addr); | ||
476 | if (cd->sw_addr >= PHY_MAX_ADDR) | ||
477 | continue; | ||
478 | |||
479 | if (!of_property_read_u32(child, "eeprom-length", &eeprom_len)) | ||
480 | cd->eeprom_len = eeprom_len; | ||
481 | |||
482 | mdio = of_parse_phandle(child, "mii-bus", 0); | ||
483 | if (mdio) { | ||
484 | mdio_bus_switch = of_mdio_find_bus(mdio); | ||
485 | if (!mdio_bus_switch) { | ||
486 | ret = -EPROBE_DEFER; | ||
487 | goto out_free_chip; | ||
488 | } | ||
489 | |||
490 | /* Drop the mdio_bus device ref, replacing the host | ||
491 | * device with the mdio_bus_switch device, keeping | ||
492 | * the refcount from of_mdio_find_bus() above. | ||
493 | */ | ||
494 | put_device(cd->host_dev); | ||
495 | cd->host_dev = &mdio_bus_switch->dev; | ||
496 | } | ||
497 | |||
498 | for_each_available_child_of_node(child, port) { | ||
499 | port_reg = of_get_property(port, "reg", NULL); | ||
500 | if (!port_reg) | ||
501 | continue; | ||
502 | |||
503 | port_index = be32_to_cpup(port_reg); | ||
504 | if (port_index >= DSA_MAX_PORTS) | ||
505 | break; | ||
506 | |||
507 | port_name = of_get_property(port, "label", NULL); | ||
508 | if (!port_name) | ||
509 | continue; | ||
510 | |||
511 | cd->port_dn[port_index] = port; | ||
512 | |||
513 | cd->port_names[port_index] = kstrdup(port_name, | ||
514 | GFP_KERNEL); | ||
515 | if (!cd->port_names[port_index]) { | ||
516 | ret = -ENOMEM; | ||
517 | goto out_free_chip; | ||
518 | } | ||
519 | |||
520 | ret = dsa_of_probe_links(pd, cd, chip_index, | ||
521 | port_index, port, port_name); | ||
522 | if (ret) | ||
523 | goto out_free_chip; | ||
524 | |||
525 | } | ||
526 | } | ||
527 | |||
528 | /* The individual chips hold their own refcount on the mdio bus, | ||
529 | * so drop ours */ | ||
530 | put_device(&mdio_bus->dev); | ||
531 | |||
532 | return 0; | ||
533 | |||
534 | out_free_chip: | ||
535 | dsa_of_free_platform_data(pd); | ||
536 | out_free: | ||
537 | kfree(pd); | ||
538 | dev->platform_data = NULL; | ||
539 | out_put_ethernet: | ||
540 | put_device(ðernet_dev->dev); | ||
541 | out_put_mdio: | ||
542 | put_device(&mdio_bus->dev); | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | static void dsa_of_remove(struct device *dev) | ||
547 | { | ||
548 | struct dsa_platform_data *pd = dev->platform_data; | ||
549 | |||
550 | if (!dev->of_node) | ||
551 | return; | ||
552 | |||
553 | dsa_of_free_platform_data(pd); | ||
554 | put_device(&pd->of_netdev->dev); | ||
555 | kfree(pd); | ||
556 | } | ||
557 | #else | ||
558 | static inline int dsa_of_probe(struct device *dev) | ||
559 | { | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static inline void dsa_of_remove(struct device *dev) | ||
564 | { | ||
565 | } | ||
566 | #endif | ||
567 | |||
568 | static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, | ||
569 | struct device *parent, struct dsa_platform_data *pd) | ||
570 | { | ||
571 | int i; | ||
572 | unsigned configured = 0; | ||
573 | |||
574 | dst->pd = pd; | ||
575 | |||
576 | for (i = 0; i < pd->nr_chips; i++) { | ||
577 | struct dsa_switch *ds; | ||
578 | |||
579 | ds = dsa_switch_setup(dst, dev, i, parent, pd->chip[i].host_dev); | ||
580 | if (IS_ERR(ds)) { | ||
581 | netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n", | ||
582 | i, PTR_ERR(ds)); | ||
583 | continue; | ||
584 | } | ||
585 | |||
586 | dst->ds[i] = ds; | ||
587 | |||
588 | ++configured; | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * If no switch was found, exit cleanly | ||
593 | */ | ||
594 | if (!configured) | ||
595 | return -EPROBE_DEFER; | ||
596 | |||
597 | return dsa_master_setup(dst->cpu_dp->master, dst->cpu_dp); | ||
598 | } | ||
599 | |||
600 | static int dsa_probe(struct platform_device *pdev) | ||
601 | { | ||
602 | struct dsa_platform_data *pd = pdev->dev.platform_data; | ||
603 | struct net_device *dev; | ||
604 | struct dsa_switch_tree *dst; | ||
605 | int ret; | ||
606 | |||
607 | if (pdev->dev.of_node) { | ||
608 | ret = dsa_of_probe(&pdev->dev); | ||
609 | if (ret) | ||
610 | return ret; | ||
611 | |||
612 | pd = pdev->dev.platform_data; | ||
613 | } | ||
614 | |||
615 | if (pd == NULL || (pd->netdev == NULL && pd->of_netdev == NULL)) | ||
616 | return -EINVAL; | ||
617 | |||
618 | if (pd->of_netdev) { | ||
619 | dev = pd->of_netdev; | ||
620 | dev_hold(dev); | ||
621 | } else { | ||
622 | dev = dsa_dev_to_net_device(pd->netdev); | ||
623 | } | ||
624 | if (dev == NULL) { | ||
625 | ret = -EPROBE_DEFER; | ||
626 | goto out; | ||
627 | } | ||
628 | |||
629 | if (dev->dsa_ptr != NULL) { | ||
630 | dev_put(dev); | ||
631 | ret = -EEXIST; | ||
632 | goto out; | ||
633 | } | ||
634 | |||
635 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); | ||
636 | if (dst == NULL) { | ||
637 | dev_put(dev); | ||
638 | ret = -ENOMEM; | ||
639 | goto out; | ||
640 | } | ||
641 | |||
642 | platform_set_drvdata(pdev, dst); | ||
643 | |||
644 | ret = dsa_setup_dst(dst, dev, &pdev->dev, pd); | ||
645 | if (ret) { | ||
646 | dev_put(dev); | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | return 0; | ||
651 | |||
652 | out: | ||
653 | dsa_of_remove(&pdev->dev); | ||
654 | |||
655 | return ret; | ||
656 | } | ||
657 | |||
658 | static void dsa_remove_dst(struct dsa_switch_tree *dst) | ||
659 | { | ||
660 | int i; | ||
661 | |||
662 | dsa_master_teardown(dst->cpu_dp->master); | ||
663 | |||
664 | for (i = 0; i < dst->pd->nr_chips; i++) { | ||
665 | struct dsa_switch *ds = dst->ds[i]; | ||
666 | |||
667 | if (ds) | ||
668 | dsa_switch_destroy(ds); | ||
669 | } | ||
670 | |||
671 | dev_put(dst->cpu_dp->master); | ||
672 | } | ||
673 | |||
674 | static int dsa_remove(struct platform_device *pdev) | ||
675 | { | ||
676 | struct dsa_switch_tree *dst = platform_get_drvdata(pdev); | ||
677 | |||
678 | dsa_remove_dst(dst); | ||
679 | dsa_of_remove(&pdev->dev); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static void dsa_shutdown(struct platform_device *pdev) | ||
685 | { | ||
686 | } | ||
687 | |||
688 | #ifdef CONFIG_PM_SLEEP | ||
689 | static int dsa_suspend(struct device *d) | ||
690 | { | ||
691 | struct dsa_switch_tree *dst = dev_get_drvdata(d); | ||
692 | int i, ret = 0; | ||
693 | |||
694 | for (i = 0; i < dst->pd->nr_chips; i++) { | ||
695 | struct dsa_switch *ds = dst->ds[i]; | ||
696 | |||
697 | if (ds != NULL) | ||
698 | ret = dsa_switch_suspend(ds); | ||
699 | } | ||
700 | |||
701 | return ret; | ||
702 | } | ||
703 | |||
704 | static int dsa_resume(struct device *d) | ||
705 | { | ||
706 | struct dsa_switch_tree *dst = dev_get_drvdata(d); | ||
707 | int i, ret = 0; | ||
708 | |||
709 | for (i = 0; i < dst->pd->nr_chips; i++) { | ||
710 | struct dsa_switch *ds = dst->ds[i]; | ||
711 | |||
712 | if (ds != NULL) | ||
713 | ret = dsa_switch_resume(ds); | ||
714 | } | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | #endif | ||
719 | |||
720 | static SIMPLE_DEV_PM_OPS(dsa_pm_ops, dsa_suspend, dsa_resume); | ||
721 | |||
722 | static const struct of_device_id dsa_of_match_table[] = { | ||
723 | { .compatible = "marvell,dsa", }, | ||
724 | {} | ||
725 | }; | ||
726 | MODULE_DEVICE_TABLE(of, dsa_of_match_table); | ||
727 | |||
728 | static struct platform_driver dsa_driver = { | ||
729 | .probe = dsa_probe, | ||
730 | .remove = dsa_remove, | ||
731 | .shutdown = dsa_shutdown, | ||
732 | .driver = { | ||
733 | .name = "dsa", | ||
734 | .of_match_table = dsa_of_match_table, | ||
735 | .pm = &dsa_pm_ops, | ||
736 | }, | ||
737 | }; | ||
738 | |||
739 | int dsa_legacy_register(void) | ||
740 | { | ||
741 | return platform_driver_register(&dsa_driver); | ||
742 | } | ||
743 | |||
744 | void dsa_legacy_unregister(void) | ||
745 | { | ||
746 | platform_driver_unregister(&dsa_driver); | ||
747 | } | ||