diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt index 5fdbbcdf8c4b..9f4807f90c31 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.txt +++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt @@ -31,8 +31,6 @@ A switch child node has the following optional property: switch. Must be set if the switch can not detect the presence and/or size of a connected EEPROM, otherwise optional. -- reset-gpios : phandle and specifier to a gpio line connected to - reset pin of the switch chip. A switch may have multiple "port" children nodes diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt new file mode 100644 index 000000000000..7629189398aa --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell.txt @@ -0,0 +1,35 @@ +Marvell DSA Switch Device Tree Bindings +--------------------------------------- + +WARNING: This binding is currently unstable. Do not program it into a +FLASH never to be changed again. Once this binding is stable, this +warning will be removed. + +If you need a stable binding, use the old dsa.txt binding. + +Marvell Switches are MDIO devices. The following properties should be +placed as a child node of an mdio device. + +The properties described here are those specific to Marvell devices. +Additional required and optional properties can be found in dsa.txt. + +Required properties: +- compatible : Should be one of "marvell,mv88e6085", +- reg : Address on the MII bus for the switch. + +Optional properties: + +- reset-gpios : Should be a gpio specifier for a reset line + +Example: + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch0: switch@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 448deb59b9a4..10ddd5a5dfb6 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -949,8 +949,8 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) /* All the interesting properties are at the parent device_node * level */ - dn = ds->pd->of_node->parent; - bcm_sf2_identify_ports(priv, ds->pd->of_node); + dn = ds->cd->of_node->parent; + bcm_sf2_identify_ports(priv, ds->cd->of_node); priv->irq0 = irq_of_parse_and_map(dn, 0); priv->irq1 = irq_of_parse_and_map(dn, 1); diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 835126e90afd..a3f0e7ec4067 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -5,6 +5,8 @@ * Copyright (c) 2015 CMC Electronics, Inc. * Added support for VLAN Table Unit operations * + * Copyright (c) 2016 Andrew Lunn + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -866,6 +869,16 @@ static int mv88e6xxx_read_eeprom_word(struct dsa_switch *ds, int addr) return ret; } +static int mv88e6xxx_get_eeprom_len(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM)) + return ps->eeprom_len; + + return 0; +} + static int mv88e6xxx_get_eeprom(struct dsa_switch *ds, struct ethtool_eeprom *eeprom, u8 *data) { @@ -2579,7 +2592,7 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_priv_state *ps) { bool ppu_active = mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU_ACTIVE); u16 is_reset = (ppu_active ? 0x8800 : 0xc800); - struct gpio_desc *gpiod = ps->ds->pd->reset; + struct gpio_desc *gpiod = ps->reset; unsigned long timeout; int ret; int i; @@ -3020,9 +3033,9 @@ static int mv88e6xxx_setup_global(struct mv88e6xxx_priv_state *ps) for (i = 0; i < 32; i++) { int nexthop = 0x1f; - if (ps->ds->pd->rtable && + if (ps->ds->cd->rtable && i != ps->ds->index && i < ps->ds->dst->pd->nr_chips) - nexthop = ps->ds->pd->rtable[i] & 0x1f; + nexthop = ps->ds->cd->rtable[i] & 0x1f; err = _mv88e6xxx_reg_write( ps, REG_GLOBAL2, @@ -3132,8 +3145,6 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) ps->ds = ds; - mutex_init(&ps->smi_mutex); - INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work); if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM)) @@ -3545,9 +3556,9 @@ mv88e6xxx_lookup_info(unsigned int prod_num, const struct mv88e6xxx_info *table, return NULL; } -static const char *mv88e6xxx_probe(struct device *dsa_dev, - struct device *host_dev, int sw_addr, - void **priv) +static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, + struct device *host_dev, int sw_addr, + void **priv) { const struct mv88e6xxx_info *info; struct mv88e6xxx_priv_state *ps; @@ -3580,6 +3591,7 @@ static const char *mv88e6xxx_probe(struct device *dsa_dev, ps->bus = bus; ps->sw_addr = sw_addr; ps->info = info; + mutex_init(&ps->smi_mutex); *priv = ps; @@ -3591,7 +3603,7 @@ static const char *mv88e6xxx_probe(struct device *dsa_dev, struct dsa_switch_driver mv88e6xxx_switch_driver = { .tag_protocol = DSA_TAG_PROTO_EDSA, - .probe = mv88e6xxx_probe, + .probe = mv88e6xxx_drv_probe, .setup = mv88e6xxx_setup, .set_addr = mv88e6xxx_set_addr, .phy_read = mv88e6xxx_phy_read, @@ -3608,6 +3620,7 @@ struct dsa_switch_driver mv88e6xxx_switch_driver = { .set_temp_limit = mv88e6xxx_set_temp_limit, .get_temp_alarm = mv88e6xxx_get_temp_alarm, #endif + .get_eeprom_len = mv88e6xxx_get_eeprom_len, .get_eeprom = mv88e6xxx_get_eeprom, .set_eeprom = mv88e6xxx_set_eeprom, .get_regs_len = mv88e6xxx_get_regs_len, @@ -3626,36 +3639,106 @@ struct dsa_switch_driver mv88e6xxx_switch_driver = { .port_fdb_dump = mv88e6xxx_port_fdb_dump, }; +int mv88e6xxx_probe(struct mdio_device *mdiodev) +{ + struct device *dev = &mdiodev->dev; + struct device_node *np = dev->of_node; + struct mv88e6xxx_priv_state *ps; + int id, prod_num, rev; + struct dsa_switch *ds; + u32 eeprom_len; + int err; + + ds = devm_kzalloc(dev, sizeof(*ds) + sizeof(*ps), GFP_KERNEL); + if (!ds) + return -ENOMEM; + + ps = (struct mv88e6xxx_priv_state *)(ds + 1); + ds->priv = ps; + ds->dev = dev; + ps->dev = dev; + ps->ds = ds; + ps->bus = mdiodev->bus; + ps->sw_addr = mdiodev->addr; + mutex_init(&ps->smi_mutex); + + get_device(&ps->bus->dev); + + ds->drv = &mv88e6xxx_switch_driver; + + id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); + if (id < 0) + return id; + + prod_num = (id & 0xfff0) >> 4; + rev = id & 0x000f; + + ps->info = mv88e6xxx_lookup_info(prod_num, mv88e6xxx_table, + ARRAY_SIZE(mv88e6xxx_table)); + if (!ps->info) + return -ENODEV; + + ps->reset = devm_gpiod_get(&mdiodev->dev, "reset", GPIOD_ASIS); + if (IS_ERR(ps->reset)) { + err = PTR_ERR(ps->reset); + if (err == -ENOENT) { + /* Optional, so not an error */ + ps->reset = NULL; + } else { + return err; + } + } + + if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM) && + !of_property_read_u32(np, "eeprom-length", &eeprom_len)) + ps->eeprom_len = eeprom_len; + + dev_set_drvdata(dev, ds); + + dev_info(dev, "switch 0x%x probed: %s, revision %u\n", + prod_num, ps->info->name, rev); + + return 0; +} + +static void mv88e6xxx_remove(struct mdio_device *mdiodev) +{ + struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev); + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + put_device(&ps->bus->dev); +} + +static const struct of_device_id mv88e6xxx_of_match[] = { + { .compatible = "marvell,mv88e6085" }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, mv88e6xxx_of_match); + +static struct mdio_driver mv88e6xxx_driver = { + .probe = mv88e6xxx_probe, + .remove = mv88e6xxx_remove, + .mdiodrv.driver = { + .name = "mv88e6085", + .of_match_table = mv88e6xxx_of_match, + }, +}; + static int __init mv88e6xxx_init(void) { register_switch_driver(&mv88e6xxx_switch_driver); - - return 0; + return mdio_driver_register(&mv88e6xxx_driver); } module_init(mv88e6xxx_init); static void __exit mv88e6xxx_cleanup(void) { + mdio_driver_unregister(&mv88e6xxx_driver); unregister_switch_driver(&mv88e6xxx_switch_driver); } module_exit(mv88e6xxx_cleanup); -MODULE_ALIAS("platform:mv88e6085"); -MODULE_ALIAS("platform:mv88e6095"); -MODULE_ALIAS("platform:mv88e6095f"); -MODULE_ALIAS("platform:mv88e6123"); -MODULE_ALIAS("platform:mv88e6131"); -MODULE_ALIAS("platform:mv88e6161"); -MODULE_ALIAS("platform:mv88e6165"); -MODULE_ALIAS("platform:mv88e6171"); -MODULE_ALIAS("platform:mv88e6172"); -MODULE_ALIAS("platform:mv88e6175"); -MODULE_ALIAS("platform:mv88e6176"); -MODULE_ALIAS("platform:mv88e6320"); -MODULE_ALIAS("platform:mv88e6321"); -MODULE_ALIAS("platform:mv88e6350"); -MODULE_ALIAS("platform:mv88e6351"); -MODULE_ALIAS("platform:mv88e6352"); MODULE_AUTHOR("Lennert Buytenhek "); MODULE_DESCRIPTION("Driver for Marvell 88E6XXX ethernet switch chips"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 5f09a4ea3cc5..40e8721ecfb1 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -12,6 +12,7 @@ #define __MV88E6XXX_H #include +#include #ifndef UINT64_MAX #define UINT64_MAX (u64)(~((u64)0)) @@ -595,6 +596,15 @@ struct mv88e6xxx_priv_state { DECLARE_BITMAP(port_state_update_mask, DSA_MAX_PORTS); struct work_struct bridge_work; + + /* A switch may have a GPIO line tied to its reset pin. Parse + * this from the device tree, and use it before performing + * switch soft reset. + */ + struct gpio_desc *reset; + + /* set to size of eeprom if supported by the switch */ + int eeprom_len; }; enum stat_type { diff --git a/include/net/dsa.h b/include/net/dsa.h index 8e86af87c84f..17c3d37b6779 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -65,13 +64,6 @@ struct dsa_chip_data { * NULL if there is only one switch chip. */ s8 *rtable; - - /* - * A switch may have a GPIO line tied to its reset pin. Parse - * this from the device tree, and use it before performing - * switch soft reset. - */ - struct gpio_desc *reset; }; struct dsa_platform_data { @@ -128,6 +120,8 @@ struct dsa_switch_tree { }; struct dsa_switch { + struct device *dev; + /* * Parent switch tree, and switch index. */ @@ -143,18 +137,13 @@ struct dsa_switch { /* * Configuration data for this switch. */ - struct dsa_chip_data *pd; + struct dsa_chip_data *cd; /* * The used switch driver. */ struct dsa_switch_driver *drv; - /* - * Reference to host device to use. - */ - struct device *master_dev; - #ifdef CONFIG_NET_DSA_HWMON /* * Hardware monitoring information @@ -201,7 +190,7 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds) if (dst->cpu_switch == ds->index) return dst->cpu_port; else - return ds->pd->rtable[dst->cpu_switch]; + return ds->cd->rtable[dst->cpu_switch]; } struct switchdev_trans; diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index d61ceed912be..eff5dfc2e33f 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -182,7 +182,7 @@ __ATTRIBUTE_GROUPS(dsa_hwmon); /* basic switch operations **************************************************/ static int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct net_device *master) { - struct dsa_chip_data *cd = ds->pd; + struct dsa_chip_data *cd = ds->cd; struct device_node *port_dn; struct phy_device *phydev; int ret, port, mode; @@ -219,7 +219,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { struct dsa_switch_driver *drv = ds->drv; struct dsa_switch_tree *dst = ds->dst; - struct dsa_chip_data *pd = ds->pd; + struct dsa_chip_data *cd = ds->cd; bool valid_name_found = false; int index = ds->index; int i, ret; @@ -230,7 +230,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) for (i = 0; i < DSA_MAX_PORTS; i++) { char *name; - name = pd->port_names[i]; + name = cd->port_names[i]; if (name == NULL) continue; @@ -328,10 +328,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) if (!(ds->enabled_port_mask & (1 << i))) continue; - ret = dsa_slave_create(ds, parent, i, pd->port_names[i]); + ret = dsa_slave_create(ds, parent, i, cd->port_names[i]); if (ret < 0) { netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s): %d\n", - index, i, pd->port_names[i], ret); + index, i, cd->port_names[i], ret); ret = 0; } } @@ -379,7 +379,7 @@ static struct dsa_switch * dsa_switch_setup(struct dsa_switch_tree *dst, int index, struct device *parent, struct device *host_dev) { - struct dsa_chip_data *pd = dst->pd->chip + index; + struct dsa_chip_data *cd = dst->pd->chip + index; struct dsa_switch_driver *drv; struct dsa_switch *ds; int ret; @@ -389,7 +389,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, /* * Probe for switch model. */ - drv = dsa_switch_probe(parent, host_dev, pd->sw_addr, &name, &priv); + drv = dsa_switch_probe(parent, host_dev, cd->sw_addr, &name, &priv); if (drv == NULL) { netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n", index); @@ -408,10 +408,10 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, ds->dst = dst; ds->index = index; - ds->pd = pd; + ds->cd = cd; ds->drv = drv; ds->priv = priv; - ds->master_dev = host_dev; + ds->dev = parent; ret = dsa_switch_setup_one(ds, parent); if (ret) @@ -424,7 +424,7 @@ static void dsa_switch_destroy(struct dsa_switch *ds) { struct device_node *port_dn; struct phy_device *phydev; - struct dsa_chip_data *cd = ds->pd; + struct dsa_chip_data *cd = ds->cd; int port; #ifdef CONFIG_NET_DSA_HWMON @@ -659,9 +659,6 @@ static int dsa_of_probe(struct device *dev) const char *port_name; int chip_index, port_index; const unsigned int *sw_addr, *port_reg; - int gpio; - enum of_gpio_flags of_flags; - unsigned long flags; u32 eeprom_len; int ret; @@ -740,19 +737,6 @@ static int dsa_of_probe(struct device *dev) put_device(cd->host_dev); cd->host_dev = &mdio_bus_switch->dev; } - gpio = of_get_named_gpio_flags(child, "reset-gpios", 0, - &of_flags); - if (gpio_is_valid(gpio)) { - flags = (of_flags == OF_GPIO_ACTIVE_LOW ? - GPIOF_ACTIVE_LOW : 0); - ret = devm_gpio_request_one(dev, gpio, flags, - "switch_reset"); - if (ret) - goto out_free_chip; - - cd->reset = gpio_to_desc(gpio); - gpiod_direction_output(cd->reset, 0); - } for_each_available_child_of_node(child, port) { port_reg = of_get_property(port, "reg", NULL); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 5ea8a40c8d33..152436cdab30 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -50,8 +50,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) ds->slave_mii_bus->read = dsa_slave_phy_read; ds->slave_mii_bus->write = dsa_slave_phy_write; snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d:%.2x", - ds->index, ds->pd->sw_addr); - ds->slave_mii_bus->parent = ds->master_dev; + ds->index, ds->cd->sw_addr); + ds->slave_mii_bus->parent = ds->dev; ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; } @@ -615,8 +615,8 @@ static int dsa_slave_get_eeprom_len(struct net_device *dev) struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->parent; - if (ds->pd->eeprom_len) - return ds->pd->eeprom_len; + if (ds->cd->eeprom_len) + return ds->cd->eeprom_len; if (ds->drv->get_eeprom_len) return ds->drv->get_eeprom_len(ds); @@ -999,7 +999,7 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p, struct net_device *slave_dev) { struct dsa_switch *ds = p->parent; - struct dsa_chip_data *cd = ds->pd; + struct dsa_chip_data *cd = ds->cd; struct device_node *phy_dn, *port_dn; bool phy_is_fixed = false; u32 phy_flags = 0; @@ -1147,7 +1147,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, NULL); SET_NETDEV_DEV(slave_dev, parent); - slave_dev->dev.of_node = ds->pd->port_dn[port]; + slave_dev->dev.of_node = ds->cd->port_dn[port]; slave_dev->vlan_features = master->vlan_features; p = netdev_priv(slave_dev);