diff mbox

[-v8,11/11] Move arch/x86 reboot= handling to generic kernel.

Message ID 1367937595-32241-12-git-send-email-holt@sgi.com (mailing list archive)
State New, archived
Headers show

Commit Message

Robin Holt May 7, 2013, 2:39 p.m. UTC
Merge together the unicore32, arm, and x86 reboot= command line
parameter handling.

Signed-off-by: Robin Holt <holt@sgi.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Guan Xuetao <gxt@mprc.pku.edu.cn>
Cc: Russ Anderson <rja@sgi.com>
Cc: Robin Holt <holt@sgi.com>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Cc: the arch/x86 maintainers <x86@kernel.org>
Cc: Arm Mailing List <linux-arm-kernel@lists.infradead.org>
---
 Documentation/kernel-parameters.txt      |  18 ++++-
 arch/arm/kernel/process.c                |  10 ---
 arch/unicore32/kernel/process.c          |  10 ---
 arch/x86/include/asm/emergency-restart.h |  12 ----
 arch/x86/kernel/apic/x2apic_uv_x.c       |   2 +-
 arch/x86/kernel/reboot.c                 | 111 +------------------------------
 include/linux/reboot.h                   |  17 +++++
 kernel/reboot.c                          |  90 ++++++++++++++++++++++++-
 8 files changed, 125 insertions(+), 145 deletions(-)

Comments

Ingo Molnar May 8, 2013, 10:39 a.m. UTC | #1
* Robin Holt <holt@sgi.com> wrote:

> Merge together the unicore32, arm, and x86 reboot= command line
> parameter handling.

The series still has this CONFIG_X86 dependency that I inquired about 
previously:

