aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
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
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')
-rw-r--r--arch/x86/Kconfig.debug79
-rw-r--r--arch/x86/kernel/io_delay.c106
2 files changed, 121 insertions, 64 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 40aba670fb37..77eda46f97b8 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -112,13 +112,78 @@ config IOMMU_LEAK
112 Add a simple leak tracer to the IOMMU code. This is useful when you 112 Add a simple leak tracer to the IOMMU code. This is useful when you
113 are debugging a buggy device driver that leaks IOMMU mappings. 113 are debugging a buggy device driver that leaks IOMMU mappings.
114 114
115config UDELAY_IO_DELAY 115#
116 bool "Delay I/O through udelay instead of outb" 116# IO delay types:
117 depends on DEBUG_KERNEL 117#
118
119config IO_DELAY_TYPE_0X80
120 int
121 default "0"
122
123config IO_DELAY_TYPE_0XED
124 int
125 default "1"
126
127config IO_DELAY_TYPE_UDELAY
128 int
129 default "2"
130
131config IO_DELAY_TYPE_NONE
132 int
133 default "3"
134
135choice
136 prompt "IO delay type"
137 default IO_DELAY_0X80
138
139config IO_DELAY_0X80
140 bool "port 0x80 based port-IO delay [recommended]"
141 help
142 This is the traditional Linux IO delay used for in/out_p.
143 It is the most tested hence safest selection here.
144
145config IO_DELAY_0XED
146 bool "port 0xed based port-IO delay"
147 help
148 Use port 0xed as the IO delay. This frees up port 0x80 which is
149 often used as a hardware-debug port.
150
151config IO_DELAY_UDELAY
152 bool "udelay based port-IO delay"
153 help
154 Use udelay(2) as the IO delay method. This provides the delay
155 while not having any side-effect on the IO port space.
156
157config IO_DELAY_NONE
158 bool "no port-IO delay"
118 help 159 help
119 Make inb_p/outb_p use udelay() based delays by default. Please note 160 No port-IO delay. Will break on old boxes that require port-IO
120 that udelay() does not have the same bus-level side-effects that 161 delay for certain operations. Should work on most new machines.
121 the normal outb based delay does meaning this could cause drivers 162
122 to change behaviour and/or bugs to surface. 163endchoice
164
165if IO_DELAY_0X80
166config DEFAULT_IO_DELAY_TYPE
167 int
168 default IO_DELAY_TYPE_0X80
169endif
170
171if IO_DELAY_0XED
172config DEFAULT_IO_DELAY_TYPE
173 int
174 default IO_DELAY_TYPE_0XED
175endif
176
177if IO_DELAY_UDELAY
178config DEFAULT_IO_DELAY_TYPE
179 int
180 default IO_DELAY_TYPE_UDELAY
181endif
182
183if IO_DELAY_NONE
184config DEFAULT_IO_DELAY_TYPE
185 int
186 default IO_DELAY_TYPE_NONE
187endif
123 188
124endmenu 189endmenu
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
index 4d955e74b974..f052e34dc94c 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