1 /* 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. 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 15 int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE; 16 EXPORT_SYMBOL_GPL(io_delay_type); 17 18 static int __initdata io_delay_override; 19 20 /* 21 * Paravirt wants native_io_delay to be a constant. 22 */ 23 void native_io_delay(void) 24 { 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 } 45 } 46 EXPORT_SYMBOL(native_io_delay); 47 48 static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id) 49 { 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 56 return 0; 57 } 58 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[] = { 64 { 65 .callback = dmi_io_delay_0xed_port, 66 .ident = "Compaq Presario V6000", 67 .matches = { 68 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 69 DMI_MATCH(DMI_BOARD_NAME, "30B7") 70 } 71 }, 72 { 73 .callback = dmi_io_delay_0xed_port, 74 .ident = "HP Pavilion dv9000z", 75 .matches = { 76 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 77 DMI_MATCH(DMI_BOARD_NAME, "30B9") 78 } 79 }, 80 { 81 .callback = dmi_io_delay_0xed_port, 82 .ident = "HP Pavilion tx1000", 83 .matches = { 84 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 85 DMI_MATCH(DMI_BOARD_NAME, "30BF") 86 } 87 }, 88 { } 89 }; 90 91 void __init io_delay_init(void) 92 { 93 if (!io_delay_override) 94 dmi_check_system(io_delay_0xed_port_dmi_table); 95 } 96 97 static int __init io_delay_param(char *s) 98 { 99 if (!strcmp(s, "0x80")) 100 io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; 101 else if (!strcmp(s, "0xed")) 102 io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; 103 else if (!strcmp(s, "udelay")) 104 io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY; 105 else if (!strcmp(s, "none")) 106 io_delay_type = CONFIG_IO_DELAY_TYPE_NONE; 107 else 108 return -EINVAL; 109 110 io_delay_override = 1; 111 return 0; 112 } 113 114 early_param("io_delay", io_delay_param); 115