Commit 06ba030a authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] APM fixes, 2.5.29

the attached patch fixes two things:

 - a TLS related bug noticed by Arjan van de Ven: apm_init() should set up
   all CPU's gdt entries - just in case some code happens to call in the
   APM BIOS on the wrong CPU. This should also handle the case when some
   APM code gets triggered (by suspend or power button or something).

 - compilation problem
parent ab12b34b
...@@ -1589,7 +1589,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) ...@@ -1589,7 +1589,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
p = buf; p = buf;
if ((num_possible_cpus() == 1) && if ((num_online_cpus() == 1) &&
!(error = apm_get_power_status(&bx, &cx, &dx))) { !(error = apm_get_power_status(&bx, &cx, &dx))) {
ac_line_status = (bx >> 8) & 0xff; ac_line_status = (bx >> 8) & 0xff;
battery_status = bx & 0xff; battery_status = bx & 0xff;
...@@ -1720,7 +1720,7 @@ static int apm(void *unused) ...@@ -1720,7 +1720,7 @@ static int apm(void *unused)
} }
} }
if (debug && (num_possible_cpus() == 1)) { if (debug && (num_online_cpus() == 1)) {
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");
...@@ -1764,7 +1764,7 @@ static int apm(void *unused) ...@@ -1764,7 +1764,7 @@ static int apm(void *unused)
pm_power_off = apm_power_off; pm_power_off = apm_power_off;
register_sysrq_key('o', &sysrq_poweroff_op); register_sysrq_key('o', &sysrq_poweroff_op);
if (num_possible_cpus() == 1) { if (num_online_cpus() == 1) {
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
console_blank_hook = apm_console_blank; console_blank_hook = apm_console_blank;
#endif #endif
...@@ -1853,6 +1853,7 @@ static struct miscdevice apm_device = { ...@@ -1853,6 +1853,7 @@ static struct miscdevice apm_device = {
static int __init apm_init(void) static int __init apm_init(void)
{ {
struct proc_dir_entry *apm_proc; struct proc_dir_entry *apm_proc;
int i;
if (apm_info.bios.version == 0) { if (apm_info.bios.version == 0) {
printk(KERN_INFO "apm: BIOS not found.\n"); printk(KERN_INFO "apm: BIOS not found.\n");
...@@ -1907,7 +1908,7 @@ static int __init apm_init(void) ...@@ -1907,7 +1908,7 @@ static int __init apm_init(void)
printk(KERN_NOTICE "apm: disabled on user request.\n"); printk(KERN_NOTICE "apm: disabled on user request.\n");
return -ENODEV; return -ENODEV;
} }
if ((num_possible_cpus() > 1) && !power_off) { if ((num_online_cpus() > 1) && !power_off) {
printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
return -ENODEV; return -ENODEV;
} }
...@@ -1926,37 +1927,39 @@ static int __init apm_init(void) ...@@ -1926,37 +1927,39 @@ static int __init apm_init(void)
* NOTE: on SMP we call into the APM BIOS only on CPU#0, so it's * NOTE: on SMP we call into the APM BIOS only on CPU#0, so it's
* enough to modify CPU#0's GDT. * enough to modify CPU#0's GDT.
*/ */
set_base(cpu_gdt_table[0][APM_40 >> 3], for (i = 0; i < NR_CPUS; i++) {
set_base(cpu_gdt_table[i][APM_40 >> 3],
__va((unsigned long)0x40 << 4)); __va((unsigned long)0x40 << 4));
_set_limit((char *)&cpu_gdt_table[0][APM_40 >> 3], 4095 - (0x40 << 4)); _set_limit((char *)&cpu_gdt_table[i][APM_40 >> 3], 4095 - (0x40 << 4));
apm_bios_entry.offset = apm_info.bios.offset; apm_bios_entry.offset = apm_info.bios.offset;
apm_bios_entry.segment = APM_CS; apm_bios_entry.segment = APM_CS;
set_base(cpu_gdt_table[0][APM_CS >> 3], set_base(cpu_gdt_table[i][APM_CS >> 3],
__va((unsigned long)apm_info.bios.cseg << 4)); __va((unsigned long)apm_info.bios.cseg << 4));
set_base(cpu_gdt_table[0][APM_CS_16 >> 3], set_base(cpu_gdt_table[i][APM_CS_16 >> 3],
__va((unsigned long)apm_info.bios.cseg_16 << 4)); __va((unsigned long)apm_info.bios.cseg_16 << 4));
set_base(cpu_gdt_table[0][APM_DS >> 3], set_base(cpu_gdt_table[i][APM_DS >> 3],
__va((unsigned long)apm_info.bios.dseg << 4)); __va((unsigned long)apm_info.bios.dseg << 4));
#ifndef APM_RELAX_SEGMENTS #ifndef APM_RELAX_SEGMENTS
if (apm_info.bios.version == 0x100) { if (apm_info.bios.version == 0x100) {
#endif #endif
/* For ASUS motherboard, Award BIOS rev 110 (and others?) */ /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
_set_limit((char *)&cpu_gdt_table[0][APM_CS >> 3], 64 * 1024 - 1); _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 - 1);
/* For some unknown machine. */ /* For some unknown machine. */
_set_limit((char *)&cpu_gdt_table[0][APM_CS_16 >> 3], 64 * 1024 - 1); _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], 64 * 1024 - 1);
/* For the DEC Hinote Ultra CT475 (and others?) */ /* For the DEC Hinote Ultra CT475 (and others?) */
_set_limit((char *)&cpu_gdt_table[0][APM_DS >> 3], 64 * 1024 - 1); _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], 64 * 1024 - 1);
#ifndef APM_RELAX_SEGMENTS #ifndef APM_RELAX_SEGMENTS
} else { } else {
_set_limit((char *)&cpu_gdt_table[0][APM_CS >> 3], _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3],
(apm_info.bios.cseg_len - 1) & 0xffff); (apm_info.bios.cseg_len - 1) & 0xffff);
_set_limit((char *)&cpu_gdt_table[0][APM_CS_16 >> 3], _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3],
(apm_info.bios.cseg_16_len - 1) & 0xffff); (apm_info.bios.cseg_16_len - 1) & 0xffff);
_set_limit((char *)&cpu_gdt_table[0][APM_DS >> 3], _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3],
(apm_info.bios.dseg_len - 1) & 0xffff); (apm_info.bios.dseg_len - 1) & 0xffff);
} }
#endif #endif
}
apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info); apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
if (apm_proc) if (apm_proc)
...@@ -1964,7 +1967,7 @@ static int __init apm_init(void) ...@@ -1964,7 +1967,7 @@ static int __init apm_init(void)
kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
if (num_possible_cpus() > 1) { if (num_online_cpus() > 1) {
printk(KERN_NOTICE printk(KERN_NOTICE
"apm: disabled - APM is not SMP safe (power off active).\n"); "apm: disabled - APM is not SMP safe (power off active).\n");
return 0; return 0;
......
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