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> | |
10 | #include <linux/init.h> | |
11 | #include <linux/delay.h> | |
12 | #include <linux/dmi.h> | |
13 | #include <asm/io.h> | |
14 | ||
6e7c4025 IM |
15 | int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE; |
16 | EXPORT_SYMBOL_GPL(io_delay_type); | |
b02aae9c | 17 | |
6e7c4025 | 18 | static int __initdata io_delay_override; |
b02aae9c RH |
19 | |
20 | /* | |
21 | * Paravirt wants native_io_delay to be a constant. | |
22 | */ | |
23 | void native_io_delay(void) | |
24 | { | |
6e7c4025 IM |
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 | } | |
b02aae9c RH |
45 | } |
46 | EXPORT_SYMBOL(native_io_delay); | |
47 | ||
6e7c4025 | 48 | static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id) |
b02aae9c | 49 | { |
6e7c4025 IM |
50 | if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) { |
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 | ||
b02aae9c RH |
56 | return 0; |
57 | } | |
58 | ||
6e7c4025 IM |
59 | /* |
60 | * Quirk table for systems that misbehave (lock up, etc.) if port | |
61 | * 0x80 is used: | |
62 | */ | |
63 | static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = { | |
b02aae9c | 64 | { |
6e7c4025 | 65 | .callback = dmi_io_delay_0xed_port, |
b02aae9c RH |
66 | .ident = "HP Pavilion dv9000z", |
67 | .matches = { | |
68 | DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), | |
69 | DMI_MATCH(DMI_BOARD_NAME, "30B9") | |
70 | } | |
71 | }, | |
6e7c4025 | 72 | { } |
b02aae9c RH |
73 | }; |
74 | ||
b02aae9c RH |
75 | void __init io_delay_init(void) |
76 | { | |
77 | if (!io_delay_override) | |
6e7c4025 | 78 | dmi_check_system(io_delay_0xed_port_dmi_table); |
b02aae9c | 79 | } |
b02aae9c RH |
80 | |
81 | static int __init io_delay_param(char *s) | |
82 | { | |
6e7c4025 IM |
83 | if (!strcmp(s, "0x80")) |
84 | io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; | |
85 | else if (!strcmp(s, "0xed")) | |
86 | io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; | |
b02aae9c | 87 | else if (!strcmp(s, "udelay")) |
6e7c4025 IM |
88 | io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY; |
89 | else if (!strcmp(s, "none")) | |
90 | io_delay_type = CONFIG_IO_DELAY_TYPE_NONE; | |
b02aae9c RH |
91 | else |
92 | return -EINVAL; | |
93 | ||
b02aae9c | 94 | io_delay_override = 1; |
b02aae9c RH |
95 | return 0; |
96 | } | |
97 | ||
98 | early_param("io_delay", io_delay_param); |