/* * I/O delay strategies for inb_p/outb_p * * Allow for a DMI based override of port 0x80, needed for certain HP laptops * and possibly other systems. Also allow for the gradual elimination of * outb_p/inb_p API uses. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/dmi.h> #include <linux/io.h> int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE; static int __initdata io_delay_override; /* * Paravirt wants native_io_delay to be a constant. */ void native_io_delay(void) { switch (io_delay_type) { default: case CONFIG_IO_DELAY_TYPE_0X80: asm volatile ("outb %al, $0x80"); break; case CONFIG_IO_DELAY_TYPE_0XED: asm volatile ("outb %al, $0xed"); break; case CONFIG_IO_DELAY_TYPE_UDELAY: /* * 2 usecs is an upper-bound for the outb delay but * note that udelay doesn't have the bus-level * side-effects that outb does, nor does udelay() have * precise timings during very early bootup (the delays * are shorter until calibrated): */ udelay(2); case CONFIG_IO_DELAY_TYPE_NONE: break; } } EXPORT_SYMBOL(native_io_delay); static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id) { if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) { pr_notice("%s: using 0xed I/O delay port\n", id->ident); io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; } return 0; } /* * Quirk table for systems that misbehave (lock up, etc.) if port * 0x80 is used: */ static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table[] = { { .callback = dmi_io_delay_0xed_port, .ident = "Compaq Presario V6000", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), DMI_MATCH(DMI_BOARD_NAME, "30B7") } }, { .callback = dmi_io_delay_0xed_port, .ident = "HP Pavilion dv9000z", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), DMI_MATCH(DMI_BOARD_NAME, "30B9") } }, { .callback = dmi_io_delay_0xed_port, .ident = "HP Pavilion dv6000", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), DMI_MATCH(DMI_BOARD_NAME, "30B8") } }, { .callback = dmi_io_delay_0xed_port, .ident = "HP Pavilion tx1000", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), DMI_MATCH(DMI_BOARD_NAME, "30BF") } }, { .callback = dmi_io_delay_0xed_port, .ident = "Presario F700", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), DMI_MATCH(DMI_BOARD_NAME, "30D3") } }, { } }; void __init io_delay_init(void) { if (!io_delay_override) dmi_check_system(io_delay_0xed_port_dmi_table); } static int __init io_delay_param(char *s) { if (!s) return -EINVAL; if (!strcmp(s, "0x80")) io_delay_type = CONFIG_IO_DELAY_TYPE_0X80; else if (!strcmp(s, "0xed")) io_delay_type = CONFIG_IO_DELAY_TYPE_0XED; else if (!strcmp(s, "udelay")) io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY; else if (!strcmp(s, "none")) io_delay_type = CONFIG_IO_DELAY_TYPE_NONE; else return -EINVAL; io_delay_override = 1; return 0; } early_param("io_delay", io_delay_param);