From 57d3231057e9e16930cef07b4281c6c902c42670 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:13:58 -0400 Subject: [PATCH 01/14] net: dsa: mv88e6xxx: fix style issues This patch fixes 5 style problems reported by checkpatch: WARNING: suspect code indent for conditional statements (8, 24) #492: FILE: drivers/net/dsa/mv88e6xxx.c:492: + if (phydev->link) + reg |= PORT_PCS_CTRL_LINK_UP; CHECK: Logical continuations should be on the previous line #1318: FILE: drivers/net/dsa/mv88e6xxx.c:1318: + oldstate == PORT_CONTROL_STATE_FORWARDING) + && (state == PORT_CONTROL_STATE_DISABLED || CHECK: multiple assignments should be avoided #1662: FILE: drivers/net/dsa/mv88e6xxx.c:1662: + vlan->vid_begin = vlan->vid_end = next.vid; WARNING: line over 80 characters #2097: FILE: drivers/net/dsa/mv88e6xxx.c:2097: + const struct switchdev_obj_port_vlan *vlan, WARNING: suspect code indent for conditional statements (16, 32) #2734: FILE: drivers/net/dsa/mv88e6xxx.c:2734: + if (mv88e6xxx_6352_family(ps) || mv88e6xxx_6351_family(ps) || [...] + reg |= PORT_CONTROL_EGRESS_ADD_TAG; total: 0 errors, 3 warnings, 2 checks, 3805 lines checked It also rebases and integrates changes sent by Ben Dooks [1]: The driver has a number of functions that are not exported or declared elsewhere, so make them static to avoid the following warnings from sparse: drivers/net/dsa/mv88e6xxx.c:113:5: warning: symbol 'mv88e6xxx_reg_read' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:167:5: warning: symbol 'mv88e6xxx_reg_write' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:231:5: warning: symbol 'mv88e6xxx_set_addr' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:367:6: warning: symbol 'mv88e6xxx_ppu_state_init' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:3157:5: warning: symbol 'mv88e6xxx_phy_page_read' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:3169:5: warning: symbol 'mv88e6xxx_phy_page_write' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:3583:26: warning: symbol 'mv88e6xxx_switch_driver' was not declared. Should it be static? drivers/net/dsa/mv88e6xxx.c:3621:5: warning: symbol 'mv88e6xxx_probe' was not declared. Should it be static? [1] http://patchwork.ozlabs.org/patch/632708/ Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index ee06055444f90..1972ec5f52732 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -111,7 +111,8 @@ static int _mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, return ret; } -int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr, int reg) +static int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr, + int reg) { int ret; @@ -165,8 +166,8 @@ static int _mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, return __mv88e6xxx_reg_write(ps->bus, ps->sw_addr, addr, reg, val); } -int mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, - int reg, u16 val) +static int mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, + int reg, u16 val) { int ret; @@ -229,7 +230,7 @@ static int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) return 0; } -int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr) +static int mv88e6xxx_set_addr(struct dsa_switch *ds, u8 *addr) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -370,7 +371,7 @@ static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_priv_state *ps) mutex_unlock(&ps->ppu_mutex); } -void mv88e6xxx_ppu_state_init(struct mv88e6xxx_priv_state *ps) +static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_priv_state *ps) { mutex_init(&ps->ppu_mutex); INIT_WORK(&ps->ppu_work, mv88e6xxx_ppu_reenable_work); @@ -490,7 +491,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, reg |= PORT_PCS_CTRL_FORCE_LINK; if (phydev->link) - reg |= PORT_PCS_CTRL_LINK_UP; + reg |= PORT_PCS_CTRL_LINK_UP; if (mv88e6xxx_6065_family(ps) && phydev->speed > SPEED_100) goto out; @@ -1314,9 +1315,9 @@ static int _mv88e6xxx_port_state(struct mv88e6xxx_priv_state *ps, int port, * Blocking or Listening state. */ if ((oldstate == PORT_CONTROL_STATE_LEARNING || - oldstate == PORT_CONTROL_STATE_FORWARDING) - && (state == PORT_CONTROL_STATE_DISABLED || - state == PORT_CONTROL_STATE_BLOCKING)) { + oldstate == PORT_CONTROL_STATE_FORWARDING) && + (state == PORT_CONTROL_STATE_DISABLED || + state == PORT_CONTROL_STATE_BLOCKING)) { ret = _mv88e6xxx_atu_remove(ps, 0, port, false); if (ret) return ret; @@ -1659,7 +1660,8 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, continue; /* reinit and dump this VLAN obj */ - vlan->vid_begin = vlan->vid_end = next.vid; + vlan->vid_begin = next.vid; + vlan->vid_end = next.vid; vlan->flags = 0; if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED) @@ -2093,9 +2095,10 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, return ret; } -static int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) +static int +mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int err; @@ -2735,7 +2738,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_priv_state *ps, int port) mv88e6xxx_6165_family(ps) || mv88e6xxx_6097_family(ps) || mv88e6xxx_6095_family(ps) || mv88e6xxx_6065_family(ps) || mv88e6xxx_6185_family(ps) || mv88e6xxx_6320_family(ps)) { - reg |= PORT_CONTROL_EGRESS_ADD_TAG; + reg |= PORT_CONTROL_EGRESS_ADD_TAG; } } if (dsa_is_dsa_port(ds, port)) { @@ -3158,7 +3161,8 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) return err; } -int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page, int reg) +static int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page, + int reg) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; @@ -3170,8 +3174,8 @@ int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page, int reg) return ret; } -int mv88e6xxx_mdio_page_write(struct dsa_switch *ds, int port, int page, - int reg, int val) +static int mv88e6xxx_mdio_page_write(struct dsa_switch *ds, int port, int page, + int reg, int val) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; @@ -3650,7 +3654,7 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, return name; } -struct dsa_switch_driver mv88e6xxx_switch_driver = { +static struct dsa_switch_driver mv88e6xxx_switch_driver = { .tag_protocol = DSA_TAG_PROTO_EDSA, .probe = mv88e6xxx_drv_probe, .setup = mv88e6xxx_setup, @@ -3686,7 +3690,7 @@ struct dsa_switch_driver mv88e6xxx_switch_driver = { .port_fdb_dump = mv88e6xxx_port_fdb_dump, }; -int mv88e6xxx_probe(struct mdio_device *mdiodev) +static int mv88e6xxx_probe(struct mdio_device *mdiodev) { struct device *dev = &mdiodev->dev; struct device_node *np = dev->of_node; From fbae5a4895b8694126388ee033b6dd0b33fadf2b Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:13:59 -0400 Subject: [PATCH 02/14] net: dsa: mv88e6xxx: remove redundant assignments The chip->ds and ds->slave_mii_bus assignments are common to both legacy and new MDIO probing and are already done in the later setup code. Remove the duplicated assignments from the MDIO probing code. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 1972ec5f52732..673283a89785a 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3708,7 +3708,6 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) 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); @@ -3748,8 +3747,6 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (err) return err; - ds->slave_mii_bus = ps->mdio_bus; - dev_set_drvdata(dev, ds); err = dsa_register_switch(ds, mdiodev->dev.of_node); From aa8ac3967e1f8d21b5f89d2a17b1281e1eb52522 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:00 -0400 Subject: [PATCH 03/14] net: dsa: mv88e6xxx: use already declared variables In the MDIO probing function, dev is already assigned to &mdiodev->dev and np is already assigned to mdiodev->dev.of_node, so use them. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 673283a89785a..b3170ea495926 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3728,7 +3728,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (!ps->info) return -ENODEV; - ps->reset = devm_gpiod_get(&mdiodev->dev, "reset", GPIOD_ASIS); + ps->reset = devm_gpiod_get(dev, "reset", GPIOD_ASIS); if (IS_ERR(ps->reset)) { err = PTR_ERR(ps->reset); if (err == -ENOENT) { @@ -3743,13 +3743,13 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) !of_property_read_u32(np, "eeprom-length", &eeprom_len)) ps->eeprom_len = eeprom_len; - err = mv88e6xxx_mdio_register(ps, mdiodev->dev.of_node); + err = mv88e6xxx_mdio_register(ps, np); if (err) return err; dev_set_drvdata(dev, ds); - err = dsa_register_switch(ds, mdiodev->dev.of_node); + err = dsa_register_switch(ds, np); if (err) { mv88e6xxx_mdio_unregister(ps); return err; From 1d35f0b2c3fcc8a0c1fd93aba02520c940c0b855 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:01 -0400 Subject: [PATCH 04/14] net: dsa: mv88e6xxx: do not increment bus refcount The MDIO device probe and remove functions are respectively incrementing and decrementing the bus refcount themselves. Since these bus level actions are out of the device scope, remove them. Signed-off-by: Vivien Didelot Acked-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index b3170ea495926..4b4bffc17d69c 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3712,8 +3712,6 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) 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); @@ -3767,7 +3765,6 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev) struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); dsa_unregister_switch(ds); - put_device(&ps->bus->dev); mv88e6xxx_mdio_unregister(ps); } From b7e66a5fad73cb0f118471e6ca8aeed3447915dc Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:02 -0400 Subject: [PATCH 05/14] net: dsa: mv88e6xxx: add switch register helpers The mixed assignments, allocations and registrations in the probe code make it hard to follow the logic and figure out what is DSA or chip specific. Extract the struct dsa_switch related code in a simple mv88e6xxx_register_switch helper function. For symmetry in the code, add a mv88e6xxx_unregister_switch function. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 41 +++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 4b4bffc17d69c..ad7735dcae844 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3690,30 +3690,48 @@ static struct dsa_switch_driver mv88e6xxx_switch_driver = { .port_fdb_dump = mv88e6xxx_port_fdb_dump, }; +static int mv88e6xxx_register_switch(struct mv88e6xxx_priv_state *ps, + struct device_node *np) +{ + struct device *dev = ps->dev; + struct dsa_switch *ds; + + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); + if (!ds) + return -ENOMEM; + + ds->dev = dev; + ds->priv = ps; + ds->drv = &mv88e6xxx_switch_driver; + + dev_set_drvdata(dev, ds); + + return dsa_register_switch(ds, np); +} + +static void mv88e6xxx_unregister_switch(struct mv88e6xxx_priv_state *ps) +{ + dsa_unregister_switch(ps->ds); +} + static 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) + ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL); + if (!ps) return -ENOMEM; - ps = (struct mv88e6xxx_priv_state *)(ds + 1); - ds->priv = ps; - ds->dev = dev; ps->dev = dev; ps->bus = mdiodev->bus; ps->sw_addr = mdiodev->addr; mutex_init(&ps->smi_mutex); - ds->drv = &mv88e6xxx_switch_driver; - id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); if (id < 0) return id; @@ -3745,9 +3763,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (err) return err; - dev_set_drvdata(dev, ds); - - err = dsa_register_switch(ds, np); + err = mv88e6xxx_register_switch(ps, np); if (err) { mv88e6xxx_mdio_unregister(ps); return err; @@ -3764,8 +3780,7 @@ 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); - dsa_unregister_switch(ds); - + mv88e6xxx_unregister_switch(ps); mv88e6xxx_mdio_unregister(ps); } From c6d19ab609d5a7f0eb9385d8dda6b2b5b3d9122f Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:03 -0400 Subject: [PATCH 06/14] net: dsa: mv88e6xxx: use gpio get optional variant Use the optional variant to get the reset GPIO line, instead of checking for the -ENOENT error. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index ad7735dcae844..ec28465ee323a 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3744,16 +3744,9 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (!ps->info) return -ENODEV; - ps->reset = devm_gpiod_get(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; - } - } + ps->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + if (IS_ERR(ps->reset)) + return PTR_ERR(ps->reset); if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM) && !of_property_read_u32(np, "eeprom-length", &eeprom_len)) From 5f7c036719536362f293c03c951f36a0509e7aec Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:04 -0400 Subject: [PATCH 07/14] net: dsa: mv88e6xxx: remove table args in info lookup The mv88e6xxx_table array and the mv88e6xxx_lookup_info function are static, so remove the table and size arguments from the lookup function. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index ec28465ee323a..75e540881077a 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3590,15 +3590,13 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { }, }; -static const struct mv88e6xxx_info * -mv88e6xxx_lookup_info(unsigned int prod_num, const struct mv88e6xxx_info *table, - unsigned int num) +static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) { int i; - for (i = 0; i < num; ++i) - if (table[i].prod_num == prod_num) - return &table[i]; + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i) + if (mv88e6xxx_table[i].prod_num == prod_num) + return &mv88e6xxx_table[i]; return NULL; } @@ -3625,8 +3623,7 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, prod_num = (id & 0xfff0) >> 4; rev = id & 0x000f; - info = mv88e6xxx_lookup_info(prod_num, mv88e6xxx_table, - ARRAY_SIZE(mv88e6xxx_table)); + info = mv88e6xxx_lookup_info(prod_num); if (!info) return NULL; @@ -3739,8 +3736,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) prod_num = (id & 0xfff0) >> 4; rev = id & 0x000f; - ps->info = mv88e6xxx_lookup_info(prod_num, mv88e6xxx_table, - ARRAY_SIZE(mv88e6xxx_table)); + ps->info = mv88e6xxx_lookup_info(prod_num); if (!ps->info) return -ENODEV; From 9f8b3ee1b5be49f5757fd60c22c921ad3ef58585 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:05 -0400 Subject: [PATCH 08/14] net: dsa: mv88e6xxx: rename smi_mutex to reg_lock The chip smi_mutex mutex is used to protect the access to the internal switch registers, not only the Multi-chip Addressing Mode, as commented. Since we will isolate SMI-specific pieces of code, avoid the confusion now by renaming smi_mutex to reg_lock. No functional changes here. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 120 ++++++++++++++++++------------------ drivers/net/dsa/mv88e6xxx.h | 7 +-- 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 75e540881077a..2c8617275d25f 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -29,10 +29,10 @@ #include #include "mv88e6xxx.h" -static void assert_smi_lock(struct mv88e6xxx_priv_state *ps) +static void assert_reg_lock(struct mv88e6xxx_priv_state *ps) { - if (unlikely(!mutex_is_locked(&ps->smi_mutex))) { - dev_err(ps->dev, "SMI lock not held!\n"); + if (unlikely(!mutex_is_locked(&ps->reg_lock))) { + dev_err(ps->dev, "Switch registers lock not held!\n"); dump_stack(); } } @@ -99,7 +99,7 @@ static int _mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, { int ret; - assert_smi_lock(ps); + assert_reg_lock(ps); ret = __mv88e6xxx_reg_read(ps->bus, ps->sw_addr, addr, reg); if (ret < 0) @@ -116,9 +116,9 @@ static int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr, { int ret; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_reg_read(ps, addr, reg); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -158,7 +158,7 @@ static int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, static int _mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, int reg, u16 val) { - assert_smi_lock(ps); + assert_reg_lock(ps); dev_dbg(ps->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", addr, reg, val); @@ -171,9 +171,9 @@ static int mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, { int ret; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_reg_write(ps, addr, reg, val); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -320,7 +320,7 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work); - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); if (mutex_trylock(&ps->ppu_mutex)) { if (mv88e6xxx_ppu_enable(ps) == 0) @@ -328,7 +328,7 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly) mutex_unlock(&ps->ppu_mutex); } - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps) @@ -477,7 +477,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, if (!phy_is_pseudo_fixed_link(phydev)) return; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_reg_read(ps, REG_PORT(port), PORT_PCS_CTRL); if (ret < 0) @@ -528,7 +528,7 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, _mv88e6xxx_reg_write(ps, REG_PORT(port), PORT_PCS_CTRL, reg); out: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static int _mv88e6xxx_stats_wait(struct mv88e6xxx_priv_state *ps) @@ -753,11 +753,11 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, int ret; int i, j; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_stats_snapshot(ps, port); if (ret < 0) { - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return; } for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { @@ -768,7 +768,7 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, } } - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) @@ -787,7 +787,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, memset(p, 0xff, 32 * sizeof(u16)); - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); for (i = 0; i < 32; i++) { int ret; @@ -797,7 +797,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, p[i] = ret; } - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static int _mv88e6xxx_wait(struct mv88e6xxx_priv_state *ps, int reg, int offset, @@ -824,9 +824,9 @@ static int mv88e6xxx_wait(struct mv88e6xxx_priv_state *ps, int reg, { int ret; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_wait(ps, reg, offset, mask); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -1123,7 +1123,7 @@ static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEE)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); reg = mv88e6xxx_mdio_read_indirect(ps, port, 16); if (reg < 0) @@ -1140,7 +1140,7 @@ static int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, reg = 0; out: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return reg; } @@ -1154,7 +1154,7 @@ static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEE)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = mv88e6xxx_mdio_read_indirect(ps, port, 16); if (ret < 0) @@ -1168,7 +1168,7 @@ static int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, ret = mv88e6xxx_mdio_write_indirect(ps, port, 16, reg); out: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -1402,9 +1402,9 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port, break; } - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); err = _mv88e6xxx_port_state(ps, port, stp_state); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); if (err) netdev_err(ds->ports[port].netdev, @@ -1638,7 +1638,7 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); err = _mv88e6xxx_port_pvid_get(ps, port, &pvid); if (err) @@ -1676,7 +1676,7 @@ static int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port, } while (next.vid < GLOBAL_VTU_VID_MASK); unlock: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return err; } @@ -2004,7 +2004,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, if (!vid_begin) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); err = _mv88e6xxx_vtu_vid_write(ps, vid_begin - 1); if (err) @@ -2043,7 +2043,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, } while (vlan.vid < vid_end); unlock: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return err; } @@ -2066,7 +2066,7 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_reg_read(ps, REG_PORT(port), PORT_CONTROL_2); if (ret < 0) @@ -2090,7 +2090,7 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port, ret = 0; unlock: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -2149,7 +2149,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU)) return; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) if (_mv88e6xxx_port_vlan_add(ps, port, vid, untagged)) @@ -2161,7 +2161,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, netdev_err(ds->ports[port].netdev, "failed to set PVID %d\n", vlan->vid_end); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_priv_state *ps, @@ -2210,7 +2210,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VTU)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); err = _mv88e6xxx_port_pvid_get(ps, port, &pvid); if (err) @@ -2229,7 +2229,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, } unlock: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return err; } @@ -2341,11 +2341,11 @@ static void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_ATU)) return; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); if (_mv88e6xxx_port_fdb_load(ps, port, fdb->addr, fdb->vid, state)) netdev_err(ds->ports[port].netdev, "failed to load MAC address\n"); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, @@ -2357,10 +2357,10 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_ATU)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_port_fdb_load(ps, port, fdb->addr, fdb->vid, GLOBAL_ATU_DATA_STATE_UNUSED); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -2465,7 +2465,7 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_ATU)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); /* Dump port's default Filtering Information Database (VLAN ID 0) */ err = _mv88e6xxx_port_fid_get(ps, port, &fid); @@ -2496,7 +2496,7 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, } while (vlan.vid < GLOBAL_VTU_VID_MASK); unlock: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return err; } @@ -2510,7 +2510,7 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VLANTABLE)) return -EOPNOTSUPP; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); /* Assign the bridge and remap each port's VLANTable */ ps->ports[port].bridge_dev = bridge; @@ -2523,7 +2523,7 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, } } - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return err; } @@ -2537,7 +2537,7 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port) if (!mv88e6xxx_has(ps, MV88E6XXX_FLAG_VLANTABLE)) return; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); /* Unassign the bridge and remap each port's VLANTable */ ps->ports[port].bridge_dev = NULL; @@ -2548,7 +2548,7 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port) netdev_warn(ds->ports[i].netdev, "failed to remap\n"); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); } static int _mv88e6xxx_mdio_page_write(struct mv88e6xxx_priv_state *ps, @@ -3139,7 +3139,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_EEPROM)) mutex_init(&ps->eeprom_mutex); - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); err = mv88e6xxx_switch_reset(ps); if (err) @@ -3156,7 +3156,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) } unlock: - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return err; } @@ -3167,9 +3167,9 @@ static int mv88e6xxx_mdio_page_read(struct dsa_switch *ds, int port, int page, struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_mdio_page_read(ps, port, page, reg); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -3180,9 +3180,9 @@ static int mv88e6xxx_mdio_page_write(struct dsa_switch *ds, int port, int page, struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = _mv88e6xxx_mdio_page_write(ps, port, page, reg, val); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -3204,7 +3204,7 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int port, int regnum) if (addr < 0) return 0xffff; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU)) ret = mv88e6xxx_mdio_read_ppu(ps, addr, regnum); @@ -3213,7 +3213,7 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int port, int regnum) else ret = mv88e6xxx_mdio_read_direct(ps, addr, regnum); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -3227,7 +3227,7 @@ static int mv88e6xxx_mdio_write(struct mii_bus *bus, int port, int regnum, if (addr < 0) return 0xffff; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_PPU)) ret = mv88e6xxx_mdio_write_ppu(ps, addr, regnum, val); @@ -3236,7 +3236,7 @@ static int mv88e6xxx_mdio_write(struct mii_bus *bus, int port, int regnum, else ret = mv88e6xxx_mdio_write_direct(ps, addr, regnum, val); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -3310,7 +3310,7 @@ static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp) *temp = 0; - mutex_lock(&ps->smi_mutex); + mutex_lock(&ps->reg_lock); ret = mv88e6xxx_mdio_write_direct(ps, 0x0, 0x16, 0x6); if (ret < 0) @@ -3343,7 +3343,7 @@ static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp) error: mv88e6xxx_mdio_write_direct(ps, 0x0, 0x16, 0x0); - mutex_unlock(&ps->smi_mutex); + mutex_unlock(&ps->reg_lock); return ret; } @@ -3637,7 +3637,7 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, ps->sw_addr = sw_addr; ps->info = info; ps->dev = dsa_dev; - mutex_init(&ps->smi_mutex); + mutex_init(&ps->reg_lock); err = mv88e6xxx_mdio_register(ps, NULL); if (err) @@ -3727,7 +3727,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) ps->dev = dev; ps->bus = mdiodev->bus; ps->sw_addr = mdiodev->addr; - mutex_init(&ps->smi_mutex); + mutex_init(&ps->reg_lock); id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); if (id < 0) diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 8221c3c7ec5ab..b279f8c3a803d 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -554,11 +554,8 @@ struct mv88e6xxx_priv_state { /* The device this structure is associated to */ struct device *dev; - /* When using multi-chip addressing, this mutex protects - * access to the indirect access registers. (In single-chip - * mode, this mutex is effectively useless.) - */ - struct mutex smi_mutex; + /* This mutex protects the access to the switch registers */ + struct mutex reg_lock; /* The MII bus and the address on the bus that is used to * communication with the switch From 469d729f2a701e78d12b936bf0df63b8acae73c9 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:06 -0400 Subject: [PATCH 09/14] net: dsa: mv88e6xxx: add chip allocation helper Add an helper function to allocate the chip structure at the beginning of the probe functions. It will be used to initialize the SMI access. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 39 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 2c8617275d25f..113092a64d6ba 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3601,6 +3601,21 @@ static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) return NULL; } +static struct mv88e6xxx_priv_state *mv88e6xxx_alloc_chip(struct device *dev) +{ + struct mv88e6xxx_priv_state *ps; + + ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL); + if (!ps) + return NULL; + + ps->dev = dev; + + mutex_init(&ps->reg_lock); + + return ps; +} + static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, struct device *host_dev, int sw_addr, void **priv) @@ -3616,32 +3631,30 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, if (!bus) return NULL; + ps = mv88e6xxx_alloc_chip(dsa_dev); + if (!ps) + return NULL; + id = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); if (id < 0) - return NULL; + goto free; prod_num = (id & 0xfff0) >> 4; rev = id & 0x000f; info = mv88e6xxx_lookup_info(prod_num); if (!info) - return NULL; + goto free; name = info->name; - ps = devm_kzalloc(dsa_dev, sizeof(*ps), GFP_KERNEL); - if (!ps) - return NULL; - ps->bus = bus; ps->sw_addr = sw_addr; ps->info = info; - ps->dev = dsa_dev; - mutex_init(&ps->reg_lock); err = mv88e6xxx_mdio_register(ps, NULL); if (err) - return NULL; + goto free; *priv = ps; @@ -3649,6 +3662,10 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, prod_num, name, rev); return name; +free: + devm_kfree(dsa_dev, ps); + + return NULL; } static struct dsa_switch_driver mv88e6xxx_switch_driver = { @@ -3720,14 +3737,12 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) u32 eeprom_len; int err; - ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL); + ps = mv88e6xxx_alloc_chip(dev); if (!ps) return -ENOMEM; - ps->dev = dev; ps->bus = mdiodev->bus; ps->sw_addr = mdiodev->addr; - mutex_init(&ps->reg_lock); id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); if (id < 0) From 4a70c4ab4fa49c07cbec519dfb9f9f90d2fec8d5 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:07 -0400 Subject: [PATCH 10/14] net: dsa: mv88e6xxx: add SMI init helper Add an helper function to isolate SMI specific assignments and checks. This function will later help choosing the different SMI accesses based of the compatible info. Since the chip structure is already allocated in the legacy probe, use the mv88e6xxx_reg_read access routine instead of __mv88e6xxx_reg_read. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 113092a64d6ba..4e24ac556ae2d 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3616,6 +3616,19 @@ static struct mv88e6xxx_priv_state *mv88e6xxx_alloc_chip(struct device *dev) return ps; } +static int mv88e6xxx_smi_init(struct mv88e6xxx_priv_state *ps, + struct mii_bus *bus, int sw_addr) +{ + /* ADDR[0] pin is unavailable externally and considered zero */ + if (sw_addr & 0x1) + return -EINVAL; + + ps->bus = bus; + ps->sw_addr = sw_addr; + + return 0; +} + static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, struct device *host_dev, int sw_addr, void **priv) @@ -3635,7 +3648,11 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, if (!ps) return NULL; - id = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); + err = mv88e6xxx_smi_init(ps, bus, sw_addr); + if (err) + goto free; + + id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); if (id < 0) goto free; @@ -3648,8 +3665,6 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, name = info->name; - ps->bus = bus; - ps->sw_addr = sw_addr; ps->info = info; err = mv88e6xxx_mdio_register(ps, NULL); @@ -3741,8 +3756,9 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (!ps) return -ENOMEM; - ps->bus = mdiodev->bus; - ps->sw_addr = mdiodev->addr; + err = mv88e6xxx_smi_init(ps, mdiodev->bus, mdiodev->addr); + if (err) + return err; id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); if (id < 0) From bc46a3d57cf7715d76eef8ea822c763cd271aacf Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:08 -0400 Subject: [PATCH 11/14] net: dsa: mv88e6xxx: add detection helper Extract the common detection code which assigns the info structure to the chip given the read switch ID. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 64 +++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 4e24ac556ae2d..de92add7f9a61 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3601,6 +3601,30 @@ static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) return NULL; } +static int mv88e6xxx_detect(struct mv88e6xxx_priv_state *ps) +{ + const struct mv88e6xxx_info *info; + int id, prod_num, rev; + + id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); + if (id < 0) + return id; + + prod_num = (id & 0xfff0) >> 4; + rev = id & 0x000f; + + info = mv88e6xxx_lookup_info(prod_num); + if (!info) + return -ENODEV; + + ps->info = info; + + dev_info(ps->dev, "switch 0x%x detected: %s, revision %u\n", + ps->info->prod_num, ps->info->name, rev); + + return 0; +} + static struct mv88e6xxx_priv_state *mv88e6xxx_alloc_chip(struct device *dev) { struct mv88e6xxx_priv_state *ps; @@ -3633,11 +3657,8 @@ 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; struct mii_bus *bus; - const char *name; - int id, prod_num, rev; int err; bus = dsa_host_dev_to_mii_bus(host_dev); @@ -3652,31 +3673,17 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, if (err) goto free; - id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); - if (id < 0) - goto free; - - prod_num = (id & 0xfff0) >> 4; - rev = id & 0x000f; - - info = mv88e6xxx_lookup_info(prod_num); - if (!info) + err = mv88e6xxx_detect(ps); + if (err) goto free; - name = info->name; - - ps->info = info; - err = mv88e6xxx_mdio_register(ps, NULL); if (err) goto free; *priv = ps; - dev_info(&ps->bus->dev, "switch 0x%x probed: %s, revision %u\n", - prod_num, name, rev); - - return name; + return ps->info->name; free: devm_kfree(dsa_dev, ps); @@ -3748,7 +3755,6 @@ static 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; u32 eeprom_len; int err; @@ -3760,16 +3766,9 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) if (err) return err; - 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); - if (!ps->info) - return -ENODEV; + err = mv88e6xxx_detect(ps); + if (err) + return err; ps->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); if (IS_ERR(ps->reset)) @@ -3789,9 +3788,6 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) return err; } - dev_info(dev, "switch 0x%x probed: %s, revision %u\n", - prod_num, ps->info->name, rev); - return 0; } From caac8545c861f2e78ae2565de31b573739b4034b Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:09 -0400 Subject: [PATCH 12/14] net: dsa: mv88e6xxx: pass compatible info After allocating the chip structure, pass it a compatible info pointer. The compatible info structure will be used later to describe how to access the switch registers and where to read the switch ID. For the standard MDIO probe, get it from the device node data. For the legacy DSA driver probing, pass it the 88E6085 info. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index de92add7f9a61..cadd1e3888363 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -3617,6 +3618,7 @@ static int mv88e6xxx_detect(struct mv88e6xxx_priv_state *ps) if (!info) return -ENODEV; + /* Update the compatible info with the probed one */ ps->info = info; dev_info(ps->dev, "switch 0x%x detected: %s, revision %u\n", @@ -3669,6 +3671,9 @@ static const char *mv88e6xxx_drv_probe(struct device *dsa_dev, if (!ps) return NULL; + /* Legacy SMI probing will only support chips similar to 88E6085 */ + ps->info = &mv88e6xxx_table[MV88E6085]; + err = mv88e6xxx_smi_init(ps, bus, sw_addr); if (err) goto free; @@ -3754,14 +3759,21 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev) { struct device *dev = &mdiodev->dev; struct device_node *np = dev->of_node; + const struct mv88e6xxx_info *compat_info; struct mv88e6xxx_priv_state *ps; u32 eeprom_len; int err; + compat_info = of_device_get_match_data(dev); + if (!compat_info) + return -EINVAL; + ps = mv88e6xxx_alloc_chip(dev); if (!ps) return -ENOMEM; + ps->info = compat_info; + err = mv88e6xxx_smi_init(ps, mdiodev->bus, mdiodev->addr); if (err) return err; @@ -3801,7 +3813,10 @@ static void mv88e6xxx_remove(struct mdio_device *mdiodev) } static const struct of_device_id mv88e6xxx_of_match[] = { - { .compatible = "marvell,mv88e6085" }, + { + .compatible = "marvell,mv88e6085", + .data = &mv88e6xxx_table[MV88E6085], + }, { /* sentinel */ }, }; From 9dddd478d4883deb1f5b6d3fcea681c9c9e90708 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:10 -0400 Subject: [PATCH 13/14] net: dsa: mv88e6xxx: add port base address to info The switch ID is located at address 0x3 of every Port Registers bank. But not all Marvell switches have their Port Registers SMI Addresses starting at 0x10. 88E6060 starts at 0x8 and 88E6390 starts at 0x0. Add this data in the info structure and use it in the detection code. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 19 ++++++++++++++++++- drivers/net/dsa/mv88e6xxx.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index cadd1e3888363..789f938a7f369 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -3443,6 +3443,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6085", .num_databases = 4096, .num_ports = 10, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6097, }, @@ -3452,6 +3453,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6095/88E6095F", .num_databases = 256, .num_ports = 11, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6095, }, @@ -3461,6 +3463,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6123", .num_databases = 4096, .num_ports = 3, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6165, }, @@ -3470,6 +3473,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6131", .num_databases = 256, .num_ports = 8, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6185, }, @@ -3479,6 +3483,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6161", .num_databases = 4096, .num_ports = 6, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6165, }, @@ -3488,6 +3493,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6165", .num_databases = 4096, .num_ports = 6, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6165, }, @@ -3497,6 +3503,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6171", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3506,6 +3513,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6172", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, @@ -3515,6 +3523,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6175", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3524,6 +3533,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6176", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, @@ -3533,6 +3543,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6185", .num_databases = 256, .num_ports = 10, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6185, }, @@ -3542,6 +3553,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6240", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, @@ -3551,6 +3563,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6320", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6320, }, @@ -3560,6 +3573,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6321", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6320, }, @@ -3569,6 +3583,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6350", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3578,6 +3593,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6351", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6351, }, @@ -3587,6 +3603,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6352", .num_databases = 4096, .num_ports = 7, + .port_base_addr = 0x10, .flags = MV88E6XXX_FLAGS_FAMILY_6352, }, }; @@ -3607,7 +3624,7 @@ static int mv88e6xxx_detect(struct mv88e6xxx_priv_state *ps) const struct mv88e6xxx_info *info; int id, prod_num, rev; - id = mv88e6xxx_reg_read(ps, REG_PORT(0), PORT_SWITCH_ID); + id = mv88e6xxx_reg_read(ps, ps->info->port_base_addr, PORT_SWITCH_ID); if (id < 0) return id; diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index b279f8c3a803d..8e6fe6b7fce30 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -519,6 +519,7 @@ struct mv88e6xxx_info { const char *name; unsigned int num_databases; unsigned int num_ports; + unsigned int port_base_addr; unsigned long flags; }; From 914b32f65afaaab005151335e183b4194d48162d Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 20 Jun 2016 13:14:11 -0400 Subject: [PATCH 14/14] net: dsa: mv88e6xxx: abstract switch registers accesses When the SMI address of the switch chip is zero, the chip assumes to be the only one on the SMI master bus and thus responds to all its known SMI devices addresses (port registers, Global2, etc.) When its SMI address is not zero, some chips (e.g. 88E6352) use an indirect access through two SMI Command and Data registers. Other models (e.g. 88E6060) using less than 16 internal SMI addresses always use a direct access. Add a capability flag to describe chips supporting the (indirect) Multi-chip Addressing Mode, and a low-level API to access the registers via SMI. Other accesses (like Ethernet management frames) may be added later. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 204 +++++++++++++++++++++++++----------- drivers/net/dsa/mv88e6xxx.h | 26 ++++- 2 files changed, 170 insertions(+), 60 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 789f938a7f369..9b116d8d4e23b 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -38,21 +38,74 @@ static void assert_reg_lock(struct mv88e6xxx_priv_state *ps) } } -/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will - * use all 32 SMI bus addresses on its SMI bus, and all switch registers - * will be directly accessible on some {device address,register address} - * pair. If the ADDR[4:0] pins are not strapped to zero, the switch - * will only respond to SMI transactions to that specific address, and - * an indirect addressing mechanism needs to be used to access its - * registers. +/* The switch ADDR[4:1] configuration pins define the chip SMI device address + * (ADDR[0] is always zero, thus only even SMI addresses can be strapped). + * + * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it + * is the only device connected to the SMI master. In this mode it responds to + * all 32 possible SMI addresses, and thus maps directly the internal devices. + * + * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing + * multiple devices to share the SMI interface. In this mode it responds to only + * 2 registers, used to indirectly access the internal SMI devices. */ -static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr) + +static int mv88e6xxx_smi_read(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 *val) +{ + if (!ps->smi_ops) + return -EOPNOTSUPP; + + return ps->smi_ops->read(ps, addr, reg, val); +} + +static int mv88e6xxx_smi_write(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 val) +{ + if (!ps->smi_ops) + return -EOPNOTSUPP; + + return ps->smi_ops->write(ps, addr, reg, val); +} + +static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 *val) +{ + int ret; + + ret = mdiobus_read_nested(ps->bus, addr, reg); + if (ret < 0) + return ret; + + *val = ret & 0xffff; + + return 0; +} + +static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 val) +{ + int ret; + + ret = mdiobus_write_nested(ps->bus, addr, reg, val); + if (ret < 0) + return ret; + + return 0; +} + +static const struct mv88e6xxx_ops mv88e6xxx_smi_single_chip_ops = { + .read = mv88e6xxx_smi_single_chip_read, + .write = mv88e6xxx_smi_single_chip_write, +}; + +static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_priv_state *ps) { int ret; int i; for (i = 0; i < 16; i++) { - ret = mdiobus_read_nested(bus, sw_addr, SMI_CMD); + ret = mdiobus_read_nested(ps->bus, ps->sw_addr, SMI_CMD); if (ret < 0) return ret; @@ -63,108 +116,134 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr) return -ETIMEDOUT; } -static int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, - int reg) +static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 *val) { int ret; - if (sw_addr == 0) - return mdiobus_read_nested(bus, addr, reg); - /* Wait for the bus to become free. */ - ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); + ret = mv88e6xxx_smi_multi_chip_wait(ps); if (ret < 0) return ret; /* Transmit the read command. */ - ret = mdiobus_write_nested(bus, sw_addr, SMI_CMD, + ret = mdiobus_write_nested(ps->bus, ps->sw_addr, SMI_CMD, SMI_CMD_OP_22_READ | (addr << 5) | reg); if (ret < 0) return ret; /* Wait for the read command to complete. */ - ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); + ret = mv88e6xxx_smi_multi_chip_wait(ps); if (ret < 0) return ret; /* Read the data. */ - ret = mdiobus_read_nested(bus, sw_addr, SMI_DATA); - if (ret < 0) - return ret; - - return ret & 0xffff; -} - -static int _mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, - int addr, int reg) -{ - int ret; - - assert_reg_lock(ps); - - ret = __mv88e6xxx_reg_read(ps->bus, ps->sw_addr, addr, reg); + ret = mdiobus_read_nested(ps->bus, ps->sw_addr, SMI_DATA); if (ret < 0) return ret; - dev_dbg(ps->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", - addr, reg, ret); - - return ret; -} + *val = ret & 0xffff; -static int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr, - int reg) -{ - int ret; - - mutex_lock(&ps->reg_lock); - ret = _mv88e6xxx_reg_read(ps, addr, reg); - mutex_unlock(&ps->reg_lock); - - return ret; + return 0; } -static int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, - int reg, u16 val) +static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 val) { int ret; - if (sw_addr == 0) - return mdiobus_write_nested(bus, addr, reg, val); - /* Wait for the bus to become free. */ - ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); + ret = mv88e6xxx_smi_multi_chip_wait(ps); if (ret < 0) return ret; /* Transmit the data to write. */ - ret = mdiobus_write_nested(bus, sw_addr, SMI_DATA, val); + ret = mdiobus_write_nested(ps->bus, ps->sw_addr, SMI_DATA, val); if (ret < 0) return ret; /* Transmit the write command. */ - ret = mdiobus_write_nested(bus, sw_addr, SMI_CMD, + ret = mdiobus_write_nested(ps->bus, ps->sw_addr, SMI_CMD, SMI_CMD_OP_22_WRITE | (addr << 5) | reg); if (ret < 0) return ret; /* Wait for the write command to complete. */ - ret = mv88e6xxx_reg_wait_ready(bus, sw_addr); + ret = mv88e6xxx_smi_multi_chip_wait(ps); if (ret < 0) return ret; return 0; } -static int _mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, - int reg, u16 val) +static const struct mv88e6xxx_ops mv88e6xxx_smi_multi_chip_ops = { + .read = mv88e6xxx_smi_multi_chip_read, + .write = mv88e6xxx_smi_multi_chip_write, +}; + +static int mv88e6xxx_read(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 *val) +{ + int err; + + assert_reg_lock(ps); + + err = mv88e6xxx_smi_read(ps, addr, reg, val); + if (err) + return err; + + dev_dbg(ps->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", + addr, reg, *val); + + return 0; +} + +static int mv88e6xxx_write(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 val) { + int err; + assert_reg_lock(ps); + err = mv88e6xxx_smi_write(ps, addr, reg, val); + if (err) + return err; + dev_dbg(ps->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n", addr, reg, val); - return __mv88e6xxx_reg_write(ps->bus, ps->sw_addr, addr, reg, val); + return 0; +} + +static int _mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, + int addr, int reg) +{ + u16 val; + int err; + + err = mv88e6xxx_read(ps, addr, reg, &val); + if (err) + return err; + + return val; +} + +static int mv88e6xxx_reg_read(struct mv88e6xxx_priv_state *ps, int addr, + int reg) +{ + int ret; + + mutex_lock(&ps->reg_lock); + ret = _mv88e6xxx_reg_read(ps, addr, reg); + mutex_unlock(&ps->reg_lock); + + return ret; +} + +static int _mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, + int reg, u16 val) +{ + return mv88e6xxx_write(ps, addr, reg, val); } static int mv88e6xxx_reg_write(struct mv88e6xxx_priv_state *ps, int addr, @@ -3666,6 +3745,13 @@ static int mv88e6xxx_smi_init(struct mv88e6xxx_priv_state *ps, if (sw_addr & 0x1) return -EINVAL; + if (sw_addr == 0) + ps->smi_ops = &mv88e6xxx_smi_single_chip_ops; + else if (mv88e6xxx_has(ps, MV88E6XXX_FLAG_MULTI_CHIP)) + ps->smi_ops = &mv88e6xxx_smi_multi_chip_ops; + else + return -EINVAL; + ps->bus = bus; ps->sw_addr = sw_addr; diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 8e6fe6b7fce30..a94acd887929c 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -387,6 +387,12 @@ enum mv88e6xxx_cap { */ MV88E6XXX_CAP_EEPROM, + /* Multi-chip Addressing Mode. + * Some chips require an indirect SMI access when their SMI device + * address is not zero. See SMI_CMD and SMI_DATA. + */ + MV88E6XXX_CAP_MULTI_CHIP, + /* Port State Filtering for 802.1D Spanning Tree. * See PORT_CONTROL_STATE_* values in the PORT_CONTROL register. */ @@ -439,6 +445,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAG_ATU BIT(MV88E6XXX_CAP_ATU) #define MV88E6XXX_FLAG_EEE BIT(MV88E6XXX_CAP_EEE) #define MV88E6XXX_FLAG_EEPROM BIT(MV88E6XXX_CAP_EEPROM) +#define MV88E6XXX_FLAG_MULTI_CHIP BIT(MV88E6XXX_CAP_MULTI_CHIP) #define MV88E6XXX_FLAG_PORTSTATE BIT(MV88E6XXX_CAP_PORTSTATE) #define MV88E6XXX_FLAG_PPU BIT(MV88E6XXX_CAP_PPU) #define MV88E6XXX_FLAG_PPU_ACTIVE BIT(MV88E6XXX_CAP_PPU_ACTIVE) @@ -452,25 +459,29 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6095 \ (MV88E6XXX_FLAG_ATU | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6097 \ (MV88E6XXX_FLAG_ATU | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6165 \ - (MV88E6XXX_FLAG_STU | \ + (MV88E6XXX_FLAG_MULTI_CHIP | \ + MV88E6XXX_FLAG_STU | \ MV88E6XXX_FLAG_SWITCH_MAC | \ MV88E6XXX_FLAG_TEMP | \ MV88E6XXX_FLAG_VTU) #define MV88E6XXX_FLAGS_FAMILY_6185 \ (MV88E6XXX_FLAG_ATU | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PPU | \ MV88E6XXX_FLAG_VLANTABLE | \ MV88E6XXX_FLAG_VTU) @@ -479,6 +490,7 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_ATU | \ MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PORTSTATE | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -490,6 +502,7 @@ enum mv88e6xxx_cap { #define MV88E6XXX_FLAGS_FAMILY_6351 \ (MV88E6XXX_FLAG_ATU | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PORTSTATE | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -503,6 +516,7 @@ enum mv88e6xxx_cap { (MV88E6XXX_FLAG_ATU | \ MV88E6XXX_FLAG_EEE | \ MV88E6XXX_FLAG_EEPROM | \ + MV88E6XXX_FLAG_MULTI_CHIP | \ MV88E6XXX_FLAG_PORTSTATE | \ MV88E6XXX_FLAG_PPU_ACTIVE | \ MV88E6XXX_FLAG_SMI_PHY | \ @@ -542,6 +556,8 @@ struct mv88e6xxx_vtu_stu_entry { u8 data[DSA_MAX_PORTS]; }; +struct mv88e6xxx_ops; + struct mv88e6xxx_priv_port { struct net_device *bridge_dev; }; @@ -561,6 +577,7 @@ struct mv88e6xxx_priv_state { /* The MII bus and the address on the bus that is used to * communication with the switch */ + const struct mv88e6xxx_ops *smi_ops; struct mii_bus *bus; int sw_addr; @@ -606,6 +623,13 @@ struct mv88e6xxx_priv_state { struct mii_bus *mdio_bus; }; +struct mv88e6xxx_ops { + int (*read)(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 *val); + int (*write)(struct mv88e6xxx_priv_state *ps, + int addr, int reg, u16 val); +}; + enum stat_type { BANK0, BANK1,