aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/dsa.h6
-rw-r--r--net/dsa/dsa.c80
-rw-r--r--net/dsa/dsa_priv.h2
-rw-r--r--net/dsa/slave.c31
4 files changed, 119 insertions, 0 deletions
diff --git a/include/net/dsa.h b/include/net/dsa.h
index e020b8a12b7d..846dce4abaa5 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -210,6 +210,12 @@ struct dsa_switch_driver {
210 void (*get_ethtool_stats)(struct dsa_switch *ds, 210 void (*get_ethtool_stats)(struct dsa_switch *ds,
211 int port, uint64_t *data); 211 int port, uint64_t *data);
212 int (*get_sset_count)(struct dsa_switch *ds); 212 int (*get_sset_count)(struct dsa_switch *ds);
213
214 /*
215 * Suspend and resume
216 */
217 int (*suspend)(struct dsa_switch *ds);
218 int (*resume)(struct dsa_switch *ds);
213}; 219};
214 220
215void register_switch_driver(struct dsa_switch_driver *type); 221void register_switch_driver(struct dsa_switch_driver *type);
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)