aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa/dsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa/dsa.c')
-rw-r--r--net/dsa/dsa.c233
1 files changed, 228 insertions, 5 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 2bc62ea857c8..0eb5d5e76dfb 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * net/dsa/dsa.c - Hardware switch handling 2 * net/dsa/dsa.c - Hardware switch handling
3 * Copyright (c) 2008-2009 Marvell Semiconductor 3 * Copyright (c) 2008-2009 Marvell Semiconductor
4 * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org>
4 * 5 *
5 * This program is free software; you can redistribute it and/or modify 6 * 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 * it under the terms of the GNU General Public License as published by
@@ -14,6 +15,9 @@
14#include <linux/slab.h> 15#include <linux/slab.h>
15#include <linux/module.h> 16#include <linux/module.h>
16#include <net/dsa.h> 17#include <net/dsa.h>
18#include <linux/of.h>
19#include <linux/of_mdio.h>
20#include <linux/of_platform.h>
17#include "dsa_priv.h" 21#include "dsa_priv.h"
18 22
19char dsa_driver_version[] = "0.1"; 23char dsa_driver_version[] = "0.1";
@@ -287,34 +291,239 @@ static struct net_device *dev_to_net_device(struct device *dev)
287 return NULL; 291 return NULL;
288} 292}
289 293
294#ifdef CONFIG_OF
295static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
296 struct dsa_chip_data *cd,
297 int chip_index,
298 struct device_node *link)
299{
300 int ret;
301 const __be32 *reg;
302 int link_port_addr;
303 int link_sw_addr;
304 struct device_node *parent_sw;
305 int len;
306
307 parent_sw = of_get_parent(link);
308 if (!parent_sw)
309 return -EINVAL;
310
311 reg = of_get_property(parent_sw, "reg", &len);
312 if (!reg || (len != sizeof(*reg) * 2))
313 return -EINVAL;
314
315 link_sw_addr = be32_to_cpup(reg + 1);
316
317 if (link_sw_addr >= pd->nr_chips)
318 return -EINVAL;
319
320 /* First time routing table allocation */
321 if (!cd->rtable) {
322 cd->rtable = kmalloc(pd->nr_chips * sizeof(s8), GFP_KERNEL);
323 if (!cd->rtable)
324 return -ENOMEM;
325
326 /* default to no valid uplink/downlink */
327 memset(cd->rtable, -1, pd->nr_chips * sizeof(s8));
328 }
329
330 reg = of_get_property(link, "reg", NULL);
331 if (!reg) {
332 ret = -EINVAL;
333 goto out;
334 }
335
336 link_port_addr = be32_to_cpup(reg);
337
338 cd->rtable[link_sw_addr] = link_port_addr;
339
340 return 0;
341out:
342 kfree(cd->rtable);
343 return ret;
344}
345
346static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
347{
348 int i;
349 int port_index;
350
351 for (i = 0; i < pd->nr_chips; i++) {
352 port_index = 0;
353 while (port_index < DSA_MAX_PORTS) {
354 if (pd->chip[i].port_names[port_index])
355 kfree(pd->chip[i].port_names[port_index]);
356 port_index++;
357 }
358 kfree(pd->chip[i].rtable);
359 }
360 kfree(pd->chip);
361}
362
363static int dsa_of_probe(struct platform_device *pdev)
364{
365 struct device_node *np = pdev->dev.of_node;
366 struct device_node *child, *mdio, *ethernet, *port, *link;
367 struct mii_bus *mdio_bus;
368 struct platform_device *ethernet_dev;
369 struct dsa_platform_data *pd;
370 struct dsa_chip_data *cd;
371 const char *port_name;
372 int chip_index, port_index;
373 const unsigned int *sw_addr, *port_reg;
374 int ret;
375
376 mdio = of_parse_phandle(np, "dsa,mii-bus", 0);
377 if (!mdio)
378 return -EINVAL;
379
380 mdio_bus = of_mdio_find_bus(mdio);
381 if (!mdio_bus)
382 return -EINVAL;
383
384 ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
385 if (!ethernet)
386 return -EINVAL;
387
388 ethernet_dev = of_find_device_by_node(ethernet);
389 if (!ethernet_dev)
390 return -ENODEV;
391
392 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
393 if (!pd)
394 return -ENOMEM;
395
396 pdev->dev.platform_data = pd;
397 pd->netdev = &ethernet_dev->dev;
398 pd->nr_chips = of_get_child_count(np);
399 if (pd->nr_chips > DSA_MAX_SWITCHES)
400 pd->nr_chips = DSA_MAX_SWITCHES;
401
402 pd->chip = kzalloc(pd->nr_chips * sizeof(struct dsa_chip_data),
403 GFP_KERNEL);
404 if (!pd->chip) {
405 ret = -ENOMEM;
406 goto out_free;
407 }
408
409 chip_index = 0;
410 for_each_available_child_of_node(np, child) {
411 cd = &pd->chip[chip_index];
412
413 cd->mii_bus = &mdio_bus->dev;
414
415 sw_addr = of_get_property(child, "reg", NULL);
416 if (!sw_addr)
417 continue;
418
419 cd->sw_addr = be32_to_cpup(sw_addr);
420 if (cd->sw_addr > PHY_MAX_ADDR)
421 continue;
422
423 for_each_available_child_of_node(child, port) {
424 port_reg = of_get_property(port, "reg", NULL);
425 if (!port_reg)
426 continue;
427
428 port_index = be32_to_cpup(port_reg);
429
430 port_name = of_get_property(port, "label", NULL);
431 if (!port_name)
432 continue;
433
434 cd->port_names[port_index] = kstrdup(port_name,
435 GFP_KERNEL);
436 if (!cd->port_names[port_index]) {
437 ret = -ENOMEM;
438 goto out_free_chip;
439 }
440
441 link = of_parse_phandle(port, "link", 0);
442
443 if (!strcmp(port_name, "dsa") && link &&
444 pd->nr_chips > 1) {
445 ret = dsa_of_setup_routing_table(pd, cd,
446 chip_index, link);
447 if (ret)
448 goto out_free_chip;
449 }
450
451 if (port_index == DSA_MAX_PORTS)
452 break;
453 }
454 }
455
456 return 0;
457
458out_free_chip:
459 dsa_of_free_platform_data(pd);
460out_free:
461 kfree(pd);
462 pdev->dev.platform_data = NULL;
463 return ret;
464}
465
466static void dsa_of_remove(struct platform_device *pdev)
467{
468 struct dsa_platform_data *pd = pdev->dev.platform_data;
469
470 if (!pdev->dev.of_node)
471 return;
472
473 dsa_of_free_platform_data(pd);
474 kfree(pd);
475}
476#else
477static inline int dsa_of_probe(struct platform_device *pdev)
478{
479 return 0;
480}
481
482static inline void dsa_of_remove(struct platform_device *pdev)
483{
484}
485#endif
486
290static int dsa_probe(struct platform_device *pdev) 487static int dsa_probe(struct platform_device *pdev)
291{ 488{
292 static int dsa_version_printed; 489 static int dsa_version_printed;
293 struct dsa_platform_data *pd = pdev->dev.platform_data; 490 struct dsa_platform_data *pd = pdev->dev.platform_data;
294 struct net_device *dev; 491 struct net_device *dev;
295 struct dsa_switch_tree *dst; 492 struct dsa_switch_tree *dst;
296 int i; 493 int i, ret;
297 494
298 if (!dsa_version_printed++) 495 if (!dsa_version_printed++)
299 printk(KERN_NOTICE "Distributed Switch Architecture " 496 printk(KERN_NOTICE "Distributed Switch Architecture "
300 "driver version %s\n", dsa_driver_version); 497 "driver version %s\n", dsa_driver_version);
301 498
499 if (pdev->dev.of_node) {
500 ret = dsa_of_probe(pdev);
501 if (ret)
502 return ret;
503
504 pd = pdev->dev.platform_data;
505 }
506
302 if (pd == NULL || pd->netdev == NULL) 507 if (pd == NULL || pd->netdev == NULL)
303 return -EINVAL; 508 return -EINVAL;
304 509
305 dev = dev_to_net_device(pd->netdev); 510 dev = dev_to_net_device(pd->netdev);
306 if (dev == NULL) 511 if (dev == NULL) {
307 return -EINVAL; 512 ret = -EINVAL;
513 goto out;
514 }
308 515
309 if (dev->dsa_ptr != NULL) { 516 if (dev->dsa_ptr != NULL) {
310 dev_put(dev); 517 dev_put(dev);
311 return -EEXIST; 518 ret = -EEXIST;
519 goto out;
312 } 520 }
313 521
314 dst = kzalloc(sizeof(*dst), GFP_KERNEL); 522 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
315 if (dst == NULL) { 523 if (dst == NULL) {
316 dev_put(dev); 524 dev_put(dev);
317 return -ENOMEM; 525 ret = -ENOMEM;
526 goto out;
318 } 527 }
319 528
320 platform_set_drvdata(pdev, dst); 529 platform_set_drvdata(pdev, dst);
@@ -366,6 +575,11 @@ static int dsa_probe(struct platform_device *pdev)
366 } 575 }
367 576
368 return 0; 577 return 0;
578
579out:
580 dsa_of_remove(pdev);
581
582 return ret;
369} 583}
370 584
371static int dsa_remove(struct platform_device *pdev) 585static int dsa_remove(struct platform_device *pdev)
@@ -385,6 +599,8 @@ static int dsa_remove(struct platform_device *pdev)
385 dsa_switch_destroy(ds); 599 dsa_switch_destroy(ds);
386 } 600 }
387 601
602 dsa_of_remove(pdev);
603
388 return 0; 604 return 0;
389} 605}
390 606
@@ -392,6 +608,12 @@ static void dsa_shutdown(struct platform_device *pdev)
392{ 608{
393} 609}
394 610
611static const struct of_device_id dsa_of_match_table[] = {
612 { .compatible = "marvell,dsa", },
613 {}
614};
615MODULE_DEVICE_TABLE(of, dsa_of_match_table);
616
395static struct platform_driver dsa_driver = { 617static struct platform_driver dsa_driver = {
396 .probe = dsa_probe, 618 .probe = dsa_probe,
397 .remove = dsa_remove, 619 .remove = dsa_remove,
@@ -399,6 +621,7 @@ static struct platform_driver dsa_driver = {
399 .driver = { 621 .driver = {
400 .name = "dsa", 622 .name = "dsa",
401 .owner = THIS_MODULE, 623 .owner = THIS_MODULE,
624 .of_match_table = dsa_of_match_table,
402 }, 625 },
403}; 626};
404 627