]> err.no Git - linux-2.6/blob - arch/x86/kernel/io_delay.c
x86: provide a DMI based port 0x80 I/O delay override.
[linux-2.6] / arch / x86 / kernel / io_delay.c
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
17 static void standard_io_delay(void)
18 {
19         asm volatile ("outb %%al, %0" : : "N" (IO_DELAY_PORT_STD));
20 }
21
22 static 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  */
36 static void udelay_io_delay(void)
37 {
38         udelay(IO_DELAY_USECS);
39 }
40
41 #ifndef CONFIG_UDELAY_IO_DELAY
42 static void (*io_delay)(void) = standard_io_delay;
43 #else
44 static void (*io_delay)(void) = udelay_io_delay;
45 #endif
46
47 /*
48  * Paravirt wants native_io_delay to be a constant.
49  */
50 void native_io_delay(void)
51 {
52         io_delay();
53 }
54 EXPORT_SYMBOL(native_io_delay);
55
56 #ifndef CONFIG_UDELAY_IO_DELAY
57 static 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
64 static 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
77 static int __initdata io_delay_override;
78
79 void __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
86 static 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
106 early_param("io_delay", io_delay_param);