aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/io_delay.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-01-30 07:30:05 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:30:05 -0500
commit6e7c402590b75b6b45138792445ee0f0315a8473 (patch)
tree94db814d496502932ab55acc560a728925f87540 /arch/x86/kernel/io_delay.c
parentb02aae9cf52956dfe1bec73f77f81a3d05d3902b (diff)
x86: various changes and cleanups to in_p/out_p delay details
various changes to the in_p/out_p delay details: - add the io_delay=none method - make each method selectable from the kernel config - simplify the delay code a bit by getting rid of an indirect function call - add the /proc/sys/kernel/io_delay_type sysctl - change 'io_delay=standard|alternate' to io_delay=0x80 and io_delay=0xed - make the io delay config not depend on CONFIG_DEBUG_KERNEL Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: "David P. Reed" <dpreed@reed.com>
Diffstat (limited to 'arch/x86/kernel/io_delay.c')
-rw-r--r--arch/x86/kernel/io_delay.c106
1 files changed, 49 insertions, 57 deletions
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
index 4d955e74b97..f052e34dc94 100644
--- a/arch/x86/kernel/io_delay.c
+++ b/arch/x86/kernel/io_delay.c
@@ -1,5 +1,9 @@
1/* 1/*
2 * I/O delay strategies for inb_p/outb_p 2 * I/O delay strategies for inb_p/outb_p
3 *
4 * Allow for a DMI based override of port 0x80, needed for certain HP laptops
5 * and possibly other systems. Also allow for the gradual elimination of
6 * outb_p/inb_p API uses.
3 */ 7 */
4#include <linux/kernel.h> 8#include <linux/kernel.h>
5#include <linux/module.h> 9#include <linux/module.h>
@@ -8,98 +12,86 @@
8#include <linux/dmi.h> 12#include <linux/dmi.h>
9#include <asm/io.h> 13#include <asm/io.h>
10 14
11/* 15int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
12 * Allow for a DMI based override of port 0x80 needed for certain HP laptops 16EXPORT_SYMBOL_GPL(io_delay_type);
13 */
14#define IO_DELAY_PORT_STD 0x80
15#define IO_DELAY_PORT_ALT 0xed
16
17static void standard_io_delay(void)
18{
19 asm volatile ("outb %%al, %0" : : "N" (IO_DELAY_PORT_STD));
20}
21
22static void alternate_io_delay(void)
23{
24 asm volatile ("outb %%al, %0" : : "N" (IO_DELAY_PORT_ALT));
25}
26
27/*
28 * 2 usecs is an upper-bound for the outb delay but note that udelay doesn't
29 * have the bus-level side-effects that outb does
30 */
31#define IO_DELAY_USECS 2
32
33/*
34 * High on a hill was a lonely goatherd
35 */
36static void udelay_io_delay(void)
37{
38 udelay(IO_DELAY_USECS);
39}
40 17
41#ifndef CONFIG_UDELAY_IO_DELAY 18static int __initdata io_delay_override;
42static void (*io_delay)(void) = standard_io_delay;
43#else
44static void (*io_delay)(void) = udelay_io_delay;
45#endif
46 19
47/* 20/*
48 * Paravirt wants native_io_delay to be a constant. 21 * Paravirt wants native_io_delay to be a constant.
49 */ 22 */
50void native_io_delay(void) 23void native_io_delay(void)
51{ 24{
52 io_delay(); 25 switch (io_delay_type) {
26 default:
27 case CONFIG_IO_DELAY_TYPE_0X80:
28 asm volatile ("outb %al, $0x80");
29 break;
30 case CONFIG_IO_DELAY_TYPE_0XED:
31 asm volatile ("outb %al, $0xed");
32 break;
33 case CONFIG_IO_DELAY_TYPE_UDELAY:
34 /*
35 * 2 usecs is an upper-bound for the outb delay but
36 * note that udelay doesn't have the bus-level
37 * side-effects that outb does, nor does udelay() have
38 * precise timings during very early bootup (the delays
39 * are shorter until calibrated):
40 */
41 udelay(2);
42 case CONFIG_IO_DELAY_TYPE_NONE:
43 break;
44 }
53} 45}
54EXPORT_SYMBOL(native_io_delay); 46EXPORT_SYMBOL(native_io_delay);
55 47
56#ifndef CONFIG_UDELAY_IO_DELAY 48static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id)
57static int __init dmi_alternate_io_delay_port(const struct dmi_system_id *id)
58{ 49{
59 printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident); 50 if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) {
60 io_delay = alternate_io_delay; 51 printk(KERN_NOTICE "%s: using 0xed I/O delay port\n",
52 id->ident);
53 io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
54 }
55
61 return 0; 56 return 0;
62} 57}
63 58
64static struct dmi_system_id __initdata alternate_io_delay_port_dmi_table[] = { 59/*
60 * Quirk table for systems that misbehave (lock up, etc.) if port
61 * 0x80 is used:
62 */
63static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = {
65 { 64 {
66 .callback = dmi_alternate_io_delay_port, 65 .callback = dmi_io_delay_0xed_port,
67 .ident = "HP Pavilion dv9000z", 66 .ident = "HP Pavilion dv9000z",
68 .matches = { 67 .matches = {
69 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 68 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
70 DMI_MATCH(DMI_BOARD_NAME, "30B9") 69 DMI_MATCH(DMI_BOARD_NAME, "30B9")
71 } 70 }
72 }, 71 },
73 { 72 { }
74 }
75}; 73};
76 74
77static int __initdata io_delay_override;
78
79void __init io_delay_init(void) 75void __init io_delay_init(void)
80{ 76{
81 if (!io_delay_override) 77 if (!io_delay_override)
82 dmi_check_system(alternate_io_delay_port_dmi_table); 78 dmi_check_system(io_delay_0xed_port_dmi_table);
83} 79}
84#endif
85 80
86static int __init io_delay_param(char *s) 81static int __init io_delay_param(char *s)
87{ 82{
88 if (!s) 83 if (!strcmp(s, "0x80"))
89 return -EINVAL; 84 io_delay_type = CONFIG_IO_DELAY_TYPE_0X80;
90 85 else if (!strcmp(s, "0xed"))
91 if (!strcmp(s, "standard")) 86 io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
92 io_delay = standard_io_delay;
93 else if (!strcmp(s, "alternate"))
94 io_delay = alternate_io_delay;
95 else if (!strcmp(s, "udelay")) 87 else if (!strcmp(s, "udelay"))
96 io_delay = udelay_io_delay; 88 io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY;
89 else if (!strcmp(s, "none"))
90 io_delay_type = CONFIG_IO_DELAY_TYPE_NONE;
97 else 91 else
98 return -EINVAL; 92 return -EINVAL;
99 93
100#ifndef CONFIG_UDELAY_IO_DELAY
101 io_delay_override = 1; 94 io_delay_override = 1;
102#endif
103 return 0; 95 return 0;
104} 96}
105 97