aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/io_delay.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/io_delay.c')
-rw-r--r--arch/x86/kernel/io_delay.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 000000000000..4d955e74b974
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,106 @@
1/*
2 * I/O delay strategies for inb_p/outb_p
3 */
4#include <linux/kernel.h>
5#include <linux/module.h>
6#include <linux/init.h>
7#include <linux/delay.h>
8#include <linux/dmi.h>
9#include <asm/io.h>
10
11/*
12 * Allow for a DMI based override of port 0x80 needed for certain HP laptops
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
41#ifndef CONFIG_UDELAY_IO_DELAY
42static void (*io_delay)(void) = standard_io_delay;
43#else
44static void (*io_delay)(void) = udelay_io_delay;
45#endif
46
47/*
48 * Paravirt wants native_io_delay to be a constant.
49 */
50void native_io_delay(void)
51{
52 io_delay();
53}
54EXPORT_SYMBOL(native_io_delay);
55
56#ifndef CONFIG_UDELAY_IO_DELAY
57static int __init dmi_alternate_io_delay_port(const struct dmi_system_id *id)
58{
59 printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident);
60 io_delay = alternate_io_delay;
61 return 0;
62}
63
64static struct dmi_system_id __initdata alternate_io_delay_port_dmi_table[] = {
65 {
66 .callback = dmi_alternate_io_delay_port,
67 .ident = "HP Pavilion dv9000z",
68 .matches = {
69 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
70 DMI_MATCH(DMI_BOARD_NAME, "30B9")
71 }
72 },
73 {
74 }
75};
76
77static int __initdata io_delay_override;
78
79void __init io_delay_init(void)
80{
81 if (!io_delay_override)
82 dmi_check_system(alternate_io_delay_port_dmi_table);
83}
84#endif
85
86static int __init io_delay_param(char *s)
87{
88 if (!s)
89 return -EINVAL;
90
91 if (!strcmp(s, "standard"))
92 io_delay = standard_io_delay;
93 else if (!strcmp(s, "alternate"))
94 io_delay = alternate_io_delay;
95 else if (!strcmp(s, "udelay"))
96 io_delay = udelay_io_delay;
97 else
98 return -EINVAL;
99
100#ifndef CONFIG_UDELAY_IO_DELAY
101 io_delay_override = 1;
102#endif
103 return 0;
104}
105
106early_param("io_delay", io_delay_param);