aboutsummaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2014-09-18 20:31:22 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-22 14:41:23 -0400
commit2446254915a7d6f08bba9a755a34cc0402880472 (patch)
tree2b27382c1139a4a9e2b012fa7a9b9604e51bb031 /net/dsa
parent34f6b8745d421683ca0a268540869eb30721e970 (diff)
net: dsa: allow switch drivers to implement suspend/resume hooks
Add an abstraction layer to suspend/resume switch devices, doing the following split: - suspend/resume the slave network devices and their corresponding PHY devices - suspend/resume the switch hardware using switch driver callbacks Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/dsa.c80
-rw-r--r--net/dsa/dsa_priv.h2
-rw-r--r--net/dsa/slave.c31
3 files changed, 113 insertions, 0 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 6e40928ec0e7..6905f2d84c44 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -238,6 +238,49 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
238{ 238{
239} 239}
240 240
241static int dsa_switch_suspend(struct dsa_switch *ds)
242{
243 int i, ret = 0;
244
245 /* Suspend slave network devices */
246 for (i = 0; i < DSA_MAX_PORTS; i++) {
247 if (!(ds->phys_port_mask & (1 << i)))
248 continue;
249
250 ret = dsa_slave_suspend(ds->ports[i]);
251 if (ret)
252 return ret;
253 }
254
255 if (ds->drv->suspend)
256 ret = ds->drv->suspend(ds);
257
258 return ret;
259}
260
261static int dsa_switch_resume(struct dsa_switch *ds)
262{
263 int i, ret = 0;
264
265 if (ds->drv->resume)
266 ret = ds->drv->resume(ds);
267
268 if (ret)
269 return ret;
270
271 /* Resume slave network devices */
272 for (i = 0; i < DSA_MAX_PORTS; i++) {
273 if (!(ds->phys_port_mask & (1 << i)))
274 continue;
275
276 ret = dsa_slave_resume(ds->ports[i]);
277 if (ret)
278 return ret;
279 }
280
281 return 0;
282}
283
241 284
242/* link polling *************************************************************/ 285/* link polling *************************************************************/
243static void dsa_link_poll_work(struct work_struct *ugly) 286static void dsa_link_poll_work(struct work_struct *ugly)
@@ -650,6 +693,42 @@ static struct packet_type dsa_pack_type __read_mostly = {
650 .func = dsa_switch_rcv, 693 .func = dsa_switch_rcv,
651}; 694};
652 695
696#ifdef CONFIG_PM_SLEEP
697static int dsa_suspend(struct device *d)
698{
699 struct platform_device *pdev = to_platform_device(d);
700 struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
701 int i, ret = 0;
702
703 for (i = 0; i < dst->pd->nr_chips; i++) {
704 struct dsa_switch *ds = dst->ds[i];
705
706 if (ds != NULL)
707 ret = dsa_switch_suspend(ds);
708 }
709
710 return ret;
711}
712
713static int dsa_resume(struct device *d)
714{
715 struct platform_device *pdev = to_platform_device(d);
716 struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
717 int i, ret = 0;
718
719 for (i = 0; i < dst->pd->nr_chips; i++) {
720 struct dsa_switch *ds = dst->ds[i];
721
722 if (ds != NULL)
723 ret = dsa_switch_resume(ds);
724 }
725
726 return ret;
727}
728#endif
729
730static SIMPLE_DEV_PM_OPS(dsa_pm_ops, dsa_suspend, dsa_resume);
731
653static const struct of_device_id dsa_of_match_table[] = { 732static const struct of_device_id dsa_of_match_table[] = {
654 { .compatible = "brcm,bcm7445-switch-v4.0" }, 733 { .compatible = "brcm,bcm7445-switch-v4.0" },
655 { .compatible = "marvell,dsa", }, 734 { .compatible = "marvell,dsa", },
@@ -665,6 +744,7 @@ static struct platform_driver dsa_driver = {
665 .name = "dsa", 744 .name = "dsa",
666 .owner = THIS_MODULE, 745 .owner = THIS_MODULE,
667 .of_match_table = dsa_of_match_table, 746 .of_match_table = dsa_of_match_table,
747 .pm = &dsa_pm_ops,
668 }, 748 },
669}; 749};
670 750
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index f90899e8ab5a..dc9756d3154c 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -56,6 +56,8 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds);
56struct net_device *dsa_slave_create(struct dsa_switch *ds, 56struct net_device *dsa_slave_create(struct dsa_switch *ds,
57 struct device *parent, 57 struct device *parent,
58 int port, char *name); 58 int port, char *name);
59int dsa_slave_suspend(struct net_device *slave_dev);
60int dsa_slave_resume(struct net_device *slave_dev);
59 61
60/* tag_dsa.c */ 62/* tag_dsa.c */
61extern const struct dsa_device_ops dsa_netdev_ops; 63extern const struct dsa_device_ops dsa_netdev_ops;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index a7997265019a..143811ef57ae 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -412,6 +412,37 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
412 p->phy->addr, p->phy->drv->name); 412 p->phy->addr, p->phy->drv->name);
413} 413}
414 414
415int dsa_slave_suspend(struct net_device *slave_dev)
416{
417 struct dsa_slave_priv *p = netdev_priv(slave_dev);
418
419 netif_device_detach(slave_dev);
420
421 if (p->phy) {
422 phy_stop(p->phy);
423 p->old_pause = -1;
424 p->old_link = -1;
425 p->old_duplex = -1;
426 phy_suspend(p->phy);
427 }
428
429 return 0;
430}
431
432int dsa_slave_resume(struct net_device *slave_dev)
433{
434 struct dsa_slave_priv *p = netdev_priv(slave_dev);
435
436 netif_device_attach(slave_dev);
437
438 if (p->phy) {
439 phy_resume(p->phy);
440 phy_start(p->phy);
441 }
442
443 return 0;
444}
445
415struct net_device * 446struct net_device *
416dsa_slave_create(struct dsa_switch *ds, struct device *parent, 447dsa_slave_create(struct dsa_switch *ds, struct device *parent,
417 int port, char *name) 448 int port, char *name)