Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/dsa/dsa.c
15111 views
1
/*
2
* net/dsa/dsa.c - Hardware switch handling
3
* 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.
9
*/
10
11
#include <linux/list.h>
12
#include <linux/netdevice.h>
13
#include <linux/platform_device.h>
14
#include <linux/slab.h>
15
#include <net/dsa.h>
16
#include "dsa_priv.h"
17
18
char dsa_driver_version[] = "0.1";
19
20
21
/* switch driver registration ***********************************************/
22
static DEFINE_MUTEX(dsa_switch_drivers_mutex);
23
static LIST_HEAD(dsa_switch_drivers);
24
25
void register_switch_driver(struct dsa_switch_driver *drv)
26
{
27
mutex_lock(&dsa_switch_drivers_mutex);
28
list_add_tail(&drv->list, &dsa_switch_drivers);
29
mutex_unlock(&dsa_switch_drivers_mutex);
30
}
31
32
void unregister_switch_driver(struct dsa_switch_driver *drv)
33
{
34
mutex_lock(&dsa_switch_drivers_mutex);
35
list_del_init(&drv->list);
36
mutex_unlock(&dsa_switch_drivers_mutex);
37
}
38
39
static struct dsa_switch_driver *
40
dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
41
{
42
struct dsa_switch_driver *ret;
43
struct list_head *list;
44
char *name;
45
46
ret = NULL;
47
name = NULL;
48
49
mutex_lock(&dsa_switch_drivers_mutex);
50
list_for_each(list, &dsa_switch_drivers) {
51
struct dsa_switch_driver *drv;
52
53
drv = list_entry(list, struct dsa_switch_driver, list);
54
55
name = drv->probe(bus, sw_addr);
56
if (name != NULL) {
57
ret = drv;
58
break;
59
}
60
}
61
mutex_unlock(&dsa_switch_drivers_mutex);
62
63
*_name = name;
64
65
return ret;
66
}
67
68
69
/* basic switch operations **************************************************/
70
static struct dsa_switch *
71
dsa_switch_setup(struct dsa_switch_tree *dst, int index,
72
struct device *parent, struct mii_bus *bus)
73
{
74
struct dsa_chip_data *pd = dst->pd->chip + index;
75
struct dsa_switch_driver *drv;
76
struct dsa_switch *ds;
77
int ret;
78
char *name;
79
int i;
80
81
/*
82
* Probe for switch model.
83
*/
84
drv = dsa_switch_probe(bus, pd->sw_addr, &name);
85
if (drv == NULL) {
86
printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
87
dst->master_netdev->name, index);
88
return ERR_PTR(-EINVAL);
89
}
90
printk(KERN_INFO "%s[%d]: detected a %s switch\n",
91
dst->master_netdev->name, index, name);
92
93
94
/*
95
* Allocate and initialise switch state.
96
*/
97
ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL);
98
if (ds == NULL)
99
return ERR_PTR(-ENOMEM);
100
101
ds->dst = dst;
102
ds->index = index;
103
ds->pd = dst->pd->chip + index;
104
ds->drv = drv;
105
ds->master_mii_bus = bus;
106
107
108
/*
109
* Validate supplied switch configuration.
110
*/
111
for (i = 0; i < DSA_MAX_PORTS; i++) {
112
char *name;
113
114
name = pd->port_names[i];
115
if (name == NULL)
116
continue;
117
118
if (!strcmp(name, "cpu")) {
119
if (dst->cpu_switch != -1) {
120
printk(KERN_ERR "multiple cpu ports?!\n");
121
ret = -EINVAL;
122
goto out;
123
}
124
dst->cpu_switch = index;
125
dst->cpu_port = i;
126
} else if (!strcmp(name, "dsa")) {
127
ds->dsa_port_mask |= 1 << i;
128
} else {
129
ds->phys_port_mask |= 1 << i;
130
}
131
}
132
133
134
/*
135
* If the CPU connects to this switch, set the switch tree
136
* tagging protocol to the preferred tagging format of this
137
* switch.
138
*/
139
if (ds->dst->cpu_switch == index)
140
ds->dst->tag_protocol = drv->tag_protocol;
141
142
143
/*
144
* Do basic register setup.
145
*/
146
ret = drv->setup(ds);
147
if (ret < 0)
148
goto out;
149
150
ret = drv->set_addr(ds, dst->master_netdev->dev_addr);
151
if (ret < 0)
152
goto out;
153
154
ds->slave_mii_bus = mdiobus_alloc();
155
if (ds->slave_mii_bus == NULL) {
156
ret = -ENOMEM;
157
goto out;
158
}
159
dsa_slave_mii_bus_init(ds);
160
161
ret = mdiobus_register(ds->slave_mii_bus);
162
if (ret < 0)
163
goto out_free;
164
165
166
/*
167
* Create network devices for physical switch ports.
168
*/
169
for (i = 0; i < DSA_MAX_PORTS; i++) {
170
struct net_device *slave_dev;
171
172
if (!(ds->phys_port_mask & (1 << i)))
173
continue;
174
175
slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
176
if (slave_dev == NULL) {
177
printk(KERN_ERR "%s[%d]: can't create dsa "
178
"slave device for port %d(%s)\n",
179
dst->master_netdev->name,
180
index, i, pd->port_names[i]);
181
continue;
182
}
183
184
ds->ports[i] = slave_dev;
185
}
186
187
return ds;
188
189
out_free:
190
mdiobus_free(ds->slave_mii_bus);
191
out:
192
kfree(ds);
193
return ERR_PTR(ret);
194
}
195
196
static void dsa_switch_destroy(struct dsa_switch *ds)
197
{
198
}
199
200
201
/* hooks for ethertype-less tagging formats *********************************/
202
/*
203
* The original DSA tag format and some other tag formats have no
204
* ethertype, which means that we need to add a little hack to the
205
* networking receive path to make sure that received frames get
206
* the right ->protocol assigned to them when one of those tag
207
* formats is in use.
208
*/
209
bool dsa_uses_dsa_tags(void *dsa_ptr)
210
{
211
struct dsa_switch_tree *dst = dsa_ptr;
212
213
return !!(dst->tag_protocol == htons(ETH_P_DSA));
214
}
215
216
bool dsa_uses_trailer_tags(void *dsa_ptr)
217
{
218
struct dsa_switch_tree *dst = dsa_ptr;
219
220
return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
221
}
222
223
224
/* link polling *************************************************************/
225
static void dsa_link_poll_work(struct work_struct *ugly)
226
{
227
struct dsa_switch_tree *dst;
228
int i;
229
230
dst = container_of(ugly, struct dsa_switch_tree, link_poll_work);
231
232
for (i = 0; i < dst->pd->nr_chips; i++) {
233
struct dsa_switch *ds = dst->ds[i];
234
235
if (ds != NULL && ds->drv->poll_link != NULL)
236
ds->drv->poll_link(ds);
237
}
238
239
mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ));
240
}
241
242
static void dsa_link_poll_timer(unsigned long _dst)
243
{
244
struct dsa_switch_tree *dst = (void *)_dst;
245
246
schedule_work(&dst->link_poll_work);
247
}
248
249
250
/* platform driver init and cleanup *****************************************/
251
static int dev_is_class(struct device *dev, void *class)
252
{
253
if (dev->class != NULL && !strcmp(dev->class->name, class))
254
return 1;
255
256
return 0;
257
}
258
259
static struct device *dev_find_class(struct device *parent, char *class)
260
{
261
if (dev_is_class(parent, class)) {
262
get_device(parent);
263
return parent;
264
}
265
266
return device_find_child(parent, class, dev_is_class);
267
}
268
269
static struct mii_bus *dev_to_mii_bus(struct device *dev)
270
{
271
struct device *d;
272
273
d = dev_find_class(dev, "mdio_bus");
274
if (d != NULL) {
275
struct mii_bus *bus;
276
277
bus = to_mii_bus(d);
278
put_device(d);
279
280
return bus;
281
}
282
283
return NULL;
284
}
285
286
static struct net_device *dev_to_net_device(struct device *dev)
287
{
288
struct device *d;
289
290
d = dev_find_class(dev, "net");
291
if (d != NULL) {
292
struct net_device *nd;
293
294
nd = to_net_dev(d);
295
dev_hold(nd);
296
put_device(d);
297
298
return nd;
299
}
300
301
return NULL;
302
}
303
304
static int dsa_probe(struct platform_device *pdev)
305
{
306
static int dsa_version_printed;
307
struct dsa_platform_data *pd = pdev->dev.platform_data;
308
struct net_device *dev;
309
struct dsa_switch_tree *dst;
310
int i;
311
312
if (!dsa_version_printed++)
313
printk(KERN_NOTICE "Distributed Switch Architecture "
314
"driver version %s\n", dsa_driver_version);
315
316
if (pd == NULL || pd->netdev == NULL)
317
return -EINVAL;
318
319
dev = dev_to_net_device(pd->netdev);
320
if (dev == NULL)
321
return -EINVAL;
322
323
if (dev->dsa_ptr != NULL) {
324
dev_put(dev);
325
return -EEXIST;
326
}
327
328
dst = kzalloc(sizeof(*dst), GFP_KERNEL);
329
if (dst == NULL) {
330
dev_put(dev);
331
return -ENOMEM;
332
}
333
334
platform_set_drvdata(pdev, dst);
335
336
dst->pd = pd;
337
dst->master_netdev = dev;
338
dst->cpu_switch = -1;
339
dst->cpu_port = -1;
340
341
for (i = 0; i < pd->nr_chips; i++) {
342
struct mii_bus *bus;
343
struct dsa_switch *ds;
344
345
bus = dev_to_mii_bus(pd->chip[i].mii_bus);
346
if (bus == NULL) {
347
printk(KERN_ERR "%s[%d]: no mii bus found for "
348
"dsa switch\n", dev->name, i);
349
continue;
350
}
351
352
ds = dsa_switch_setup(dst, i, &pdev->dev, bus);
353
if (IS_ERR(ds)) {
354
printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
355
"instance (error %ld)\n", dev->name, i,
356
PTR_ERR(ds));
357
continue;
358
}
359
360
dst->ds[i] = ds;
361
if (ds->drv->poll_link != NULL)
362
dst->link_poll_needed = 1;
363
}
364
365
/*
366
* If we use a tagging format that doesn't have an ethertype
367
* field, make sure that all packets from this point on get
368
* sent to the tag format's receive function.
369
*/
370
wmb();
371
dev->dsa_ptr = (void *)dst;
372
373
if (dst->link_poll_needed) {
374
INIT_WORK(&dst->link_poll_work, dsa_link_poll_work);
375
init_timer(&dst->link_poll_timer);
376
dst->link_poll_timer.data = (unsigned long)dst;
377
dst->link_poll_timer.function = dsa_link_poll_timer;
378
dst->link_poll_timer.expires = round_jiffies(jiffies + HZ);
379
add_timer(&dst->link_poll_timer);
380
}
381
382
return 0;
383
}
384
385
static int dsa_remove(struct platform_device *pdev)
386
{
387
struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
388
int i;
389
390
if (dst->link_poll_needed)
391
del_timer_sync(&dst->link_poll_timer);
392
393
flush_work_sync(&dst->link_poll_work);
394
395
for (i = 0; i < dst->pd->nr_chips; i++) {
396
struct dsa_switch *ds = dst->ds[i];
397
398
if (ds != NULL)
399
dsa_switch_destroy(ds);
400
}
401
402
return 0;
403
}
404
405
static void dsa_shutdown(struct platform_device *pdev)
406
{
407
}
408
409
static struct platform_driver dsa_driver = {
410
.probe = dsa_probe,
411
.remove = dsa_remove,
412
.shutdown = dsa_shutdown,
413
.driver = {
414
.name = "dsa",
415
.owner = THIS_MODULE,
416
},
417
};
418
419
static int __init dsa_init_module(void)
420
{
421
return platform_driver_register(&dsa_driver);
422
}
423
module_init(dsa_init_module);
424
425
static void __exit dsa_cleanup_module(void)
426
{
427
platform_driver_unregister(&dsa_driver);
428
}
429
module_exit(dsa_cleanup_module);
430
431
MODULE_AUTHOR("Lennert Buytenhek <[email protected]>");
432
MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
433
MODULE_LICENSE("GPL");
434
MODULE_ALIAS("platform:dsa");
435
436