Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9178ba29 authored by Alexander Graf's avatar Alexander Graf Committed by Michael Ellerman
Browse files

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: default avatarAlexander Graf <agraf@suse.de>
[mpe: Squash into one patch and update changelog based on cover letter]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 0df1f248
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -142,7 +142,6 @@ struct machdep_calls {
#endif
#endif


	void		(*restart)(char *cmd);
	void		(*restart)(char *cmd);
	void		(*power_off)(void);
	void		(*halt)(void);
	void		(*halt)(void);
	void		(*panic)(char *str);
	void		(*panic)(char *str);
	void		(*cpu_die)(void);
	void		(*cpu_die)(void);
+3 −3
Original line number Original line Diff line number Diff line
@@ -139,8 +139,8 @@ void machine_restart(char *cmd)
void machine_power_off(void)
void machine_power_off(void)
{
{
	machine_shutdown();
	machine_shutdown();
	if (ppc_md.power_off)
	if (pm_power_off)
		ppc_md.power_off();
		pm_power_off();
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	smp_send_stop();
	smp_send_stop();
#endif
#endif
@@ -151,7 +151,7 @@ void machine_power_off(void)
/* Used by the G5 thermal driver */
/* Used by the G5 thermal driver */
EXPORT_SYMBOL_GPL(machine_power_off);
EXPORT_SYMBOL_GPL(machine_power_off);


void (*pm_power_off)(void) = machine_power_off;
void (*pm_power_off)(void);
EXPORT_SYMBOL_GPL(pm_power_off);
EXPORT_SYMBOL_GPL(pm_power_off);


void machine_halt(void)
void machine_halt(void)
+1 −1
Original line number Original line Diff line number Diff line
@@ -94,7 +94,7 @@ static int avr_probe(struct i2c_client *client,
{
{
	avr_i2c_client = client;
	avr_i2c_client = client;
	ppc_md.restart = avr_reset_system;
	ppc_md.restart = avr_reset_system;
	ppc_md.power_off = avr_power_off_system;
	pm_power_off = avr_power_off_system;
	return 0;
	return 0;
}
}


+2 −1
Original line number Original line Diff line number Diff line
@@ -212,6 +212,8 @@ static int __init efika_probe(void)
	DMA_MODE_READ = 0x44;
	DMA_MODE_READ = 0x44;
	DMA_MODE_WRITE = 0x48;
	DMA_MODE_WRITE = 0x48;


	pm_power_off = rtas_power_off;

	return 1;
	return 1;
}
}


@@ -225,7 +227,6 @@ define_machine(efika)
	.init_IRQ		= mpc52xx_init_irq,
	.init_IRQ		= mpc52xx_init_irq,
	.get_irq		= mpc52xx_get_irq,
	.get_irq		= mpc52xx_get_irq,
	.restart		= rtas_restart,
	.restart		= rtas_restart,
	.power_off		= rtas_power_off,
	.halt			= rtas_halt,
	.halt			= rtas_halt,
	.set_rtc_time		= rtas_set_rtc_time,
	.set_rtc_time		= rtas_set_rtc_time,
	.get_rtc_time		= rtas_get_rtc_time,
	.get_rtc_time		= rtas_get_rtc_time,
+4 −4
Original line number Original line Diff line number Diff line
@@ -167,10 +167,10 @@ static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id)
	if (ret)
	if (ret)
		goto err;
		goto err;


	/* XXX: this is potentially racy, but there is no lock for ppc_md */
	/* XXX: this is potentially racy, but there is no lock for pm_power_off */
	if (!ppc_md.power_off) {
	if (!pm_power_off) {
		glob_mcu = mcu;
		glob_mcu = mcu;
		ppc_md.power_off = mcu_power_off;
		pm_power_off = mcu_power_off;
		dev_info(&client->dev, "will provide power-off service\n");
		dev_info(&client->dev, "will provide power-off service\n");
	}
	}


@@ -197,7 +197,7 @@ static int mcu_remove(struct i2c_client *client)
	device_remove_file(&client->dev, &dev_attr_status);
	device_remove_file(&client->dev, &dev_attr_status);


	if (glob_mcu == mcu) {
	if (glob_mcu == mcu) {
		ppc_md.power_off = NULL;
		pm_power_off = NULL;
		glob_mcu = NULL;
		glob_mcu = NULL;
	}
	}


Loading