Commit | Line | Data |
---|---|---|
b02aae9c RH |
1 | /* |
2 | * I/O delay strategies for inb_p/outb_p | |
6e7c4025 IM |
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. | |
b02aae9c RH |
7 | */ |
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
b02aae9c | 10 | #include <linux/delay.h> |
d53a4444 | 11 | #include <linux/init.h> |
b02aae9c | 12 | #include <linux/dmi.h> |
d53a4444 | 13 | #include <linux/io.h> |
b02aae9c | 14 | |
6e7c4025 | 15 | int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE; |
b02aae9c | 16 | |
6e7c4025 | 17 | static int __initdata io_delay_override; |
b02aae9c RH |
18 | |
19 | /* | |
20 | * Paravirt wants native_io_delay to be a constant. | |
21 | */ | |
22 | void native_io_delay(void) | |
23 | { | |
6e7c4025 IM |
24 | switch (io_delay_type) { |
25 | default: | |
26 | case CONFIG_IO_DELAY_TYPE_0X80: | |
27 | asm volatile ("outb %al, $0x80"); | |
28 | break; | |
29 | case CONFIG_IO_DELAY_TYPE_0XED: | |
30 | asm volatile ("outb %al, $0xed"); | |
31 | break; | |
32 | case CONFIG_IO_DELAY_TYPE_UDELAY: | |
33 | /* | |
34 | * 2 usecs is an upper-bound for the outb delay but | |
35 | * note that udelay doesn't have the bus-level | |
36 | * side-effects that outb does, nor does udelay() have | |
37 | * precise timings during very early bootup (the delays | |
38 | * are shorter until calibrated): | |
39 | */ | |
40 | udelay(2); | |
41 | case CONFIG_IO_DELAY_TYPE_NONE: | |
42 | break; | |
43 | } | |
b02aae9c RH |
44 | } |
45 | EXPORT_SYMBOL(native_io_delay); | |
46 | ||
6e7c4025 | 47 | static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id) |
b02aae9c | 48 | { |
6e7c4025 | 49 | if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) { |
d53a4444 | 50 | pr_notice("%s: using 0xed I/O delay port\n", id->ident); |
6e7c4025 IM |
51 | io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; |
52 | } | |
53 | ||
b02aae9c RH |
54 | return 0; |
55 | } | |
56 | ||
6e7c4025 IM |
57 | /* |
58 | * Quirk table for systems that misbehave (lock up, etc.) if port | |
59 | * 0x80 is used: | |
60 | */ | |
61 | static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = { | |
f9fc5891 IM |
62 | { |
63 | .callback = dmi_io_delay_0xed_port, | |
64 | .ident = "Compaq Presario V6000", | |
65 | .matches = { | |
d53a4444 JSR |
66 | DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), |
67 | DMI_MATCH(DMI_BOARD_NAME, "30B7") | |
f9fc5891 IM |
68 | } |
69 | }, | |
b02aae9c | 70 | { |
6e7c4025 | 71 | .callback = dmi_io_delay_0xed_port, |
b02aae9c RH |
72 | .ident = "HP Pavilion dv9000z", |
73 | .matches = { | |
d53a4444 JSR |
74 | DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), |
75 | DMI_MATCH(DMI_BOARD_NAME, "30B9") | |
b02aae9c RH |
76 | } |
77 | }, | |
3c274c29 IM |
78 | { |
79 | .callback = dmi_io_delay_0xed_port, | |
80 | .ident = "HP Pavilion dv6000", | |
81 | .matches = { | |
d53a4444 JSR |
82 | DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), |
83 | DMI_MATCH(DMI_BOARD_NAME, "30B8") | |
3c274c29 IM |
84 | } |
85 | }, | |
f9fc5891 IM |
86 | { |
87 | .callback = dmi_io_delay_0xed_port, | |
88 | .ident = "HP Pavilion tx1000", | |
89 | .matches = { | |
d53a4444 JSR |
90 | DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), |
91 | DMI_MATCH(DMI_BOARD_NAME, "30BF") | |
f9fc5891 IM |
92 | } |
93 | }, | |
e6a5652f CE |
94 | { |
95 | .callback = dmi_io_delay_0xed_port, | |
96 | .ident = "Presario F700", | |
97 | .matches = { | |
d53a4444 JSR |
98 | DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), |
99 | DMI_MATCH(DMI_BOARD_NAME, "30D3") | |
e6a5652f CE |
100 | } |
101 | }, | |
6e7c4025 | 102 | { } |
b02aae9c RH |
103 | }; |
104 | ||
b02aae9c RH |
105 | void __init io_delay_init(void) |
106 | { | |
107 | if (!io_delay_override) | |
6e7c4025 | 108 | dmi_check_system(io_delay_0xed_port_dmi_table); |
b02aae9c | 109 | } |
b02aae9c RH |
110 | |
111 | static int __init io_delay_param(char *s) | |
112 | { | |
d6cd7eff CG |
113 | if (!s) |
114 | return -EINVAL; | |
115 | ||
6e7c4025 IM |
116 | if (!strcmp(s, "0x80")) |
117 | io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; | |
118 | else if (!strcmp(s, "0xed")) | |
119 | io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; | |
b02aae9c | 120 | else if (!strcmp(s, "udelay")) |
6e7c4025 IM |
121 | io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY; |
122 | else if (!strcmp(s, "none")) | |
123 | io_delay_type = CONFIG_IO_DELAY_TYPE_NONE; | |
b02aae9c RH |
124 | else |
125 | return -EINVAL; | |
126 | ||
b02aae9c | 127 | io_delay_override = 1; |
b02aae9c RH |
128 | return 0; |
129 | } | |
130 | ||
131 | early_param("io_delay", io_delay_param); |