diff options
author | Alexander Graf <agraf@suse.de> | 2014-10-13 10:01:09 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2014-11-02 20:12:51 -0500 |
commit | 9178ba294b6839eeff1a91bed95515d783f3ee6c (patch) | |
tree | 61252a8808bba5208c7b7c0f0af31301278272de /arch/powerpc/platforms/pseries | |
parent | 0df1f2487d2f0d04703f142813d53615d62a1da4 (diff) |
powerpc: Convert power off logic to pm_power_off
The generic Linux framework to power off the machine is a function pointer
called pm_power_off. The trick about this pointer is that device drivers can
potentially implement it rather than board files.
Today on powerpc we set pm_power_off to invoke our generic full machine power
off logic which then calls ppc_md.power_off to invoke machine specific power
off.
However, when we want to add a power off GPIO via the "gpio-poweroff" driver,
this card house falls apart. That driver only registers itself if pm_power_off
is NULL to ensure it doesn't override board specific logic. However, since we
always set pm_power_off to the generic power off logic (which will just not
power off the machine if no ppc_md.power_off call is implemented), we can't
implement power off via the generic GPIO power off driver.
To fix this up, let's get rid of the ppc_md.power_off logic and just always use
pm_power_off as was intended. Then individual drivers such as the GPIO power off
driver can implement power off logic via that function pointer.
With this patch set applied and a few patches on top of QEMU that implement a
power off GPIO on the virt e500 machine, I can successfully turn off my virtual
machine after halt.
Signed-off-by: Alexander Graf <agraf@suse.de>
[mpe: Squash into one patch and update changelog based on cover letter]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 59 |
1 files changed, 30 insertions, 29 deletions
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 125c589eeef5..db0fc0c07568 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -659,6 +659,34 @@ static void __init pSeries_init_early(void) | |||
659 | pr_debug(" <- pSeries_init_early()\n"); | 659 | pr_debug(" <- pSeries_init_early()\n"); |
660 | } | 660 | } |
661 | 661 | ||
662 | /** | ||
663 | * pseries_power_off - tell firmware about how to power off the system. | ||
664 | * | ||
665 | * This function calls either the power-off rtas token in normal cases | ||
666 | * or the ibm,power-off-ups token (if present & requested) in case of | ||
667 | * a power failure. If power-off token is used, power on will only be | ||
668 | * possible with power button press. If ibm,power-off-ups token is used | ||
669 | * it will allow auto poweron after power is restored. | ||
670 | */ | ||
671 | static void pseries_power_off(void) | ||
672 | { | ||
673 | int rc; | ||
674 | int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups"); | ||
675 | |||
676 | if (rtas_flash_term_hook) | ||
677 | rtas_flash_term_hook(SYS_POWER_OFF); | ||
678 | |||
679 | if (rtas_poweron_auto == 0 || | ||
680 | rtas_poweroff_ups_token == RTAS_UNKNOWN_SERVICE) { | ||
681 | rc = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); | ||
682 | printk(KERN_INFO "RTAS power-off returned %d\n", rc); | ||
683 | } else { | ||
684 | rc = rtas_call(rtas_poweroff_ups_token, 0, 1, NULL); | ||
685 | printk(KERN_INFO "RTAS ibm,power-off-ups returned %d\n", rc); | ||
686 | } | ||
687 | for (;;); | ||
688 | } | ||
689 | |||
662 | /* | 690 | /* |
663 | * Called very early, MMU is off, device-tree isn't unflattened | 691 | * Called very early, MMU is off, device-tree isn't unflattened |
664 | */ | 692 | */ |
@@ -741,6 +769,8 @@ static int __init pSeries_probe(void) | |||
741 | else | 769 | else |
742 | hpte_init_native(); | 770 | hpte_init_native(); |
743 | 771 | ||
772 | pm_power_off = pseries_power_off; | ||
773 | |||
744 | pr_debug("Machine is%s LPAR !\n", | 774 | pr_debug("Machine is%s LPAR !\n", |
745 | (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); | 775 | (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); |
746 | 776 | ||
@@ -754,34 +784,6 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) | |||
754 | return PCI_PROBE_NORMAL; | 784 | return PCI_PROBE_NORMAL; |
755 | } | 785 | } |
756 | 786 | ||
757 | /** | ||
758 | * pSeries_power_off - tell firmware about how to power off the system. | ||
759 | * | ||
760 | * This function calls either the power-off rtas token in normal cases | ||
761 | * or the ibm,power-off-ups token (if present & requested) in case of | ||
762 | * a power failure. If power-off token is used, power on will only be | ||
763 | * possible with power button press. If ibm,power-off-ups token is used | ||
764 | * it will allow auto poweron after power is restored. | ||
765 | */ | ||
766 | static void pSeries_power_off(void) | ||
767 | { | ||
768 | int rc; | ||
769 | int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups"); | ||
770 | |||
771 | if (rtas_flash_term_hook) | ||
772 | rtas_flash_term_hook(SYS_POWER_OFF); | ||
773 | |||
774 | if (rtas_poweron_auto == 0 || | ||
775 | rtas_poweroff_ups_token == RTAS_UNKNOWN_SERVICE) { | ||
776 | rc = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); | ||
777 | printk(KERN_INFO "RTAS power-off returned %d\n", rc); | ||
778 | } else { | ||
779 | rc = rtas_call(rtas_poweroff_ups_token, 0, 1, NULL); | ||
780 | printk(KERN_INFO "RTAS ibm,power-off-ups returned %d\n", rc); | ||
781 | } | ||
782 | for (;;); | ||
783 | } | ||
784 | |||
785 | #ifndef CONFIG_PCI | 787 | #ifndef CONFIG_PCI |
786 | void pSeries_final_fixup(void) { } | 788 | void pSeries_final_fixup(void) { } |
787 | #endif | 789 | #endif |
@@ -796,7 +798,6 @@ define_machine(pseries) { | |||
796 | .pcibios_fixup = pSeries_final_fixup, | 798 | .pcibios_fixup = pSeries_final_fixup, |
797 | .pci_probe_mode = pSeries_pci_probe_mode, | 799 | .pci_probe_mode = pSeries_pci_probe_mode, |
798 | .restart = rtas_restart, | 800 | .restart = rtas_restart, |
799 | .power_off = pSeries_power_off, | ||
800 | .halt = rtas_halt, | 801 | .halt = rtas_halt, |
801 | .panic = rtas_os_term, | 802 | .panic = rtas_os_term, |
802 | .get_boot_time = rtas_get_boot_time, | 803 | .get_boot_time = rtas_get_boot_time, |