Bring S2RAM support to the mv88e6xxx DSA driver. The content of the *_irq_poll() helper is moved in *_do_irq_poll() so that that the function can be called from the ->resume() callback without using the *work pointer.
Signed-off-by: Miquel Raynal <miquel.ray...@bootlin.com> --- Changes since v1: ================= * Added the logic to replay rules. * Did not add any port_disable/enable() calls as this will be taken care of by Vivien's patches. drivers/net/dsa/mv88e6xxx/chip.c | 89 ++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 428177f80abd..e83c02aaca49 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -547,15 +547,21 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip) return err; } +static void mv88e6xxx_do_irq_poll(struct mv88e6xxx_chip *chip) +{ + mv88e6xxx_g1_irq_thread_work(chip); + + kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, + msecs_to_jiffies(100)); +} + static void mv88e6xxx_irq_poll(struct kthread_work *work) { struct mv88e6xxx_chip *chip = container_of(work, struct mv88e6xxx_chip, irq_poll_work.work); - mv88e6xxx_g1_irq_thread_work(chip); - kthread_queue_delayed_work(chip->kworker, &chip->irq_poll_work, - msecs_to_jiffies(100)); + mv88e6xxx_do_irq_poll(chip); } static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip) @@ -4855,6 +4861,82 @@ static const void *pdata_device_get_match_data(struct device *dev) return NULL; } +static int __maybe_unused mv88e6xxx_suspend(struct device *dev) +{ + struct dsa_switch *ds = dev_get_drvdata(dev); + struct mv88e6xxx_chip *chip = ds->priv; + + kthread_cancel_delayed_work_sync(&chip->irq_poll_work); + + return dsa_switch_suspend(ds); +} + +static int __maybe_unused mv88e6xxx_resume(struct device *dev) +{ + struct dsa_switch *ds = dev_get_drvdata(dev); + struct mv88e6xxx_chip *chip = ds->priv; + struct mv88e6xxx_rule *rule; + int ret; + + mv88e6xxx_phy_init(chip); + + mutex_lock(&chip->reg_lock); + ret = mv88e6xxx_switch_reset(chip); + mutex_unlock(&chip->reg_lock); + if (ret) { + dev_err(dev, "Failed to reset the switch\n"); + return ret; + } + + ret = mv88e6xxx_setup(ds); + if (ret) { + dev_err(dev, "Failed to setup the switch\n"); + return ret; + } + + mv88e6xxx_do_irq_poll(chip); + + list_for_each_entry(rule, &chip->rules, node) { + switch (rule->type) { + case FDB_RULE: + ret = _mv88e6xxx_port_fdb_add(chip, rule->port, + rule->params.db.addr, + rule->params.db.vid); + break; + case MDB_RULE: + ret = _mv88e6xxx_port_mdb_add(chip, rule->port, + rule->params.db.addr, + rule->params.db.vid); + break; + case VLAN_RULE: + ret = _mv88e6xxx_port_vlan_add(chip, rule->port, + &rule->params.vlan); + break; + case BRIDGE_RULE: + ret = _mv88e6xxx_port_bridge_join(chip, rule->port, + rule->params.br); + break; + case CC_BRIDGE_RULE: + ret = _mv88e6xxx_crosschip_bridge_join(chip, + rule->params.crosschip.dev, + rule->port, + rule->params.crosschip.br); + break; + default: + dev_warn(chip->dev, "Unknown rule type (%d)\n", + rule->type); + continue; + } + + if (ret) + dev_warn(chip->dev, "Cannot re-apply rule\n"); + } + + return dsa_switch_resume(ds); +} + +static SIMPLE_DEV_PM_OPS(mv88e6xxx_pm_ops, mv88e6xxx_suspend, mv88e6xxx_resume); + static int mv88e6xxx_probe(struct mdio_device *mdiodev) { struct dsa_mv88e6xxx_pdata *pdata = mdiodev->dev.platform_data; @@ -5041,6 +5123,7 @@ static struct mdio_driver mv88e6xxx_driver = { .mdiodrv.driver = { .name = "mv88e6085", .of_match_table = mv88e6xxx_of_match, + .pm = &mv88e6xxx_pm_ops, }, }; -- 2.19.1