Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
14c03a4a
Commit
14c03a4a
authored
May 25, 2022
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge back reboot/poweroff notifiers rework for 5.19-rc1.
parents
09583dfe
6779db97
Changes
27
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
639 additions
and
124 deletions
+639
-124
arch/arm/kernel/reboot.c
arch/arm/kernel/reboot.c
+1
-3
arch/arm64/kernel/process.c
arch/arm64/kernel/process.c
+1
-2
arch/csky/kernel/power.c
arch/csky/kernel/power.c
+2
-4
arch/ia64/kernel/process.c
arch/ia64/kernel/process.c
+2
-2
arch/m68k/emu/natfeat.c
arch/m68k/emu/natfeat.c
+2
-1
arch/m68k/include/asm/machdep.h
arch/m68k/include/asm/machdep.h
+0
-1
arch/m68k/kernel/process.c
arch/m68k/kernel/process.c
+2
-3
arch/m68k/kernel/setup_mm.c
arch/m68k/kernel/setup_mm.c
+0
-1
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/setup_no.c
+0
-1
arch/m68k/mac/config.c
arch/m68k/mac/config.c
+3
-1
arch/mips/kernel/reset.c
arch/mips/kernel/reset.c
+1
-2
arch/parisc/kernel/process.c
arch/parisc/kernel/process.c
+2
-2
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup-common.c
+1
-3
arch/powerpc/xmon/xmon.c
arch/powerpc/xmon/xmon.c
+1
-2
arch/riscv/kernel/reset.c
arch/riscv/kernel/reset.c
+4
-8
arch/sh/kernel/reboot.c
arch/sh/kernel/reboot.c
+1
-2
arch/x86/kernel/reboot.c
arch/x86/kernel/reboot.c
+2
-2
arch/x86/xen/enlighten_pv.c
arch/x86/xen/enlighten_pv.c
+2
-2
drivers/acpi/sleep.c
drivers/acpi/sleep.c
+12
-4
drivers/memory/emif.c
drivers/memory/emif.c
+1
-1
drivers/regulator/pfuze100-regulator.c
drivers/regulator/pfuze100-regulator.c
+17
-25
drivers/soc/tegra/pmc.c
drivers/soc/tegra/pmc.c
+62
-25
include/linux/notifier.h
include/linux/notifier.h
+7
-0
include/linux/pm.h
include/linux/pm.h
+0
-1
include/linux/reboot.h
include/linux/reboot.h
+91
-0
kernel/notifier.c
kernel/notifier.c
+82
-19
kernel/reboot.c
kernel/reboot.c
+340
-7
No files found.
arch/arm/kernel/reboot.c
View file @
14c03a4a
...
...
@@ -116,9 +116,7 @@ void machine_power_off(void)
{
local_irq_disable
();
smp_send_stop
();
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
}
/*
...
...
arch/arm64/kernel/process.c
View file @
14c03a4a
...
...
@@ -111,8 +111,7 @@ void machine_power_off(void)
{
local_irq_disable
();
smp_send_stop
();
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
}
/*
...
...
arch/csky/kernel/power.c
View file @
14c03a4a
...
...
@@ -9,16 +9,14 @@ EXPORT_SYMBOL(pm_power_off);
void
machine_power_off
(
void
)
{
local_irq_disable
();
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
asm
volatile
(
"bkpt"
);
}
void
machine_halt
(
void
)
{
local_irq_disable
();
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
asm
volatile
(
"bkpt"
);
}
...
...
arch/ia64/kernel/process.c
View file @
14c03a4a
...
...
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/personality.h>
#include <linux/reboot.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/hotplug.h>
...
...
@@ -599,8 +600,7 @@ machine_halt (void)
void
machine_power_off
(
void
)
{
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
machine_halt
();
}
...
...
arch/m68k/emu/natfeat.c
View file @
14c03a4a
...
...
@@ -15,6 +15,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/io.h>
#include <asm/machdep.h>
#include <asm/natfeat.h>
...
...
@@ -90,5 +91,5 @@ void __init nf_init(void)
pr_info
(
"NatFeats found (%s, %lu.%lu)
\n
"
,
buf
,
version
>>
16
,
version
&
0xffff
);
mach_power_off
=
nf_poweroff
;
register_platform_power_off
(
nf_poweroff
)
;
}
arch/m68k/include/asm/machdep.h
View file @
14c03a4a
...
...
@@ -24,7 +24,6 @@ extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
extern
int
(
*
mach_set_rtc_pll
)(
struct
rtc_pll_info
*
);
extern
void
(
*
mach_reset
)(
void
);
extern
void
(
*
mach_halt
)(
void
);
extern
void
(
*
mach_power_off
)(
void
);
extern
unsigned
long
(
*
mach_hd_init
)
(
unsigned
long
,
unsigned
long
);
extern
void
(
*
mach_hd_setup
)(
char
*
,
int
*
);
extern
void
(
*
mach_heartbeat
)
(
int
);
...
...
arch/m68k/kernel/process.c
View file @
14c03a4a
...
...
@@ -67,12 +67,11 @@ void machine_halt(void)
void
machine_power_off
(
void
)
{
if
(
mach_power_off
)
mach_power_off
();
do_kernel_power_off
();
for
(;;);
}
void
(
*
pm_power_off
)(
void
)
=
machine_power_off
;
void
(
*
pm_power_off
)(
void
);
EXPORT_SYMBOL
(
pm_power_off
);
void
show_regs
(
struct
pt_regs
*
regs
)
...
...
arch/m68k/kernel/setup_mm.c
View file @
14c03a4a
...
...
@@ -98,7 +98,6 @@ EXPORT_SYMBOL(mach_get_rtc_pll);
EXPORT_SYMBOL
(
mach_set_rtc_pll
);
void
(
*
mach_reset
)(
void
);
void
(
*
mach_halt
)(
void
);
void
(
*
mach_power_off
)(
void
);
#ifdef CONFIG_HEARTBEAT
void
(
*
mach_heartbeat
)
(
int
);
EXPORT_SYMBOL
(
mach_heartbeat
);
...
...
arch/m68k/kernel/setup_no.c
View file @
14c03a4a
...
...
@@ -55,7 +55,6 @@ int (*mach_hwclk) (int, struct rtc_time*);
/* machine dependent reboot functions */
void
(
*
mach_reset
)(
void
);
void
(
*
mach_halt
)(
void
);
void
(
*
mach_power_off
)(
void
);
#ifdef CONFIG_M68000
#if defined(CONFIG_M68328)
...
...
arch/m68k/mac/config.c
View file @
14c03a4a
...
...
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/tty.h>
...
...
@@ -140,7 +141,6 @@ void __init config_mac(void)
mach_hwclk
=
mac_hwclk
;
mach_reset
=
mac_reset
;
mach_halt
=
mac_poweroff
;
mach_power_off
=
mac_poweroff
;
#if IS_ENABLED(CONFIG_INPUT_M68K_BEEP)
mach_beep
=
mac_mksound
;
#endif
...
...
@@ -160,6 +160,8 @@ void __init config_mac(void)
if
(
macintosh_config
->
ident
==
MAC_MODEL_IICI
)
mach_l2_flush
=
via_l2_flush
;
register_platform_power_off
(
mac_poweroff
);
}
...
...
arch/mips/kernel/reset.c
View file @
14c03a4a
...
...
@@ -114,8 +114,7 @@ void machine_halt(void)
void
machine_power_off
(
void
)
{
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
#ifdef CONFIG_SMP
preempt_disable
();
...
...
arch/parisc/kernel/process.c
View file @
14c03a4a
...
...
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/personality.h>
#include <linux/ptrace.h>
#include <linux/reboot.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/sched/task.h>
...
...
@@ -116,8 +117,7 @@ void machine_power_off(void)
pdc_chassis_send_status
(
PDC_CHASSIS_DIRECT_SHUTDOWN
);
/* ipmi_poweroff may have been installed. */
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
/* It seems we have no way to power the system off via
* software. The user has to press the button himself. */
...
...
arch/powerpc/kernel/setup-common.c
View file @
14c03a4a
...
...
@@ -161,9 +161,7 @@ void machine_restart(char *cmd)
void
machine_power_off
(
void
)
{
machine_shutdown
();
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
smp_send_stop
();
machine_hang
();
}
...
...
arch/powerpc/xmon/xmon.c
View file @
14c03a4a
...
...
@@ -1243,8 +1243,7 @@ static void bootcmds(void)
}
else
if
(
cmd
==
'h'
)
{
ppc_md
.
halt
();
}
else
if
(
cmd
==
'p'
)
{
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
}
}
...
...
arch/riscv/kernel/reset.c
View file @
14c03a4a
...
...
@@ -23,16 +23,12 @@ void machine_restart(char *cmd)
void
machine_halt
(
void
)
{
if
(
pm_power_off
!=
NULL
)
pm_power_off
();
else
default_power_off
();
do_kernel_power_off
();
default_power_off
();
}
void
machine_power_off
(
void
)
{
if
(
pm_power_off
!=
NULL
)
pm_power_off
();
else
default_power_off
();
do_kernel_power_off
();
default_power_off
();
}
arch/sh/kernel/reboot.c
View file @
14c03a4a
...
...
@@ -46,8 +46,7 @@ static void native_machine_shutdown(void)
static
void
native_machine_power_off
(
void
)
{
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
}
static
void
native_machine_halt
(
void
)
...
...
arch/x86/kernel/reboot.c
View file @
14c03a4a
...
...
@@ -739,10 +739,10 @@ static void native_machine_halt(void)
static
void
native_machine_power_off
(
void
)
{
if
(
pm_power_off
)
{
if
(
kernel_can_power_off
()
)
{
if
(
!
reboot_force
)
machine_shutdown
();
pm
_power_off
();
do_kernel
_power_off
();
}
/* A fallback in case there is no PM info available */
tboot_shutdown
(
TB_SHUTDOWN_HALT
);
...
...
arch/x86/xen/enlighten_pv.c
View file @
14c03a4a
...
...
@@ -30,6 +30,7 @@
#include <linux/pci.h>
#include <linux/gfp.h>
#include <linux/edd.h>
#include <linux/reboot.h>
#include <xen/xen.h>
#include <xen/events.h>
...
...
@@ -1069,8 +1070,7 @@ static void xen_machine_halt(void)
static
void
xen_machine_power_off
(
void
)
{
if
(
pm_power_off
)
pm_power_off
();
do_kernel_power_off
();
xen_reboot
(
SHUTDOWN_poweroff
);
}
...
...
drivers/acpi/sleep.c
View file @
14c03a4a
...
...
@@ -1035,20 +1035,22 @@ static void acpi_sleep_hibernate_setup(void)
static
inline
void
acpi_sleep_hibernate_setup
(
void
)
{}
#endif
/* !CONFIG_HIBERNATION */
static
void
acpi_power_off_prepare
(
void
)
static
int
acpi_power_off_prepare
(
struct
sys_off_data
*
data
)
{
/* Prepare to power off the system */
acpi_sleep_prepare
(
ACPI_STATE_S5
);
acpi_disable_all_gpes
();
acpi_os_wait_events_complete
();
return
NOTIFY_DONE
;
}
static
void
acpi_power_off
(
void
)
static
int
acpi_power_off
(
struct
sys_off_data
*
data
)
{
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
pr_debug
(
"%s called
\n
"
,
__func__
);
local_irq_disable
();
acpi_enter_sleep_state
(
ACPI_STATE_S5
);
return
NOTIFY_DONE
;
}
int
__init
acpi_sleep_init
(
void
)
...
...
@@ -1067,8 +1069,14 @@ int __init acpi_sleep_init(void)
if
(
acpi_sleep_state_supported
(
ACPI_STATE_S5
))
{
sleep_states
[
ACPI_STATE_S5
]
=
1
;
pm_power_off_prepare
=
acpi_power_off_prepare
;
pm_power_off
=
acpi_power_off
;
register_sys_off_handler
(
SYS_OFF_MODE_POWER_OFF_PREPARE
,
SYS_OFF_PRIO_FIRMWARE
,
acpi_power_off_prepare
,
NULL
);
register_sys_off_handler
(
SYS_OFF_MODE_POWER_OFF
,
SYS_OFF_PRIO_FIRMWARE
,
acpi_power_off
,
NULL
);
}
else
{
acpi_no_s5
=
true
;
}
...
...
drivers/memory/emif.c
View file @
14c03a4a
...
...
@@ -630,7 +630,7 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
dev_emerg
(
emif
->
dev
,
"SDRAM temperature exceeds operating limit.. Needs shut down!!!
\n
"
);
/* If we have Power OFF ability, use it, else try restarting */
if
(
pm_power_off
)
{
if
(
kernel_can_power_off
()
)
{
kernel_power_off
();
}
else
{
WARN
(
1
,
"FIXME: NO pm_power_off!!! trying restart
\n
"
);
...
...
drivers/regulator/pfuze100-regulator.c
View file @
14c03a4a
...
...
@@ -10,6 +10,7 @@
#include <linux/of_device.h>
#include <linux/regulator/of_regulator.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/pfuze100.h>
...
...
@@ -571,10 +572,10 @@ static inline struct device_node *match_of_node(int index)
return
pfuze_matches
[
index
].
of_node
;
}
static
struct
pfuze_chip
*
syspm_pfuze_chip
;
static
void
pfuze_power_off_prepare
(
void
)
static
int
pfuze_power_off_prepare
(
struct
sys_off_data
*
data
)
{
struct
pfuze_chip
*
syspm_pfuze_chip
=
data
->
cb_data
;
dev_info
(
syspm_pfuze_chip
->
dev
,
"Configure standby mode for power off"
);
/* Switch from default mode: APS/APS to APS/Off */
...
...
@@ -609,28 +610,30 @@ static void pfuze_power_off_prepare(void)
regmap_update_bits
(
syspm_pfuze_chip
->
regmap
,
PFUZE100_VGEN6VOL
,
PFUZE100_VGENxLPWR
|
PFUZE100_VGENxSTBY
,
PFUZE100_VGENxSTBY
);
return
NOTIFY_DONE
;
}
static
int
pfuze_power_off_prepare_init
(
struct
pfuze_chip
*
pfuze_chip
)
{
int
err
;
if
(
pfuze_chip
->
chip_id
!=
PFUZE100
)
{
dev_warn
(
pfuze_chip
->
dev
,
"Requested pm_power_off_prepare handler for not supported chip
\n
"
);
return
-
ENODEV
;
}
if
(
pm_power_off_prepare
)
{
dev_warn
(
pfuze_chip
->
dev
,
"pm_power_off_prepare is already registered.
\n
"
);
return
-
EBUSY
;
err
=
devm_register_sys_off_handler
(
pfuze_chip
->
dev
,
SYS_OFF_MODE_POWER_OFF_PREPARE
,
SYS_OFF_PRIO_DEFAULT
,
pfuze_power_off_prepare
,
pfuze_chip
);
if
(
err
)
{
dev_err
(
pfuze_chip
->
dev
,
"failed to register sys-off handler: %d
\n
"
,
err
);
return
err
;
}
if
(
syspm_pfuze_chip
)
{
dev_warn
(
pfuze_chip
->
dev
,
"syspm_pfuze_chip is already set.
\n
"
);
return
-
EBUSY
;
}
syspm_pfuze_chip
=
pfuze_chip
;
pm_power_off_prepare
=
pfuze_power_off_prepare
;
return
0
;
}
...
...
@@ -839,23 +842,12 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
return
0
;
}
static
int
pfuze100_regulator_remove
(
struct
i2c_client
*
client
)
{
if
(
syspm_pfuze_chip
)
{
syspm_pfuze_chip
=
NULL
;
pm_power_off_prepare
=
NULL
;
}
return
0
;
}
static
struct
i2c_driver
pfuze_driver
=
{
.
driver
=
{
.
name
=
"pfuze100-regulator"
,
.
of_match_table
=
pfuze_dt_ids
,
},
.
probe
=
pfuze100_regulator_probe
,
.
remove
=
pfuze100_regulator_remove
,
};
module_i2c_driver
(
pfuze_driver
);
...
...
drivers/soc/tegra/pmc.c
View file @
14c03a4a
...
...
@@ -39,6 +39,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/power_supply.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/reset.h>
...
...
@@ -108,6 +109,7 @@
#define PMC_USB_DEBOUNCE_DEL 0xec
#define PMC_USB_AO 0xf0
#define PMC_SCRATCH37 0x130
#define PMC_SCRATCH41 0x140
#define PMC_WAKE2_MASK 0x160
...
...
@@ -1099,8 +1101,7 @@ static struct notifier_block tegra_pmc_reboot_notifier = {
.
notifier_call
=
tegra_pmc_reboot_notify
,
};
static
int
tegra_pmc_restart_notify
(
struct
notifier_block
*
this
,
unsigned
long
action
,
void
*
data
)
static
void
tegra_pmc_restart
(
void
)
{
u32
value
;
...
...
@@ -1108,14 +1109,31 @@ static int tegra_pmc_restart_notify(struct notifier_block *this,
value
=
tegra_pmc_readl
(
pmc
,
PMC_CNTRL
);
value
|=
PMC_CNTRL_MAIN_RST
;
tegra_pmc_writel
(
pmc
,
value
,
PMC_CNTRL
);
}
static
int
tegra_pmc_restart_handler
(
struct
sys_off_data
*
data
)
{
tegra_pmc_restart
();
return
NOTIFY_DONE
;
}
static
struct
notifier_block
tegra_pmc_restart_handler
=
{
.
notifier_call
=
tegra_pmc_restart_notify
,
.
priority
=
128
,
};
static
int
tegra_pmc_power_off_handler
(
struct
sys_off_data
*
data
)
{
/*
* Reboot Nexus 7 into special bootloader mode if USB cable is
* connected in order to display battery status and power off.
*/
if
(
of_machine_is_compatible
(
"asus,grouper"
)
&&
power_supply_is_system_supplied
())
{
const
u32
go_to_charger_mode
=
0xa5a55a5a
;
tegra_pmc_writel
(
pmc
,
go_to_charger_mode
,
PMC_SCRATCH37
);
tegra_pmc_restart
();
}
return
NOTIFY_DONE
;
}
static
int
powergate_show
(
struct
seq_file
*
s
,
void
*
data
)
{
...
...
@@ -2877,6 +2895,42 @@ static int tegra_pmc_probe(struct platform_device *pdev)
pmc
->
clk
=
NULL
;
}
/*
* PMC should be last resort for restarting since it soft-resets
* CPU without resetting everything else.
*/
err
=
devm_register_reboot_notifier
(
&
pdev
->
dev
,
&
tegra_pmc_reboot_notifier
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to register reboot notifier, %d
\n
"
,
err
);
return
err
;
}
err
=
devm_register_sys_off_handler
(
&
pdev
->
dev
,
SYS_OFF_MODE_RESTART
,
SYS_OFF_PRIO_LOW
,
tegra_pmc_restart_handler
,
NULL
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register sys-off handler: %d
\n
"
,
err
);
return
err
;
}
/*
* PMC should be primary power-off method if it soft-resets CPU,
* asking bootloader to shutdown hardware.
*/
err
=
devm_register_sys_off_handler
(
&
pdev
->
dev
,
SYS_OFF_MODE_POWER_OFF
,
SYS_OFF_PRIO_FIRMWARE
,
tegra_pmc_power_off_handler
,
NULL
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register sys-off handler: %d
\n
"
,
err
);
return
err
;
}
/*
* PCLK clock rate can't be retrieved using CLK API because it
* causes lockup if CPU enters LP2 idle state from some other
...
...
@@ -2908,28 +2962,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)
goto
cleanup_sysfs
;
}
err
=
devm_register_reboot_notifier
(
&
pdev
->
dev
,
&
tegra_pmc_reboot_notifier
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to register reboot notifier, %d
\n
"
,
err
);
goto
cleanup_debugfs
;
}
err
=
register_restart_handler
(
&
tegra_pmc_restart_handler
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"unable to register restart handler, %d
\n
"
,
err
);
goto
cleanup_debugfs
;
}
err
=
tegra_pmc_pinctrl_init
(
pmc
);
if
(
err
)
goto
cleanup_
restart_handler
;
goto
cleanup_
debugfs
;
err
=
tegra_pmc_regmap_init
(
pmc
);
if
(
err
<
0
)
goto
cleanup_
restart_handler
;
goto
cleanup_
debugfs
;
err
=
tegra_powergate_init
(
pmc
,
pdev
->
dev
.
of_node
);
if
(
err
<
0
)
...
...
@@ -2952,8 +2991,6 @@ static int tegra_pmc_probe(struct platform_device *pdev)
cleanup_powergates:
tegra_powergate_remove_all
(
pdev
->
dev
.
of_node
);
cleanup_restart_handler:
unregister_restart_handler
(
&
tegra_pmc_restart_handler
);
cleanup_debugfs:
debugfs_remove
(
pmc
->
debugfs
);
cleanup_sysfs:
...
...
include/linux/notifier.h
View file @
14c03a4a
...
...
@@ -150,6 +150,11 @@ extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
extern
int
srcu_notifier_chain_register
(
struct
srcu_notifier_head
*
nh
,
struct
notifier_block
*
nb
);
extern
int
atomic_notifier_chain_register_unique_prio
(
struct
atomic_notifier_head
*
nh
,
struct
notifier_block
*
nb
);
extern
int
blocking_notifier_chain_register_unique_prio
(
struct
blocking_notifier_head
*
nh
,
struct
notifier_block
*
nb
);
extern
int
atomic_notifier_chain_unregister
(
struct
atomic_notifier_head
*
nh
,
struct
notifier_block
*
nb
);
extern
int
blocking_notifier_chain_unregister
(
struct
blocking_notifier_head
*
nh
,
...
...
@@ -173,6 +178,8 @@ extern int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh
extern
int
raw_notifier_call_chain_robust
(
struct
raw_notifier_head
*
nh
,
unsigned
long
val_up
,
unsigned
long
val_down
,
void
*
v
);
extern
bool
atomic_notifier_call_chain_is_empty
(
struct
atomic_notifier_head
*
nh
);
#define NOTIFY_DONE 0x0000
/* Don't care */
#define NOTIFY_OK 0x0001
/* Suits me */
#define NOTIFY_STOP_MASK 0x8000
/* Don't call further */
...
...
include/linux/pm.h
View file @
14c03a4a
...
...
@@ -21,7 +21,6 @@
* Callbacks for platform drivers to implement.
*/
extern
void
(
*
pm_power_off
)(
void
);
extern
void
(
*
pm_power_off_prepare
)(
void
);
struct
device
;
/* we have a circular dep with device.h */
#ifdef CONFIG_VT_CONSOLE_SLEEP
...
...
include/linux/reboot.h
View file @
14c03a4a
...
...
@@ -7,6 +7,7 @@
#include <uapi/linux/reboot.h>
struct
device
;
struct
sys_off_handler
;
#define SYS_DOWN 0x0001
/* Notify of system down */
#define SYS_RESTART SYS_DOWN
...
...
@@ -62,6 +63,95 @@ extern void machine_shutdown(void);
struct
pt_regs
;
extern
void
machine_crash_shutdown
(
struct
pt_regs
*
);
void
do_kernel_power_off
(
void
);
/*
* sys-off handler API.
*/
/*
* Standard sys-off priority levels. Users are expected to set priorities
* relative to the standard levels.
*
* SYS_OFF_PRIO_PLATFORM: Use this for platform-level handlers.
*
* SYS_OFF_PRIO_LOW: Use this for handler of last resort.
*
* SYS_OFF_PRIO_DEFAULT: Use this for normal handlers.
*
* SYS_OFF_PRIO_HIGH: Use this for higher priority handlers.
*
* SYS_OFF_PRIO_FIRMWARE: Use this if handler uses firmware call.
*/
#define SYS_OFF_PRIO_PLATFORM -256
#define SYS_OFF_PRIO_LOW -128
#define SYS_OFF_PRIO_DEFAULT 0
#define SYS_OFF_PRIO_HIGH 192
#define SYS_OFF_PRIO_FIRMWARE 224
enum
sys_off_mode
{
/**
* @SYS_OFF_MODE_POWER_OFF_PREPARE:
*
* Handlers prepare system to be powered off. Handlers are
* allowed to sleep.
*/
SYS_OFF_MODE_POWER_OFF_PREPARE
,
/**
* @SYS_OFF_MODE_POWER_OFF:
*
* Handlers power-off system. Handlers are disallowed to sleep.
*/
SYS_OFF_MODE_POWER_OFF
,
/**
* @SYS_OFF_MODE_RESTART:
*
* Handlers restart system. Handlers are disallowed to sleep.
*/
SYS_OFF_MODE_RESTART
,
};
/**
* struct sys_off_data - sys-off callback argument
*
* @mode: Mode ID. Currently used only by the sys-off restart mode,
* see enum reboot_mode for the available modes.
* @cb_data: User's callback data.
* @cmd: Command string. Currently used only by the sys-off restart mode,
* NULL otherwise.
*/
struct
sys_off_data
{
int
mode
;
void
*
cb_data
;
const
char
*
cmd
;
};
struct
sys_off_handler
*
register_sys_off_handler
(
enum
sys_off_mode
mode
,
int
priority
,
int
(
*
callback
)(
struct
sys_off_data
*
data
),
void
*
cb_data
);
void
unregister_sys_off_handler
(
struct
sys_off_handler
*
handler
);
int
devm_register_sys_off_handler
(
struct
device
*
dev
,
enum
sys_off_mode
mode
,
int
priority
,
int
(
*
callback
)(
struct
sys_off_data
*
data
),
void
*
cb_data
);
int
devm_register_power_off_handler
(
struct
device
*
dev
,
int
(
*
callback
)(
struct
sys_off_data
*
data
),
void
*
cb_data
);
int
devm_register_restart_handler
(
struct
device
*
dev
,
int
(
*
callback
)(
struct
sys_off_data
*
data
),
void
*
cb_data
);
int
register_platform_power_off
(
void
(
*
power_off
)(
void
));
void
unregister_platform_power_off
(
void
(
*
power_off
)(
void
));
/*
* Architecture independent implemenations of sys_reboot commands.
*/
...
...
@@ -70,6 +160,7 @@ extern void kernel_restart_prepare(char *cmd);
extern
void
kernel_restart
(
char
*
cmd
);
extern
void
kernel_halt
(
void
);
extern
void
kernel_power_off
(
void
);
extern
bool
kernel_can_power_off
(
void
);
extern
int
C_A_D
;
/* for sysctl */
void
ctrl_alt_del
(
void
);
...
...
kernel/notifier.c
View file @
14c03a4a
...
...
@@ -20,7 +20,8 @@ BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
*/
static
int
notifier_chain_register
(
struct
notifier_block
**
nl
,
struct
notifier_block
*
n
)
struct
notifier_block
*
n
,
bool
unique_priority
)
{
while
((
*
nl
)
!=
NULL
)
{
if
(
unlikely
((
*
nl
)
==
n
))
{
...
...
@@ -30,6 +31,8 @@ static int notifier_chain_register(struct notifier_block **nl,
}
if
(
n
->
priority
>
(
*
nl
)
->
priority
)
break
;
if
(
n
->
priority
==
(
*
nl
)
->
priority
&&
unique_priority
)
return
-
EBUSY
;
nl
=
&
((
*
nl
)
->
next
);
}
n
->
next
=
*
nl
;
...
...
@@ -144,12 +147,35 @@ int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
int
ret
;
spin_lock_irqsave
(
&
nh
->
lock
,
flags
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
,
false
);
spin_unlock_irqrestore
(
&
nh
->
lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
atomic_notifier_chain_register
);
/**
* atomic_notifier_chain_register_unique_prio - Add notifier to an atomic notifier chain
* @nh: Pointer to head of the atomic notifier chain
* @n: New entry in notifier chain
*
* Adds a notifier to an atomic notifier chain if there is no other
* notifier registered using the same priority.
*
* Returns 0 on success, %-EEXIST or %-EBUSY on error.
*/
int
atomic_notifier_chain_register_unique_prio
(
struct
atomic_notifier_head
*
nh
,
struct
notifier_block
*
n
)
{
unsigned
long
flags
;
int
ret
;
spin_lock_irqsave
(
&
nh
->
lock
,
flags
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
,
true
);
spin_unlock_irqrestore
(
&
nh
->
lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
atomic_notifier_chain_register_unique_prio
);
/**
* atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain
* @nh: Pointer to head of the atomic notifier chain
...
...
@@ -204,23 +230,27 @@ int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
EXPORT_SYMBOL_GPL
(
atomic_notifier_call_chain
);
NOKPROBE_SYMBOL
(
atomic_notifier_call_chain
);
/**
* atomic_notifier_call_chain_is_empty - Check whether notifier chain is empty
* @nh: Pointer to head of the atomic notifier chain
*
* Checks whether notifier chain is empty.
*
* Returns true is notifier chain is empty, false otherwise.
*/
bool
atomic_notifier_call_chain_is_empty
(
struct
atomic_notifier_head
*
nh
)
{
return
!
rcu_access_pointer
(
nh
->
head
);
}
/*
* Blocking notifier chain routines. All access to the chain is
* synchronized by an rwsem.
*/
/**
* blocking_notifier_chain_register - Add notifier to a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
* @n: New entry in notifier chain
*
* Adds a notifier to a blocking notifier chain.
* Must be called in process context.
*
* Returns 0 on success, %-EEXIST on error.
*/
int
blocking_notifier_chain_register
(
struct
blocking_notifier_head
*
nh
,
struct
notifier_block
*
n
)
static
int
__blocking_notifier_chain_register
(
struct
blocking_notifier_head
*
nh
,
struct
notifier_block
*
n
,
bool
unique_priority
)
{
int
ret
;
...
...
@@ -230,15 +260,48 @@ int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
* such times we must not call down_write().
*/
if
(
unlikely
(
system_state
==
SYSTEM_BOOTING
))
return
notifier_chain_register
(
&
nh
->
head
,
n
);
return
notifier_chain_register
(
&
nh
->
head
,
n
,
unique_priority
);
down_write
(
&
nh
->
rwsem
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
,
unique_priority
);
up_write
(
&
nh
->
rwsem
);
return
ret
;
}
/**
* blocking_notifier_chain_register - Add notifier to a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
* @n: New entry in notifier chain
*
* Adds a notifier to a blocking notifier chain.
* Must be called in process context.
*
* Returns 0 on success, %-EEXIST on error.
*/
int
blocking_notifier_chain_register
(
struct
blocking_notifier_head
*
nh
,
struct
notifier_block
*
n
)
{
return
__blocking_notifier_chain_register
(
nh
,
n
,
false
);
}
EXPORT_SYMBOL_GPL
(
blocking_notifier_chain_register
);
/**
* blocking_notifier_chain_register_unique_prio - Add notifier to a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
* @n: New entry in notifier chain
*
* Adds a notifier to an blocking notifier chain if there is no other
* notifier registered using the same priority.
*
* Returns 0 on success, %-EEXIST or %-EBUSY on error.
*/
int
blocking_notifier_chain_register_unique_prio
(
struct
blocking_notifier_head
*
nh
,
struct
notifier_block
*
n
)
{
return
__blocking_notifier_chain_register
(
nh
,
n
,
true
);
}
EXPORT_SYMBOL_GPL
(
blocking_notifier_chain_register_unique_prio
);
/**
* blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
...
...
@@ -341,7 +404,7 @@ EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
int
raw_notifier_chain_register
(
struct
raw_notifier_head
*
nh
,
struct
notifier_block
*
n
)
{
return
notifier_chain_register
(
&
nh
->
head
,
n
);
return
notifier_chain_register
(
&
nh
->
head
,
n
,
false
);
}
EXPORT_SYMBOL_GPL
(
raw_notifier_chain_register
);
...
...
@@ -420,10 +483,10 @@ int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
* such times we must not call mutex_lock().
*/
if
(
unlikely
(
system_state
==
SYSTEM_BOOTING
))
return
notifier_chain_register
(
&
nh
->
head
,
n
);
return
notifier_chain_register
(
&
nh
->
head
,
n
,
false
);
mutex_lock
(
&
nh
->
mutex
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
);
ret
=
notifier_chain_register
(
&
nh
->
head
,
n
,
false
);
mutex_unlock
(
&
nh
->
mutex
);
return
ret
;
}
...
...
kernel/reboot.c
View file @
14c03a4a
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment