x86: various changes and cleanups to in_p/out_p delay details

various changes to the in_p/out_p delay details:

- add the io_delay=none method
- make each method selectable from the kernel config
- simplify the delay code a bit by getting rid of an indirect function call
- add the /proc/sys/kernel/io_delay_type sysctl
- change 'io_delay=standard|alternate' to io_delay=0x80 and io_delay=0xed
- make the io delay config not depend on CONFIG_DEBUG_KERNEL

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: "David P. Reed" <dpreed@reed.com>
This commit is contained in:
Ingo Molnar
2008-01-30 13:30:05 +01:00
parent b02aae9cf5
commit 6e7c402590
6 changed files with 143 additions and 83 deletions

View File

@@ -1,5 +1,9 @@
/*
* 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>
@@ -8,98 +12,86 @@
#include <linux/dmi.h>
#include <asm/io.h>
/*
* Allow for a DMI based override of port 0x80 needed for certain HP laptops
*/
#define IO_DELAY_PORT_STD 0x80
#define IO_DELAY_PORT_ALT 0xed
int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
EXPORT_SYMBOL_GPL(io_delay_type);
static void standard_io_delay(void)
{
asm volatile ("outb %%al, %0" : : "N" (IO_DELAY_PORT_STD));
}
static void alternate_io_delay(void)
{
asm volatile ("outb %%al, %0" : : "N" (IO_DELAY_PORT_ALT));
}
/*
* 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
*/
#define IO_DELAY_USECS 2
/*
* High on a hill was a lonely goatherd
*/
static void udelay_io_delay(void)
{
udelay(IO_DELAY_USECS);
}
#ifndef CONFIG_UDELAY_IO_DELAY
static void (*io_delay)(void) = standard_io_delay;
#else
static void (*io_delay)(void) = udelay_io_delay;
#endif
static int __initdata io_delay_override;
/*
* Paravirt wants native_io_delay to be a constant.
*/
void native_io_delay(void)
{
io_delay();
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);
#ifndef CONFIG_UDELAY_IO_DELAY
static int __init dmi_alternate_io_delay_port(const struct dmi_system_id *id)
static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id)
{
printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident);
io_delay = alternate_io_delay;
if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) {
printk(KERN_NOTICE "%s: using 0xed I/O delay port\n",
id->ident);
io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
}
return 0;
}
static struct dmi_system_id __initdata alternate_io_delay_port_dmi_table[] = {
/*
* 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_alternate_io_delay_port,
.callback = dmi_io_delay_0xed_port,
.ident = "HP Pavilion dv9000z",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
DMI_MATCH(DMI_BOARD_NAME, "30B9")
}
},
{
}
{ }
};
static int __initdata io_delay_override;
void __init io_delay_init(void)
{
if (!io_delay_override)
dmi_check_system(alternate_io_delay_port_dmi_table);
dmi_check_system(io_delay_0xed_port_dmi_table);
}
#endif
static int __init io_delay_param(char *s)
{
if (!s)
return -EINVAL;
if (!strcmp(s, "standard"))
io_delay = standard_io_delay;
else if (!strcmp(s, "alternate"))
io_delay = alternate_io_delay;
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 = udelay_io_delay;
io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY;
else if (!strcmp(s, "none"))
io_delay_type = CONFIG_IO_DELAY_TYPE_NONE;
else
return -EINVAL;
#ifndef CONFIG_UDELAY_IO_DELAY
io_delay_override = 1;
#endif
return 0;
}