diff options
Diffstat (limited to 'net/dsa/dsa.c')
| -rw-r--r-- | net/dsa/dsa.c | 171 |
1 files changed, 151 insertions, 20 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 6317b41c99b0..37317149f918 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
| @@ -9,6 +9,9 @@ | |||
| 9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/ctype.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/hwmon.h> | ||
| 12 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| 13 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 14 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| @@ -17,6 +20,7 @@ | |||
| 17 | #include <linux/of.h> | 20 | #include <linux/of.h> |
| 18 | #include <linux/of_mdio.h> | 21 | #include <linux/of_mdio.h> |
| 19 | #include <linux/of_platform.h> | 22 | #include <linux/of_platform.h> |
| 23 | #include <linux/sysfs.h> | ||
| 20 | #include "dsa_priv.h" | 24 | #include "dsa_priv.h" |
| 21 | 25 | ||
| 22 | char dsa_driver_version[] = "0.1"; | 26 | char dsa_driver_version[] = "0.1"; |
| @@ -71,6 +75,104 @@ dsa_switch_probe(struct device *host_dev, int sw_addr, char **_name) | |||
| 71 | return ret; | 75 | return ret; |
| 72 | } | 76 | } |
| 73 | 77 | ||
| 78 | /* hwmon support ************************************************************/ | ||
| 79 | |||
| 80 | #ifdef CONFIG_NET_DSA_HWMON | ||
| 81 | |||
| 82 | static ssize_t temp1_input_show(struct device *dev, | ||
| 83 | struct device_attribute *attr, char *buf) | ||
| 84 | { | ||
| 85 | struct dsa_switch *ds = dev_get_drvdata(dev); | ||
| 86 | int temp, ret; | ||
| 87 | |||
| 88 | ret = ds->drv->get_temp(ds, &temp); | ||
| 89 | if (ret < 0) | ||
| 90 | return ret; | ||
| 91 | |||
| 92 | return sprintf(buf, "%d\n", temp * 1000); | ||
| 93 | } | ||
| 94 | static DEVICE_ATTR_RO(temp1_input); | ||
| 95 | |||
| 96 | static ssize_t temp1_max_show(struct device *dev, | ||
| 97 | struct device_attribute *attr, char *buf) | ||
| 98 | { | ||
| 99 | struct dsa_switch *ds = dev_get_drvdata(dev); | ||
| 100 | int temp, ret; | ||
| 101 | |||
| 102 | ret = ds->drv->get_temp_limit(ds, &temp); | ||
| 103 | if (ret < 0) | ||
| 104 | return ret; | ||
| 105 | |||
| 106 | return sprintf(buf, "%d\n", temp * 1000); | ||
| 107 | } | ||
| 108 | |||
| 109 | static ssize_t temp1_max_store(struct device *dev, | ||
| 110 | struct device_attribute *attr, const char *buf, | ||
| 111 | size_t count) | ||
| 112 | { | ||
| 113 | struct dsa_switch *ds = dev_get_drvdata(dev); | ||
| 114 | int temp, ret; | ||
| 115 | |||
| 116 | ret = kstrtoint(buf, 0, &temp); | ||
| 117 | if (ret < 0) | ||
| 118 | return ret; | ||
| 119 | |||
| 120 | ret = ds->drv->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000)); | ||
| 121 | if (ret < 0) | ||
| 122 | return ret; | ||
| 123 | |||
| 124 | return count; | ||
| 125 | } | ||
| 126 | static DEVICE_ATTR(temp1_max, S_IRUGO, temp1_max_show, temp1_max_store); | ||
| 127 | |||
| 128 | static ssize_t temp1_max_alarm_show(struct device *dev, | ||
| 129 | struct device_attribute *attr, char *buf) | ||
| 130 | { | ||
| 131 | struct dsa_switch *ds = dev_get_drvdata(dev); | ||
| 132 | bool alarm; | ||
| 133 | int ret; | ||
| 134 | |||
| 135 | ret = ds->drv->get_temp_alarm(ds, &alarm); | ||
| 136 | if (ret < 0) | ||
| 137 | return ret; | ||
| 138 | |||
| 139 | return sprintf(buf, "%d\n", alarm); | ||
| 140 | } | ||
| 141 | static DEVICE_ATTR_RO(temp1_max_alarm); | ||
| 142 | |||
| 143 | static struct attribute *dsa_hwmon_attrs[] = { | ||
| 144 | &dev_attr_temp1_input.attr, /* 0 */ | ||
| 145 | &dev_attr_temp1_max.attr, /* 1 */ | ||
| 146 | &dev_attr_temp1_max_alarm.attr, /* 2 */ | ||
| 147 | NULL | ||
| 148 | }; | ||
| 149 | |||
| 150 | static umode_t dsa_hwmon_attrs_visible(struct kobject *kobj, | ||
| 151 | struct attribute *attr, int index) | ||
| 152 | { | ||
| 153 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 154 | struct dsa_switch *ds = dev_get_drvdata(dev); | ||
| 155 | struct dsa_switch_driver *drv = ds->drv; | ||
| 156 | umode_t mode = attr->mode; | ||
| 157 | |||
| 158 | if (index == 1) { | ||
| 159 | if (!drv->get_temp_limit) | ||
| 160 | mode = 0; | ||
| 161 | else if (drv->set_temp_limit) | ||
| 162 | mode |= S_IWUSR; | ||
| 163 | } else if (index == 2 && !drv->get_temp_alarm) { | ||
| 164 | mode = 0; | ||
| 165 | } | ||
| 166 | return mode; | ||
| 167 | } | ||
| 168 | |||
| 169 | static const struct attribute_group dsa_hwmon_group = { | ||
| 170 | .attrs = dsa_hwmon_attrs, | ||
| 171 | .is_visible = dsa_hwmon_attrs_visible, | ||
| 172 | }; | ||
| 173 | __ATTRIBUTE_GROUPS(dsa_hwmon); | ||
| 174 | |||
| 175 | #endif /* CONFIG_NET_DSA_HWMON */ | ||
| 74 | 176 | ||
| 75 | /* basic switch operations **************************************************/ | 177 | /* basic switch operations **************************************************/ |
| 76 | static struct dsa_switch * | 178 | static struct dsa_switch * |
| @@ -90,12 +192,12 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, | |||
| 90 | */ | 192 | */ |
| 91 | drv = dsa_switch_probe(host_dev, pd->sw_addr, &name); | 193 | drv = dsa_switch_probe(host_dev, pd->sw_addr, &name); |
| 92 | if (drv == NULL) { | 194 | if (drv == NULL) { |
| 93 | printk(KERN_ERR "%s[%d]: could not detect attached switch\n", | 195 | netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n", |
| 94 | dst->master_netdev->name, index); | 196 | index); |
| 95 | return ERR_PTR(-EINVAL); | 197 | return ERR_PTR(-EINVAL); |
| 96 | } | 198 | } |
| 97 | printk(KERN_INFO "%s[%d]: detected a %s switch\n", | 199 | netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n", |
| 98 | dst->master_netdev->name, index, name); | 200 | index, name); |
| 99 | 201 | ||
| 100 | 202 | ||
| 101 | /* | 203 | /* |
| @@ -123,7 +225,8 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, | |||
| 123 | 225 | ||
| 124 | if (!strcmp(name, "cpu")) { | 226 | if (!strcmp(name, "cpu")) { |
| 125 | if (dst->cpu_switch != -1) { | 227 | if (dst->cpu_switch != -1) { |
| 126 | printk(KERN_ERR "multiple cpu ports?!\n"); | 228 | netdev_err(dst->master_netdev, |
| 229 | "multiple cpu ports?!\n"); | ||
| 127 | ret = -EINVAL; | 230 | ret = -EINVAL; |
| 128 | goto out; | 231 | goto out; |
| 129 | } | 232 | } |
| @@ -218,16 +321,39 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, | |||
| 218 | 321 | ||
| 219 | slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); | 322 | slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]); |
| 220 | if (slave_dev == NULL) { | 323 | if (slave_dev == NULL) { |
| 221 | printk(KERN_ERR "%s[%d]: can't create dsa " | 324 | netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n", |
| 222 | "slave device for port %d(%s)\n", | 325 | index, i, pd->port_names[i]); |
| 223 | dst->master_netdev->name, | ||
| 224 | index, i, pd->port_names[i]); | ||
| 225 | continue; | 326 | continue; |
| 226 | } | 327 | } |
| 227 | 328 | ||
| 228 | ds->ports[i] = slave_dev; | 329 | ds->ports[i] = slave_dev; |
| 229 | } | 330 | } |
| 230 | 331 | ||
| 332 | #ifdef CONFIG_NET_DSA_HWMON | ||
| 333 | /* If the switch provides a temperature sensor, | ||
| 334 | * register with hardware monitoring subsystem. | ||
| 335 | * Treat registration error as non-fatal and ignore it. | ||
| 336 | */ | ||
| 337 | if (drv->get_temp) { | ||
| 338 | const char *netname = netdev_name(dst->master_netdev); | ||
| 339 | char hname[IFNAMSIZ + 1]; | ||
| 340 | int i, j; | ||
| 341 | |||
| 342 | /* Create valid hwmon 'name' attribute */ | ||
| 343 | for (i = j = 0; i < IFNAMSIZ && netname[i]; i++) { | ||
| 344 | if (isalnum(netname[i])) | ||
| 345 | hname[j++] = netname[i]; | ||
| 346 | } | ||
| 347 | hname[j] = '\0'; | ||
| 348 | scnprintf(ds->hwmon_name, sizeof(ds->hwmon_name), "%s_dsa%d", | ||
| 349 | hname, index); | ||
| 350 | ds->hwmon_dev = hwmon_device_register_with_groups(NULL, | ||
| 351 | ds->hwmon_name, ds, dsa_hwmon_groups); | ||
| 352 | if (IS_ERR(ds->hwmon_dev)) | ||
| 353 | ds->hwmon_dev = NULL; | ||
| 354 | } | ||
| 355 | #endif /* CONFIG_NET_DSA_HWMON */ | ||
| 356 | |||
| 231 | return ds; | 357 | return ds; |
| 232 | 358 | ||
| 233 | out_free: | 359 | out_free: |
| @@ -239,6 +365,10 @@ out: | |||
| 239 | 365 | ||
| 240 | static void dsa_switch_destroy(struct dsa_switch *ds) | 366 | static void dsa_switch_destroy(struct dsa_switch *ds) |
| 241 | { | 367 | { |
| 368 | #ifdef CONFIG_NET_DSA_HWMON | ||
| 369 | if (ds->hwmon_dev) | ||
| 370 | hwmon_device_unregister(ds->hwmon_dev); | ||
| 371 | #endif | ||
| 242 | } | 372 | } |
| 243 | 373 | ||
| 244 | #ifdef CONFIG_PM_SLEEP | 374 | #ifdef CONFIG_PM_SLEEP |
| @@ -396,7 +526,8 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, | |||
| 396 | 526 | ||
| 397 | /* First time routing table allocation */ | 527 | /* First time routing table allocation */ |
| 398 | if (!cd->rtable) { | 528 | if (!cd->rtable) { |
| 399 | cd->rtable = kmalloc(pd->nr_chips * sizeof(s8), GFP_KERNEL); | 529 | cd->rtable = kmalloc_array(pd->nr_chips, sizeof(s8), |
| 530 | GFP_KERNEL); | ||
| 400 | if (!cd->rtable) | 531 | if (!cd->rtable) |
| 401 | return -ENOMEM; | 532 | return -ENOMEM; |
| 402 | 533 | ||
| @@ -447,6 +578,7 @@ static int dsa_of_probe(struct platform_device *pdev) | |||
| 447 | const char *port_name; | 578 | const char *port_name; |
| 448 | int chip_index, port_index; | 579 | int chip_index, port_index; |
| 449 | const unsigned int *sw_addr, *port_reg; | 580 | const unsigned int *sw_addr, *port_reg; |
| 581 | u32 eeprom_len; | ||
| 450 | int ret; | 582 | int ret; |
| 451 | 583 | ||
| 452 | mdio = of_parse_phandle(np, "dsa,mii-bus", 0); | 584 | mdio = of_parse_phandle(np, "dsa,mii-bus", 0); |
| @@ -475,8 +607,8 @@ static int dsa_of_probe(struct platform_device *pdev) | |||
| 475 | if (pd->nr_chips > DSA_MAX_SWITCHES) | 607 | if (pd->nr_chips > DSA_MAX_SWITCHES) |
| 476 | pd->nr_chips = DSA_MAX_SWITCHES; | 608 | pd->nr_chips = DSA_MAX_SWITCHES; |
| 477 | 609 | ||
| 478 | pd->chip = kzalloc(pd->nr_chips * sizeof(struct dsa_chip_data), | 610 | pd->chip = kcalloc(pd->nr_chips, sizeof(struct dsa_chip_data), |
| 479 | GFP_KERNEL); | 611 | GFP_KERNEL); |
| 480 | if (!pd->chip) { | 612 | if (!pd->chip) { |
| 481 | ret = -ENOMEM; | 613 | ret = -ENOMEM; |
| 482 | goto out_free; | 614 | goto out_free; |
| @@ -498,6 +630,9 @@ static int dsa_of_probe(struct platform_device *pdev) | |||
| 498 | if (cd->sw_addr > PHY_MAX_ADDR) | 630 | if (cd->sw_addr > PHY_MAX_ADDR) |
| 499 | continue; | 631 | continue; |
| 500 | 632 | ||
| 633 | if (!of_property_read_u32(np, "eeprom-length", &eeprom_len)) | ||
| 634 | cd->eeprom_len = eeprom_len; | ||
| 635 | |||
| 501 | for_each_available_child_of_node(child, port) { | 636 | for_each_available_child_of_node(child, port) { |
| 502 | port_reg = of_get_property(port, "reg", NULL); | 637 | port_reg = of_get_property(port, "reg", NULL); |
| 503 | if (!port_reg) | 638 | if (!port_reg) |
| @@ -566,15 +701,13 @@ static inline void dsa_of_remove(struct platform_device *pdev) | |||
| 566 | 701 | ||
| 567 | static int dsa_probe(struct platform_device *pdev) | 702 | static int dsa_probe(struct platform_device *pdev) |
| 568 | { | 703 | { |
| 569 | static int dsa_version_printed; | ||
| 570 | struct dsa_platform_data *pd = pdev->dev.platform_data; | 704 | struct dsa_platform_data *pd = pdev->dev.platform_data; |
| 571 | struct net_device *dev; | 705 | struct net_device *dev; |
| 572 | struct dsa_switch_tree *dst; | 706 | struct dsa_switch_tree *dst; |
| 573 | int i, ret; | 707 | int i, ret; |
| 574 | 708 | ||
| 575 | if (!dsa_version_printed++) | 709 | pr_notice_once("Distributed Switch Architecture driver version %s\n", |
| 576 | printk(KERN_NOTICE "Distributed Switch Architecture " | 710 | dsa_driver_version); |
| 577 | "driver version %s\n", dsa_driver_version); | ||
| 578 | 711 | ||
| 579 | if (pdev->dev.of_node) { | 712 | if (pdev->dev.of_node) { |
| 580 | ret = dsa_of_probe(pdev); | 713 | ret = dsa_of_probe(pdev); |
| @@ -618,9 +751,8 @@ static int dsa_probe(struct platform_device *pdev) | |||
| 618 | 751 | ||
| 619 | ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev); | 752 | ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev); |
| 620 | if (IS_ERR(ds)) { | 753 | if (IS_ERR(ds)) { |
| 621 | printk(KERN_ERR "%s[%d]: couldn't create dsa switch " | 754 | netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n", |
| 622 | "instance (error %ld)\n", dev->name, i, | 755 | i, PTR_ERR(ds)); |
| 623 | PTR_ERR(ds)); | ||
| 624 | continue; | 756 | continue; |
| 625 | } | 757 | } |
| 626 | 758 | ||
| @@ -747,7 +879,6 @@ static struct platform_driver dsa_driver = { | |||
| 747 | .shutdown = dsa_shutdown, | 879 | .shutdown = dsa_shutdown, |
| 748 | .driver = { | 880 | .driver = { |
| 749 | .name = "dsa", | 881 | .name = "dsa", |
| 750 | .owner = THIS_MODULE, | ||
| 751 | .of_match_table = dsa_of_match_table, | 882 | .of_match_table = dsa_of_match_table, |
| 752 | .pm = &dsa_pm_ops, | 883 | .pm = &dsa_pm_ops, |
| 753 | }, | 884 | }, |