> +static int __init reboot_setup(char *str)
> +{
> +	for (;;) {
> +		/*
> +		 * Having anything passed on the command line via
> +		 * reboot= will cause us to disable DMI checking
> +		 * below.
> +		 */
> +		reboot_default = 0;
> +
> +		switch (*str) {
> +#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
> +		case 'w':
> +			reboot_mode = REBOOT_WARM;
> +			break;
> +
> +		case 'c':
> +			reboot_mode = REBOOT_COLD;
> +			break;
> +
> +#ifdef CONFIG_SMP
> +		case 's':
> +			if (isdigit(*(str+1))) {
> +				reboot_cpu = (int) (*(str+1) - '0');
> +				if (isdigit(*(str+2)))
> +					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
> +			}
> +			/*
> +			 * We will leave sorting out the final value
> +			 * when we are ready to reboot, since we might not
> +			 * have detected BSP APIC ID or smp_num_cpu
> +			 */
> +			break;
> +#endif /* CONFIG_SMP */
> +
> +#else
> +		case 's':
> +			reboot_mode = REBOOT_WARM;
> +		case 'h':
> +			reboot_mode = REBOOT_COLD;
> +		case 'g':
> +			reboot_mode = REBOOT_GPIO;
> +#endif
> +
> +		case 'b':
> +		case 'a':
> +		case 'k':
> +		case 't':
> +		case 'e':
> +		case 'p':
> +			reboot_type = *str;
> +			break;
> +
> +		case 'f':
> +			reboot_force = 1;
> +			break;
> +		}
> +
> +		str = strchr(str, ',');
> +		if (str)
> +			str++;
> +		else
> +			break;
> +	}
> +	return 1;

To explain my concern more verbosely, if we cannot make it 'obviously 
generic' then there's no point in moving it to kernel/reboot.c ...

And yes, I realize that there's an option clash between architectures - 
see below for potential solutions to that.

To generalize it, firstly here's a summary of the existing reboot option 
mappings:

 x86-only:  w, c, s
 non-x86:         s, h, g
 generic:                  b, a, k, t, e, p, f


it appears that 'w', 'c', 'h', and 'g' could be made generic straight 
away.

Which leaves 's' as the only truly problematic option:

 - it means REBOOT_WARM on some non-x86 platform(s?)
 - while it means the SMP-cpu on x86.

Stupid question: which non-x86 platform(s) use 's'?

I think we should either change that platform to have 'w' as the warm 
reboot (and hope that no-one actually relies on the old 's' option: it's a 
truly rare option) - or change the x86 mapping from 's' to 'S' and 
generalize and unify it thusly.

Another cleanliness problem is the duality of reboot_mode and reboot_type. 
We should pick one and use it everywhere consistently.

[ Once these problems are solved and there's no objections from others to 
  this approach, I'd be willing to apply, test and push this series to 
  Linus. ]

Thanks,

	Ingo
Russell King - ARM Linux May 8, 2013, 6:20 p.m. UTC | #2
On Wed, May 08, 2013 at 12:39:56PM +0200, Ingo Molnar wrote:
> To generalize it, firstly here's a summary of the existing reboot option 
> mappings:
> 
>  x86-only:  w, c, s
>  non-x86:         s, h, g
>  generic:                  b, a, k, t, e, p, f
> 
> 
> it appears that 'w', 'c', 'h', and 'g' could be made generic straight 
> away.
> 
> Which leaves 's' as the only truly problematic option:
> 
>  - it means REBOOT_WARM on some non-x86 platform(s?)
>  - while it means the SMP-cpu on x86.
> 
> Stupid question: which non-x86 platform(s) use 's'?

Let's try to get the meaning back.  On ARM, these are taken from the first
letter of the 'reboot=' command line argument, which was initially either
"hard" or "soft".  This refers to whether we hit some bit of hardware
which physically asserts some reset line in the system, or merely vector
the CPU via the reset vector (for some systems, this is the only
possibility.)

Then PXA happened, and there was a need for some platforms there to do
a hardware restart via toggling a GPIO output, which would then ultimately
assert the system reset line.  So we then added the "gpio" mode as well.
reboot via toggling a GPIO output.  So we then ended up with "gpio" as
well.

So, on ARM, the modes are: hard, soft, gpio, which get translated to a
single letter by the simple parsing code:

static char reboot_mode = 'h';

int __init reboot_setup(char *str)
{
        reboot_mode = str[0];
        return 1;
}

__setup("reboot=", reboot_setup);

Now, arguably, "hard" and "soft" have an entirely different meaning to
"warm" and "cold" in the normal parlence.  A "warm" reboot involves the
system doing less tasks at restart than a "cold" reboot.  This is not
necessarily the case between 'hard' and 'soft'.

So, while I don't entirely agree with mapping "hard" to "cold" and
"soft" to "warm", I guess for the sake of generalisation it's okay.
However, thinking about the future, if ARM becomes more server-like,
we might also want "cold" and "warm" reboot identifiers too.

I think the solution to this would be to have the new generic code
parse the entire argument, not just the first letter - certainly for
the 's' case.  If it's the x86 version, it'll be "s<number>".  If
it's the ARM version, it should be "soft".
Russell King - ARM Linux May 8, 2013, 6:23 p.m. UTC | #3
On Tue, May 07, 2013 at 09:39:55AM -0500, Robin Holt wrote:
> +		case 's':
> +			reboot_mode = REBOOT_WARM;
> +		case 'h':
> +			reboot_mode = REBOOT_COLD;
> +		case 'g':
> +			reboot_mode = REBOOT_GPIO;

Further to Ingo's comments, also note that the above is broken.  Any
of s,h,g will result in REBOOT_GPIO being set which is clearly wrong.
H. Peter Anvin May 8, 2013, 6:33 p.m. UTC | #4
On 05/08/2013 11:20 AM, Russell King - ARM Linux wrote:
> 
> Let's try to get the meaning back.  On ARM, these are taken from the first
> letter of the 'reboot=' command line argument, which was initially either
> "hard" or "soft".  This refers to whether we hit some bit of hardware
> which physically asserts some reset line in the system, or merely vector
> the CPU via the reset vector (for some systems, this is the only
> possibility.)
> 
> Then PXA happened, and there was a need for some platforms there to do
> a hardware restart via toggling a GPIO output, which would then ultimately
> assert the system reset line.  So we then added the "gpio" mode as well.
> reboot via toggling a GPIO output.  So we then ended up with "gpio" as
> well.
> 
> So, on ARM, the modes are: hard, soft, gpio, which get translated to a
> single letter by the simple parsing code:
> 
> static char reboot_mode = 'h';
> 
> int __init reboot_setup(char *str)
> {
>         reboot_mode = str[0];
>         return 1;
> }
> 
> __setup("reboot=", reboot_setup);
> 
> Now, arguably, "hard" and "soft" have an entirely different meaning to
> "warm" and "cold" in the normal parlence.  A "warm" reboot involves the
> system doing less tasks at restart than a "cold" reboot.  This is not
> necessarily the case between 'hard' and 'soft'.
> 
> So, while I don't entirely agree with mapping "hard" to "cold" and
> "soft" to "warm", I guess for the sake of generalisation it's okay.
> However, thinking about the future, if ARM becomes more server-like,
> we might also want "cold" and "warm" reboot identifiers too.
> 
> I think the solution to this would be to have the new generic code
> parse the entire argument, not just the first letter - certainly for
> the 's' case.  If it's the x86 version, it'll be "s<number>".  If
> it's the ARM version, it should be "soft".
> 

The s<number> thing is pretty awful, admittedly (it was supposed to be
smp<number>, but the parser, rather than *allowing* only the first
letter, seems to *require* that it is only the first letter.)

The problem I see is that we don't know what we'll break if we change
it, but Ingo seems to think it doesn't matter so much.

For the boolean letter argument, we could simply have the parser set a
bitmask of the letters seen; the x86 "s" argument is clearly an outlier.

We could handle it in a generic exception by looking for s<digit> or
smp<digit>, which will not match ARM's "soft" argument.  I suspect we
can worry about other argument-carrying options in a generic fashion
when the need arises; I would personally prefer the "subtag:argument"
format used by libata &c for that, and the presence of a ':' would be
indicative.

	-hpa
Andrew Morton May 8, 2013, 8:50 p.m. UTC | #5
On Tue,  7 May 2013 09:39:55 -0500 Robin Holt <holt@sgi.com> wrote:

> Merge together the unicore32, arm, and x86 reboot= command line
> parameter handling.
> 
> ...
>
> +static int __init reboot_setup(char *str)
> +{
> +	for (;;) {
> +		/*
> +		 * Having anything passed on the command line via
> +		 * reboot= will cause us to disable DMI checking
> +		 * below.
> +		 */
> +		reboot_default = 0;
> +
> +		switch (*str) {
> +#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
> +		case 'w':
> +			reboot_mode = REBOOT_WARM;
> +			break;
> +
> +		case 'c':
> +			reboot_mode = REBOOT_COLD;
> +			break;
> +
> +#ifdef CONFIG_SMP
> +		case 's':
> +			if (isdigit(*(str+1))) {
> +				reboot_cpu = (int) (*(str+1) - '0');
> +				if (isdigit(*(str+2)))
> +					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
> +			}

Boy, that's some weird stuff.

What's wrong with doing

			if (isdigit(str[1])) {
				reboot_cpu = str[1] - '0';
				if (isdigit(str[2]))
					reboot_cpu = reboot_cpu * 10 +
							str[2] - '0';
			}

?

But it's still nonsense - we should eliminate its
you-have-less-than-101-CPUs restriction by using, you know, atoi().
Robin Holt May 9, 2013, 11:20 a.m. UTC | #6
On Wed, May 08, 2013 at 11:33:39AM -0700, H. Peter Anvin wrote:
> On 05/08/2013 11:20 AM, Russell King - ARM Linux wrote:
> > 
> > Let's try to get the meaning back.  On ARM, these are taken from the first
> > letter of the 'reboot=' command line argument, which was initially either
> > "hard" or "soft".  This refers to whether we hit some bit of hardware
> > which physically asserts some reset line in the system, or merely vector
> > the CPU via the reset vector (for some systems, this is the only
> > possibility.)
> > 
> > Then PXA happened, and there was a need for some platforms there to do
> > a hardware restart via toggling a GPIO output, which would then ultimately
> > assert the system reset line.  So we then added the "gpio" mode as well.
> > reboot via toggling a GPIO output.  So we then ended up with "gpio" as
> > well.
> > 
> > So, on ARM, the modes are: hard, soft, gpio, which get translated to a
> > single letter by the simple parsing code:
> > 
> > static char reboot_mode = 'h';
> > 
> > int __init reboot_setup(char *str)
> > {
> >         reboot_mode = str[0];
> >         return 1;
> > }
> > 
> > __setup("reboot=", reboot_setup);
> > 
> > Now, arguably, "hard" and "soft" have an entirely different meaning to
> > "warm" and "cold" in the normal parlence.  A "warm" reboot involves the
> > system doing less tasks at restart than a "cold" reboot.  This is not
> > necessarily the case between 'hard' and 'soft'.
> > 
> > So, while I don't entirely agree with mapping "hard" to "cold" and
> > "soft" to "warm", I guess for the sake of generalisation it's okay.
> > However, thinking about the future, if ARM becomes more server-like,
> > we might also want "cold" and "warm" reboot identifiers too.
> > 
> > I think the solution to this would be to have the new generic code
> > parse the entire argument, not just the first letter - certainly for
> > the 's' case.  If it's the x86 version, it'll be "s<number>".  If
> > it's the ARM version, it should be "soft".
> > 
> 
> The s<number> thing is pretty awful, admittedly (it was supposed to be
> smp<number>, but the parser, rather than *allowing* only the first
> letter, seems to *require* that it is only the first letter.)
> 
> The problem I see is that we don't know what we'll break if we change
> it, but Ingo seems to think it doesn't matter so much.
> 
> For the boolean letter argument, we could simply have the parser set a
> bitmask of the letters seen; the x86 "s" argument is clearly an outlier.
> 
> We could handle it in a generic exception by looking for s<digit> or
> smp<digit>, which will not match ARM's "soft" argument.  I suspect we
> can worry about other argument-carrying options in a generic fashion
> when the need arises; I would personally prefer the "subtag:argument"
> format used by libata &c for that, and the presence of a ':' would be
> indicative.

Is there really a reason for having this conglomeration of disparate
options all merged together?  Why can't we go with having a separate
param(reboot_cpu, int, 0644); so it can be controlled via sysfs as
well?  If we are breaking the reboot=s## syntax, why not become a
little more standardized with the reboot_cpu?

Robin
Robin Holt May 9, 2013, 11:29 a.m. UTC | #7
On Wed, May 08, 2013 at 01:50:29PM -0700, Andrew Morton wrote:
> On Tue,  7 May 2013 09:39:55 -0500 Robin Holt <holt@sgi.com> wrote:
> 
> > Merge together the unicore32, arm, and x86 reboot= command line
> > parameter handling.
> > 
> > ...
> >
> > +static int __init reboot_setup(char *str)
> > +{
> > +	for (;;) {
> > +		/*
> > +		 * Having anything passed on the command line via
> > +		 * reboot= will cause us to disable DMI checking
> > +		 * below.
> > +		 */
> > +		reboot_default = 0;
> > +
> > +		switch (*str) {
> > +#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
> > +		case 'w':
> > +			reboot_mode = REBOOT_WARM;
> > +			break;
> > +
> > +		case 'c':
> > +			reboot_mode = REBOOT_COLD;
> > +			break;
> > +
> > +#ifdef CONFIG_SMP
> > +		case 's':
> > +			if (isdigit(*(str+1))) {
> > +				reboot_cpu = (int) (*(str+1) - '0');
> > +				if (isdigit(*(str+2)))
> > +					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
> > +			}
> 
> Boy, that's some weird stuff.
> 
> What's wrong with doing
> 
> 			if (isdigit(str[1])) {
> 				reboot_cpu = str[1] - '0';
> 				if (isdigit(str[2]))
> 					reboot_cpu = reboot_cpu * 10 +
> 							str[2] - '0';
> 			}
> 
> ?
> 
> But it's still nonsense - we should eliminate its
> you-have-less-than-101-CPUs restriction by using, you know, atoi().

I had an earlier version which I must have dropped which handled the
larger parsing, but I do like your suggestion of using atoi.  I will
submit a -v9 in a few hours.

Robin
Robin Holt May 9, 2013, 11:29 a.m. UTC | #8
On Wed, May 08, 2013 at 07:23:05PM +0100, Russell King - ARM Linux wrote:
> On Tue, May 07, 2013 at 09:39:55AM -0500, Robin Holt wrote:
> > +		case 's':
> > +			reboot_mode = REBOOT_WARM;
> > +		case 'h':
> > +			reboot_mode = REBOOT_COLD;
> > +		case 'g':
> > +			reboot_mode = REBOOT_GPIO;
> 
> Further to Ingo's comments, also note that the above is broken.  Any
> of s,h,g will result in REBOOT_GPIO being set which is clearly wrong.

I couldn't be more of an idiot.  I will fix it in -v9.

Robin
diff mbox

Patch

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c3bfacb..87e8dea 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2677,9 +2677,21 @@  bytes respectively. Such letter suffixes can also be entirely omitted.
 			Run specified binary instead of /init from the ramdisk,
 			used for early userspace startup. See initrd.
 
-	reboot=		[BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
-			Format: <reboot_mode>[,<reboot_mode2>[,...]]
-			See arch/*/kernel/reboot.c or arch/*/kernel/process.c
+	reboot=		[KNL]
+			Format (x86 or x86_64):
+				[w[arm] | c[old]] \
+				[,] s[mp]#### \
+				[,b[ios] | a[cpi] | k[bd] | t[riple] | e[fi] | p[ci]] \
+				[,f[orce]
+			Format (all other archs):
+				[s[oft] | h[ard]] \
+				[,b[ios] | a[cpi] | k[bd] | t[riple] | e[fi] | p[ci]] \
+				[,f[orce]]
+			Where reboot_mode is one of warm (soft) or cold,
+			      reboot_type is one of bios, acpi, kbd, triple, efi, or pci,
+			      reboot_force is either force or not specified,
+			      reboot_cpu is s[mp]#### with #### being the processor
+					(in decimal) to be used for rebooting.
 
 	relax_domain_level=
 			[KNL, SMP] Set scheduler's default relax_domain_level.
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 58c0d7a..304b102 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -175,16 +175,6 @@  void arch_cpu_idle(void)
 		default_idle();
 }
 
-enum reboot_mode reboot_mode;
-
-static int __init reboot_setup(char *str)
-{
-	if ('s' == str[0])
-		reboot_mode = REBOOT_WARM;
-	return 1;
-}
-__setup("reboot=", reboot_setup);
-
 void machine_shutdown(void)
 {
 #ifdef CONFIG_SMP
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index 9dc6e48..fdb8e79 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -51,16 +51,6 @@  void arch_cpu_idle(void)
 	local_irq_enable();
 }
 
-static enum reboot_mode reboot_mode;
-
-int __init reboot_setup(char *str)
-{
-	if ('s' == str[0])
-		reboot_mode = REBOOT_WARM;
-	return 1;
-}
-__setup("reboot=", reboot_setup);
-
 void machine_halt(void)
 {
 	gpio_set_value(GPO_SOFT_OFF, 0);
diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h
index 75ce3f4..77a99ac 100644
--- a/arch/x86/include/asm/emergency-restart.h
+++ b/arch/x86/include/asm/emergency-restart.h
@@ -1,18 +1,6 @@ 
 #ifndef _ASM_X86_EMERGENCY_RESTART_H
 #define _ASM_X86_EMERGENCY_RESTART_H
 
-enum reboot_type {
-	BOOT_TRIPLE = 't',
-	BOOT_KBD = 'k',
-	BOOT_BIOS = 'b',
-	BOOT_ACPI = 'a',
-	BOOT_EFI = 'e',
-	BOOT_CF9 = 'p',
-	BOOT_CF9_COND = 'q',
-};
-
-extern enum reboot_type reboot_type;
-
 extern void machine_emergency_restart(void);
 
 #endif /* _ASM_X86_EMERGENCY_RESTART_H */
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 794f6eb..958e3e4 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -25,6 +25,7 @@ 
 #include <linux/kdebug.h>
 #include <linux/delay.h>
 #include <linux/crash_dump.h>
+#include <linux/reboot.h>
 
 #include <asm/uv/uv_mmrs.h>
 #include <asm/uv/uv_hub.h>
@@ -36,7 +37,6 @@ 
 #include <asm/ipi.h>
 #include <asm/smp.h>
 #include <asm/x86_init.h>
-#include <asm/emergency-restart.h>
 #include <asm/nmi.h>
 
 /* BMC sets a bit this MMR non-zero before sending an NMI */
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d42e3b2..563ed91 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -36,22 +36,6 @@  void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 static const struct desc_ptr no_idt = {};
-static enum reboot_mode reboot_mode = REBOOT_COLD;
-enum reboot_type reboot_type = BOOT_ACPI;
-int reboot_force;
-
-/*
- * This variable is used privately to keep track of whether or not
- * reboot_type is still set to its default value (i.e., reboot= hasn't
- * been set on the command line).  This is needed so that we can
- * suppress DMI scanning for reboot quirks.  Without it, it's
- * impossible to override a faulty reboot quirk without recompiling.
- */
-static int reboot_default = 1;
-
-#ifdef CONFIG_SMP
-static int reboot_cpu = -1;
-#endif
 
 /*
  * This is set if we need to go through the 'emergency' path.
@@ -64,79 +48,6 @@  static int reboot_emergency;
 bool port_cf9_safe = false;
 
 /*
- * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
- * warm   Don't set the cold reboot flag
- * cold   Set the cold reboot flag
- * bios   Reboot by jumping through the BIOS
- * smp    Reboot by executing reset on BSP or other CPU
- * triple Force a triple fault (init)
- * kbd    Use the keyboard controller. cold reset (default)
- * acpi   Use the RESET_REG in the FADT
- * efi    Use efi reset_system runtime service
- * pci    Use the so-called "PCI reset register", CF9
- * force  Avoid anything that could hang.
- */
-static int __init reboot_setup(char *str)
-{
-	for (;;) {
-		/*
-		 * Having anything passed on the command line via
-		 * reboot= will cause us to disable DMI checking
-		 * below.
-		 */
-		reboot_default = 0;
-
-		switch (*str) {
-		case 'w':
-			reboot_mode = REBOOT_WARM;
-			break;
-
-		case 'c':
-			reboot_mode = REBOOT_COLD;
-			break;
-
-#ifdef CONFIG_SMP
-		case 's':
-			if (isdigit(*(str+1))) {
-				reboot_cpu = (int) (*(str+1) - '0');
-				if (isdigit(*(str+2)))
-					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
-			}
-			/*
-			 * We will leave sorting out the final value
-			 * when we are ready to reboot, since we might not
-			 * have detected BSP APIC ID or smp_num_cpu
-			 */
-			break;
-#endif /* CONFIG_SMP */
-
-		case 'b':
-		case 'a':
-		case 'k':
-		case 't':
-		case 'e':
-		case 'p':
-			reboot_type = *str;
-			break;
-
-		case 'f':
-			reboot_force = 1;
-			break;
-		}
-
-		str = strchr(str, ',');
-		if (str)
-			str++;
-		else
-			break;
-	}
-	return 1;
-}
-
-__setup("reboot=", reboot_setup);
-
-
-/*
  * Reboot options and system auto-detection code provided by
  * Dell Inc. so their systems "just work". :-)
  */
@@ -616,26 +527,10 @@  void native_machine_shutdown(void)
 {
 	/* Stop the cpus and apics */
 #ifdef CONFIG_SMP
-
-	/* The boot cpu is always logical cpu 0 */
-	int reboot_cpu_id = 0;
-
-	/* See if there has been given a command line override */
-	if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
-		cpu_online(reboot_cpu))
-		reboot_cpu_id = reboot_cpu;
-
-	/* Make certain the cpu I'm about to reboot on is online */
-	if (!cpu_online(reboot_cpu_id))
-		reboot_cpu_id = smp_processor_id();
-
-	/* Make certain I only run on the appropriate processor */
-	set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
-
 	/*
-	 * O.K Now that I'm on the appropriate processor, stop all of the
-	 * others. Also disable the local irq to not receive the per-cpu
-	 * timer interrupt which may trigger scheduler's load balance.
+	 * Stop all of the others. Also disable the local irq to
+	 * not receive the per-cpu timer interrupt which may trigger
+	 * scheduler's load balance.
 	 */
 	local_irq_disable();
 	stop_other_cpus();
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 26cf11b..bc77231 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -15,6 +15,23 @@  enum reboot_mode {
 	REBOOT_WARM,
 	REBOOT_GPIO,
 };
+extern enum reboot_mode reboot_mode;
+
+enum reboot_type {
+	BOOT_TRIPLE = 't',
+	BOOT_KBD = 'k',
+	BOOT_BIOS = 'b',
+	BOOT_ACPI = 'a',
+	BOOT_EFI = 'e',
+	BOOT_CF9 = 'p',
+	BOOT_CF9_COND = 'q',
+};
+extern enum reboot_type reboot_type;
+
+extern int reboot_default;
+extern int reboot_cpu;
+extern int reboot_force;
+
 
 extern int register_reboot_notifier(struct notifier_block *);
 extern int unregister_reboot_notifier(struct notifier_block *);
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 0a97794..e0f640b 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -6,6 +6,7 @@ 
 
 #define pr_fmt(fmt)	"reboot: " fmt
 
+#include <linux/ctype.h>
 #include <linux/export.h>
 #include <linux/kexec.h>
 #include <linux/kmod.h>
@@ -87,7 +88,7 @@  EXPORT_SYMBOL(unregister_reboot_notifier);
 static void migrate_to_reboot_cpu(void)
 {
 	/* The boot cpu is always logical cpu 0 */
-	int reboot_cpu = 0;
+	int reboot_cpu = reboot_cpu;
 
 	cpu_hotplug_disable();
 
@@ -343,3 +344,90 @@  int orderly_poweroff(bool force)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(orderly_poweroff);
+
+int reboot_default;
+enum reboot_mode reboot_mode = REBOOT_COLD;
+int reboot_cpu;
+enum reboot_type reboot_type = BOOT_ACPI;
+int reboot_force;
+
+/*
+ * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
+ * warm   Don't set the cold reboot flag
+ * cold   Set the cold reboot flag
+ * bios   Reboot by jumping through the BIOS
+ * smp    Reboot by executing reset on BSP or other CPU
+ * triple Force a triple fault (init)
+ * kbd    Use the keyboard controller. cold reset (default)
+ * acpi   Use the RESET_REG in the FADT
+ * efi    Use efi reset_system runtime service
+ * pci    Use the so-called "PCI reset register", CF9
+ * force  Avoid anything that could hang.
+ */
+static int __init reboot_setup(char *str)
+{
+	for (;;) {
+		/*
+		 * Having anything passed on the command line via
+		 * reboot= will cause us to disable DMI checking
+		 * below.
+		 */
+		reboot_default = 0;
+
+		switch (*str) {
+#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
+		case 'w':
+			reboot_mode = REBOOT_WARM;
+			break;
+
+		case 'c':
+			reboot_mode = REBOOT_COLD;
+			break;
+
+#ifdef CONFIG_SMP
+		case 's':
+			if (isdigit(*(str+1))) {
+				reboot_cpu = (int) (*(str+1) - '0');
+				if (isdigit(*(str+2)))
+					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
+			}
+			/*
+			 * We will leave sorting out the final value
+			 * when we are ready to reboot, since we might not
+			 * have detected BSP APIC ID or smp_num_cpu
+			 */
+			break;
+#endif /* CONFIG_SMP */
+
+#else
+		case 's':
+			reboot_mode = REBOOT_WARM;
+		case 'h':
+			reboot_mode = REBOOT_COLD;
+		case 'g':
+			reboot_mode = REBOOT_GPIO;
+#endif
+
+		case 'b':
+		case 'a':
+		case 'k':
+		case 't':
+		case 'e':
+		case 'p':
+			reboot_type = *str;
+			break;
+
+		case 'f':
+			reboot_force = 1;
+			break;
+		}
+
+		str = strchr(str, ',');
+		if (str)
+			str++;
+		else
+			break;
+	}
+	return 1;
+}
+__setup("reboot=", reboot_setup);