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 17 static int __initdata io_delay_override; 18 19 /* 20 * Paravirt wants native_io_delay to be a constant. 21 */ 22 void native_io_delay(void) 23 { 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 } 44 } 45 EXPORT_SYMBOL(native_io_delay); 46 47 static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id) 48 { 49 if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) { 50 printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", 51 id->ident); 52 io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; 53 } 54 55 return 0; 56 } 57 58 /* 59 * Quirk table for systems that misbehave (lock up, etc.) if port 60 * 0x80 is used: 61 */ 62 static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = { 63 { 64 .callback = dmi_io_delay_0xed_port, 65 .ident = "Compaq Presario V6000", 66 .matches = { 67 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 68 DMI_MATCH(DMI_BOARD_NAME, "30B7") 69 } 70 }, 71 { 72 .callback = dmi_io_delay_0xed_port, 73 .ident = "HP Pavilion dv9000z", 74 .matches = { 75 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 76 DMI_MATCH(DMI_BOARD_NAME, "30B9") 77 } 78 }, 79 { 80 .callback = dmi_io_delay_0xed_port, 81 .ident = "HP Pavilion dv6000", 82 .matches = { 83 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 84 DMI_MATCH(DMI_BOARD_NAME, "30B8") 85 } 86 }, 87 { 88 .callback = dmi_io_delay_0xed_port, 89 .ident = "HP Pavilion tx1000", 90 .matches = { 91 DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), 92 DMI_MATCH(DMI_BOARD_NAME, "30BF") 93 } 94 }, 95 { } 96 }; 97 98 void __init io_delay_init(void) 99 { 100 if (!io_delay_override) 101 dmi_check_system(io_delay_0xed_port_dmi_table); 102 } 103 104 static int __init io_delay_param(char *s) 105 { 106 if (!s) 107 return -EINVAL; 108 109 if (!strcmp(s, "0x80")) 110 io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; 111 else if (!strcmp(s, "0xed")) 112 io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; 113 else if (!strcmp(s, "udelay")) 114 io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY; 115 else if (!strcmp(s, "none")) 116 io_delay_type = CONFIG_IO_DELAY_TYPE_NONE; 117 else 118 return -EINVAL; 119 120 io_delay_override = 1; 121 return 0; 122 } 123 124 early_param("io_delay", io_delay_param); 125