Commit ba8bdc86 authored by Dave Jones's avatar Dave Jones Committed by Linus Torvalds

[PATCH] APM SMP fixes.

From 2.4 with some 2.5 mangling from Robert Love.
parent 94148975
...@@ -571,9 +571,10 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, ...@@ -571,9 +571,10 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
{ {
APM_DECL_SEGS APM_DECL_SEGS
unsigned long flags; unsigned long flags;
int cpu = smp_processor_id(); int cpu;
struct desc_struct save_desc_40; struct desc_struct save_desc_40;
cpu = get_cpu();
save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
...@@ -599,6 +600,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, ...@@ -599,6 +600,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
APM_DO_RESTORE_SEGS; APM_DO_RESTORE_SEGS;
local_irq_restore(flags); local_irq_restore(flags);
cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; cpu_gdt_table[cpu][0x40 / 8] = save_desc_40;
put_cpu();
return *eax & 0xff; return *eax & 0xff;
} }
...@@ -621,9 +623,10 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) ...@@ -621,9 +623,10 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
u8 error; u8 error;
APM_DECL_SEGS APM_DECL_SEGS
unsigned long flags; unsigned long flags;
int cpu = smp_processor_id(); int cpu;
struct desc_struct save_desc_40; struct desc_struct save_desc_40;
cpu = get_cpu();
save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
...@@ -653,6 +656,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) ...@@ -653,6 +656,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
APM_DO_RESTORE_SEGS; APM_DO_RESTORE_SEGS;
local_irq_restore(flags); local_irq_restore(flags);
cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40; cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40;
put_cpu();
return error; return error;
} }
...@@ -864,7 +868,7 @@ static void apm_cpu_idle(void) ...@@ -864,7 +868,7 @@ static void apm_cpu_idle(void)
case 1: apm_idle_done = 1; case 1: apm_idle_done = 1;
break; break;
default: /* BIOS refused */ default: /* BIOS refused */
; break;
} }
} }
if (original_pm_idle) if (original_pm_idle)
...@@ -880,14 +884,6 @@ static void apm_cpu_idle(void) ...@@ -880,14 +884,6 @@ static void apm_cpu_idle(void)
apm_do_busy(); apm_do_busy();
} }
#ifdef CONFIG_SMP
static int apm_magic(void * unused)
{
while (1)
schedule();
}
#endif
/** /**
* apm_power_off - ask the BIOS to power off * apm_power_off - ask the BIOS to power off
* *
...@@ -915,10 +911,11 @@ static void apm_power_off(void) ...@@ -915,10 +911,11 @@ static void apm_power_off(void)
*/ */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Some bioses don't like being called from CPU != 0 */ /* Some bioses don't like being called from CPU != 0 */
while (smp_processor_id() != 0) { if (smp_processor_id() != 0) {
kernel_thread(apm_magic, NULL, current->cpus_allowed = 1;
CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
schedule(); schedule();
if (unlikely(smp_processor_id() != 0))
BUG();
} }
#endif #endif
if (apm_info.realmode_power_off) if (apm_info.realmode_power_off)
...@@ -1688,6 +1685,21 @@ static int apm(void *unused) ...@@ -1688,6 +1685,21 @@ static int apm(void *unused)
current->flags |= PF_IOTHREAD; current->flags |= PF_IOTHREAD;
sigfillset(&current->blocked); sigfillset(&current->blocked);
#ifdef CONFIG_SMP
/* 2002/08/01 - WT
* This is to avoid random crashes at boot time during initialization
* on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
* Some bioses don't like being called from CPU != 0.
* Method suggested by Ingo Molnar.
*/
if (smp_processor_id() != 0) {
current->cpus_allowed = 1;
schedule();
if (unlikely(smp_processor_id() != 0))
BUG();
}
#endif
if (apm_info.connection_version == 0) { if (apm_info.connection_version == 0) {
apm_info.connection_version = apm_info.bios.version; apm_info.connection_version = apm_info.bios.version;
if (apm_info.connection_version > 0x100) { if (apm_info.connection_version > 0x100) {
...@@ -1734,7 +1746,7 @@ static int apm(void *unused) ...@@ -1734,7 +1746,7 @@ static int apm(void *unused)
} }
} }
if (debug && (num_online_cpus() == 1)) { if (debug) {
error = apm_get_power_status(&bx, &cx, &dx); error = apm_get_power_status(&bx, &cx, &dx);
if (error) if (error)
printk(KERN_INFO "apm: power status not available\n"); printk(KERN_INFO "apm: power status not available\n");
...@@ -1937,9 +1949,6 @@ static int __init apm_init(void) ...@@ -1937,9 +1949,6 @@ static int __init apm_init(void)
* that extends up to the end of page zero (that we have reserved). * that extends up to the end of page zero (that we have reserved).
* This is for buggy BIOS's that refer to (real mode) segment 0x40 * This is for buggy BIOS's that refer to (real mode) segment 0x40
* even though they are called in protected mode. * even though they are called in protected mode.
*
* NOTE: on SMP we call into the APM BIOS only on CPU#0, so it's
* enough to modify CPU#0's GDT.
*/ */
set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment