Commit 6e7c4025 authored by Ingo Molnar's avatar Ingo Molnar

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: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatar"David P. Reed" <dpreed@reed.com>
parent b02aae9c
...@@ -795,12 +795,14 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -795,12 +795,14 @@ and is between 256 and 4096 characters. It is defined in the file
then look in the higher range. then look in the higher range.
io_delay= [X86-32,X86-64] I/O delay method io_delay= [X86-32,X86-64] I/O delay method
standard 0x80
Standard port 0x80 delay Standard port 0x80 based delay
alternate 0xed
Alternate port 0xed delay Alternate port 0xed based delay (needed on some systems)
udelay udelay
Simple two microsecond delay Simple two microseconds delay
none
No delay
io7= [HW] IO7 for Marvel based alpha systems io7= [HW] IO7 for Marvel based alpha systems
See comment before marvel_specify_io7 in See comment before marvel_specify_io7 in
......
...@@ -112,13 +112,78 @@ config IOMMU_LEAK ...@@ -112,13 +112,78 @@ config IOMMU_LEAK
Add a simple leak tracer to the IOMMU code. This is useful when you Add a simple leak tracer to the IOMMU code. This is useful when you
are debugging a buggy device driver that leaks IOMMU mappings. are debugging a buggy device driver that leaks IOMMU mappings.
config UDELAY_IO_DELAY #
bool "Delay I/O through udelay instead of outb" # IO delay types:
depends on DEBUG_KERNEL #
config IO_DELAY_TYPE_0X80
int
default "0"
config IO_DELAY_TYPE_0XED
int
default "1"
config IO_DELAY_TYPE_UDELAY
int
default "2"
config IO_DELAY_TYPE_NONE
int
default "3"
choice
prompt "IO delay type"
default IO_DELAY_0X80
config IO_DELAY_0X80
bool "port 0x80 based port-IO delay [recommended]"
help
This is the traditional Linux IO delay used for in/out_p.
It is the most tested hence safest selection here.
config IO_DELAY_0XED
bool "port 0xed based port-IO delay"
help
Use port 0xed as the IO delay. This frees up port 0x80 which is
often used as a hardware-debug port.
config IO_DELAY_UDELAY
bool "udelay based port-IO delay"
help
Use udelay(2) as the IO delay method. This provides the delay
while not having any side-effect on the IO port space.
config IO_DELAY_NONE
bool "no port-IO delay"
help help
Make inb_p/outb_p use udelay() based delays by default. Please note No port-IO delay. Will break on old boxes that require port-IO
that udelay() does not have the same bus-level side-effects that delay for certain operations. Should work on most new machines.
the normal outb based delay does meaning this could cause drivers
to change behaviour and/or bugs to surface. endchoice
if IO_DELAY_0X80
config DEFAULT_IO_DELAY_TYPE
int
default IO_DELAY_TYPE_0X80
endif
if IO_DELAY_0XED
config DEFAULT_IO_DELAY_TYPE
int
default IO_DELAY_TYPE_0XED
endif
if IO_DELAY_UDELAY
config DEFAULT_IO_DELAY_TYPE
int
default IO_DELAY_TYPE_UDELAY
endif
if IO_DELAY_NONE
config DEFAULT_IO_DELAY_TYPE
int
default IO_DELAY_TYPE_NONE
endif
endmenu endmenu
/* /*
* I/O delay strategies for inb_p/outb_p * 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/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -8,98 +12,86 @@ ...@@ -8,98 +12,86 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <asm/io.h> #include <asm/io.h>
/* int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
* Allow for a DMI based override of port 0x80 needed for certain HP laptops EXPORT_SYMBOL_GPL(io_delay_type);
*/
#define IO_DELAY_PORT_STD 0x80
#define IO_DELAY_PORT_ALT 0xed
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 int __initdata io_delay_override;
static void (*io_delay)(void) = standard_io_delay;
#else
static void (*io_delay)(void) = udelay_io_delay;
#endif
/* /*
* Paravirt wants native_io_delay to be a constant. * Paravirt wants native_io_delay to be a constant.
*/ */
void native_io_delay(void) 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); EXPORT_SYMBOL(native_io_delay);
#ifndef CONFIG_UDELAY_IO_DELAY static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id)
static int __init dmi_alternate_io_delay_port(const struct dmi_system_id *id)
{ {
printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident); if (io_delay_type == CONFIG_IO_DELAY_TYPE_0X80) {
io_delay = alternate_io_delay; printk(KERN_NOTICE "%s: using 0xed I/O delay port\n",
id->ident);
io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
}
return 0; 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", .ident = "HP Pavilion dv9000z",
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"), DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
DMI_MATCH(DMI_BOARD_NAME, "30B9") DMI_MATCH(DMI_BOARD_NAME, "30B9")
} }
}, },
{ { }
}
}; };
static int __initdata io_delay_override;
void __init io_delay_init(void) void __init io_delay_init(void)
{ {
if (!io_delay_override) 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) static int __init io_delay_param(char *s)
{ {
if (!s) if (!strcmp(s, "0x80"))
return -EINVAL; io_delay_type = CONFIG_IO_DELAY_TYPE_0X80;
else if (!strcmp(s, "0xed"))
if (!strcmp(s, "standard")) io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
io_delay = standard_io_delay;
else if (!strcmp(s, "alternate"))
io_delay = alternate_io_delay;
else if (!strcmp(s, "udelay")) 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 else
return -EINVAL; return -EINVAL;
#ifndef CONFIG_UDELAY_IO_DELAY
io_delay_override = 1; io_delay_override = 1;
#endif
return 0; return 0;
} }
......
...@@ -250,15 +250,11 @@ static inline void flush_write_buffers(void) ...@@ -250,15 +250,11 @@ static inline void flush_write_buffers(void)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#ifndef CONFIG_UDELAY_IO_DELAY
extern void io_delay_init(void);
#else
static inline void io_delay_init(void)
{
}
#endif
extern void native_io_delay(void); extern void native_io_delay(void);
extern int io_delay_type;
extern void io_delay_init(void);
#if defined(CONFIG_PARAVIRT) #if defined(CONFIG_PARAVIRT)
#include <asm/paravirt.h> #include <asm/paravirt.h>
#else #else
......
...@@ -35,15 +35,11 @@ ...@@ -35,15 +35,11 @@
* - Arnaldo Carvalho de Melo <acme@conectiva.com.br> * - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*/ */
#ifndef CONFIG_UDELAY_IO_DELAY
extern void io_delay_init(void);
#else
static inline void io_delay_init(void)
{
}
#endif
extern void native_io_delay(void); extern void native_io_delay(void);
extern int io_delay_type;
extern void io_delay_init(void);
static inline void slow_down_io(void) static inline void slow_down_io(void)
{ {
native_io_delay(); native_io_delay();
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#ifdef CONFIG_X86 #ifdef CONFIG_X86
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
#include <asm/io.h>
#endif #endif
static int deprecated_sysctl_warning(struct __sysctl_args *args); static int deprecated_sysctl_warning(struct __sysctl_args *args);
...@@ -727,6 +728,14 @@ static struct ctl_table kern_table[] = { ...@@ -727,6 +728,14 @@ static struct ctl_table kern_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .proc_handler = &proc_dointvec,
}, },
{
.ctl_name = CTL_UNNUMBERED,
.procname = "io_delay_type",
.data = &io_delay_type,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
#endif #endif
#if defined(CONFIG_MMU) #if defined(CONFIG_MMU)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment