diff options
author | David S. Miller <davem@davemloft.net> | 2018-06-05 08:50:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-06-05 08:50:18 -0400 |
commit | 7a723099be325f6c5edd25c775b672a056907f75 (patch) | |
tree | 9a3188f34ac7db2ee7c749a80fc6beb40060950c | |
parent | 7d840a606515b04dfb4f13d1abb86dd59163799c (diff) | |
parent | 9107c05e2e55c1c7abd02ab38f7694e0da08b643 (diff) |
Merge branch 'net-phy-improve-PM-handling-of-PHY-MDIO'
Heiner Kallweit says:
====================
net: phy: improve PM handling of PHY/MDIO
Current implementation of MDIO bus PM ops doesn't actually implement
bus-specific PM ops but just calls PM ops defined on a device level
what doesn't seem to be fully in line with the core PM model.
When looking e.g. at __device_suspend() the PM core looks for PM ops
of a device in a specific order:
1. device PM domain
2. device type
3. device class
4. device bus
I think it has good reason that there's no PM ops on device level.
The situation can be improved by modeling PHY's as device type of
a MDIO device. If for some other type of MDIO device PM ops are
needed, it could be modeled as struct device_type as well.
====================
Tested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 48 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 96 | ||||
-rw-r--r-- | include/linux/mdio.h | 1 |
3 files changed, 50 insertions, 95 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 24b5511222c8..98f4b1f706df 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -717,58 +717,10 @@ static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
717 | return 0; | 717 | return 0; |
718 | } | 718 | } |
719 | 719 | ||
720 | #ifdef CONFIG_PM | ||
721 | static int mdio_bus_suspend(struct device *dev) | ||
722 | { | ||
723 | struct mdio_device *mdio = to_mdio_device(dev); | ||
724 | |||
725 | if (mdio->pm_ops && mdio->pm_ops->suspend) | ||
726 | return mdio->pm_ops->suspend(dev); | ||
727 | |||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | static int mdio_bus_resume(struct device *dev) | ||
732 | { | ||
733 | struct mdio_device *mdio = to_mdio_device(dev); | ||
734 | |||
735 | if (mdio->pm_ops && mdio->pm_ops->resume) | ||
736 | return mdio->pm_ops->resume(dev); | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | static int mdio_bus_restore(struct device *dev) | ||
742 | { | ||
743 | struct mdio_device *mdio = to_mdio_device(dev); | ||
744 | |||
745 | if (mdio->pm_ops && mdio->pm_ops->restore) | ||
746 | return mdio->pm_ops->restore(dev); | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static const struct dev_pm_ops mdio_bus_pm_ops = { | ||
752 | .suspend = mdio_bus_suspend, | ||
753 | .resume = mdio_bus_resume, | ||
754 | .freeze = mdio_bus_suspend, | ||
755 | .thaw = mdio_bus_resume, | ||
756 | .restore = mdio_bus_restore, | ||
757 | }; | ||
758 | |||
759 | #define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops) | ||
760 | |||
761 | #else | ||
762 | |||
763 | #define MDIO_BUS_PM_OPS NULL | ||
764 | |||
765 | #endif /* CONFIG_PM */ | ||
766 | |||
767 | struct bus_type mdio_bus_type = { | 720 | struct bus_type mdio_bus_type = { |
768 | .name = "mdio_bus", | 721 | .name = "mdio_bus", |
769 | .match = mdio_bus_match, | 722 | .match = mdio_bus_match, |
770 | .uevent = mdio_uevent, | 723 | .uevent = mdio_uevent, |
771 | .pm = MDIO_BUS_PM_OPS, | ||
772 | }; | 724 | }; |
773 | EXPORT_SYMBOL(mdio_bus_type); | 725 | EXPORT_SYMBOL(mdio_bus_type); |
774 | 726 | ||
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9e4ba8e80a18..bd0f339f69fd 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -346,6 +346,55 @@ static int phy_bus_match(struct device *dev, struct device_driver *drv) | |||
346 | } | 346 | } |
347 | } | 347 | } |
348 | 348 | ||
349 | static ssize_t | ||
350 | phy_id_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
351 | { | ||
352 | struct phy_device *phydev = to_phy_device(dev); | ||
353 | |||
354 | return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id); | ||
355 | } | ||
356 | static DEVICE_ATTR_RO(phy_id); | ||
357 | |||
358 | static ssize_t | ||
359 | phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
360 | { | ||
361 | struct phy_device *phydev = to_phy_device(dev); | ||
362 | const char *mode = NULL; | ||
363 | |||
364 | if (phy_is_internal(phydev)) | ||
365 | mode = "internal"; | ||
366 | else | ||
367 | mode = phy_modes(phydev->interface); | ||
368 | |||
369 | return sprintf(buf, "%s\n", mode); | ||
370 | } | ||
371 | static DEVICE_ATTR_RO(phy_interface); | ||
372 | |||
373 | static ssize_t | ||
374 | phy_has_fixups_show(struct device *dev, struct device_attribute *attr, | ||
375 | char *buf) | ||
376 | { | ||
377 | struct phy_device *phydev = to_phy_device(dev); | ||
378 | |||
379 | return sprintf(buf, "%d\n", phydev->has_fixups); | ||
380 | } | ||
381 | static DEVICE_ATTR_RO(phy_has_fixups); | ||
382 | |||
383 | static struct attribute *phy_dev_attrs[] = { | ||
384 | &dev_attr_phy_id.attr, | ||
385 | &dev_attr_phy_interface.attr, | ||
386 | &dev_attr_phy_has_fixups.attr, | ||
387 | NULL, | ||
388 | }; | ||
389 | ATTRIBUTE_GROUPS(phy_dev); | ||
390 | |||
391 | static const struct device_type mdio_bus_phy_type = { | ||
392 | .name = "PHY", | ||
393 | .groups = phy_dev_groups, | ||
394 | .release = phy_device_release, | ||
395 | .pm = MDIO_BUS_PHY_PM_OPS, | ||
396 | }; | ||
397 | |||
349 | struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, | 398 | struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, |
350 | bool is_c45, | 399 | bool is_c45, |
351 | struct phy_c45_device_ids *c45_ids) | 400 | struct phy_c45_device_ids *c45_ids) |
@@ -359,11 +408,10 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, | |||
359 | return ERR_PTR(-ENOMEM); | 408 | return ERR_PTR(-ENOMEM); |
360 | 409 | ||
361 | mdiodev = &dev->mdio; | 410 | mdiodev = &dev->mdio; |
362 | mdiodev->dev.release = phy_device_release; | ||
363 | mdiodev->dev.parent = &bus->dev; | 411 | mdiodev->dev.parent = &bus->dev; |
364 | mdiodev->dev.bus = &mdio_bus_type; | 412 | mdiodev->dev.bus = &mdio_bus_type; |
413 | mdiodev->dev.type = &mdio_bus_phy_type; | ||
365 | mdiodev->bus = bus; | 414 | mdiodev->bus = bus; |
366 | mdiodev->pm_ops = MDIO_BUS_PHY_PM_OPS; | ||
367 | mdiodev->bus_match = phy_bus_match; | 415 | mdiodev->bus_match = phy_bus_match; |
368 | mdiodev->addr = addr; | 416 | mdiodev->addr = addr; |
369 | mdiodev->flags = MDIO_DEVICE_FLAG_PHY; | 417 | mdiodev->flags = MDIO_DEVICE_FLAG_PHY; |
@@ -587,48 +635,6 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) | |||
587 | } | 635 | } |
588 | EXPORT_SYMBOL(get_phy_device); | 636 | EXPORT_SYMBOL(get_phy_device); |
589 | 637 | ||
590 | static ssize_t | ||
591 | phy_id_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
592 | { | ||
593 | struct phy_device *phydev = to_phy_device(dev); | ||
594 | |||
595 | return sprintf(buf, "0x%.8lx\n", (unsigned long)phydev->phy_id); | ||
596 | } | ||
597 | static DEVICE_ATTR_RO(phy_id); | ||
598 | |||
599 | static ssize_t | ||
600 | phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
601 | { | ||
602 | struct phy_device *phydev = to_phy_device(dev); | ||
603 | const char *mode = NULL; | ||
604 | |||
605 | if (phy_is_internal(phydev)) | ||
606 | mode = "internal"; | ||
607 | else | ||
608 | mode = phy_modes(phydev->interface); | ||
609 | |||
610 | return sprintf(buf, "%s\n", mode); | ||
611 | } | ||
612 | static DEVICE_ATTR_RO(phy_interface); | ||
613 | |||
614 | static ssize_t | ||
615 | phy_has_fixups_show(struct device *dev, struct device_attribute *attr, | ||
616 | char *buf) | ||
617 | { | ||
618 | struct phy_device *phydev = to_phy_device(dev); | ||
619 | |||
620 | return sprintf(buf, "%d\n", phydev->has_fixups); | ||
621 | } | ||
622 | static DEVICE_ATTR_RO(phy_has_fixups); | ||
623 | |||
624 | static struct attribute *phy_dev_attrs[] = { | ||
625 | &dev_attr_phy_id.attr, | ||
626 | &dev_attr_phy_interface.attr, | ||
627 | &dev_attr_phy_has_fixups.attr, | ||
628 | NULL, | ||
629 | }; | ||
630 | ATTRIBUTE_GROUPS(phy_dev); | ||
631 | |||
632 | /** | 638 | /** |
633 | * phy_device_register - Register the phy device on the MDIO bus | 639 | * phy_device_register - Register the phy device on the MDIO bus |
634 | * @phydev: phy_device structure to be added to the MDIO bus | 640 | * @phydev: phy_device structure to be added to the MDIO bus |
@@ -651,8 +657,6 @@ int phy_device_register(struct phy_device *phydev) | |||
651 | goto out; | 657 | goto out; |
652 | } | 658 | } |
653 | 659 | ||
654 | phydev->mdio.dev.groups = phy_dev_groups; | ||
655 | |||
656 | err = device_add(&phydev->mdio.dev); | 660 | err = device_add(&phydev->mdio.dev); |
657 | if (err) { | 661 | if (err) { |
658 | pr_err("PHY %d failed to add\n", phydev->mdio.addr); | 662 | pr_err("PHY %d failed to add\n", phydev->mdio.addr); |
diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 2cfffe586885..bfa7114167d7 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h | |||
@@ -29,7 +29,6 @@ enum mdio_mutex_lock_class { | |||
29 | struct mdio_device { | 29 | struct mdio_device { |
30 | struct device dev; | 30 | struct device dev; |
31 | 31 | ||
32 | const struct dev_pm_ops *pm_ops; | ||
33 | struct mii_bus *bus; | 32 | struct mii_bus *bus; |
34 | char modalias[MDIO_NAME_SIZE]; | 33 | char modalias[MDIO_NAME_SIZE]; |
35 | 34 | ||