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:
parent
b02aae9cf5
commit
6e7c402590
|
@ -795,12 +795,14 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
then look in the higher range.
|
||||
|
||||
io_delay= [X86-32,X86-64] I/O delay method
|
||||
standard
|
||||
Standard port 0x80 delay
|
||||
alternate
|
||||
Alternate port 0xed delay
|
||||
0x80
|
||||
Standard port 0x80 based delay
|
||||
0xed
|
||||
Alternate port 0xed based delay (needed on some systems)
|
||||
udelay
|
||||
Simple two microsecond delay
|
||||
Simple two microseconds delay
|
||||
none
|
||||
No delay
|
||||
|
||||
io7= [HW] IO7 for Marvel based alpha systems
|
||||
See comment before marvel_specify_io7 in
|
||||
|
|
|
@ -112,13 +112,78 @@ config IOMMU_LEAK
|
|||
Add a simple leak tracer to the IOMMU code. This is useful when you
|
||||
are debugging a buggy device driver that leaks IOMMU mappings.
|
||||
|
||||
config UDELAY_IO_DELAY
|
||||
bool "Delay I/O through udelay instead of outb"
|
||||
depends on DEBUG_KERNEL
|
||||
#
|
||||
# IO delay types:
|
||||
#
|
||||
|
||||
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
|
||||
Make inb_p/outb_p use udelay() based delays by default. Please note
|
||||
that udelay() does not have the same bus-level side-effects that
|
||||
the normal outb based delay does meaning this could cause drivers
|
||||
to change behaviour and/or bugs to surface.
|
||||
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
|
||||
No port-IO delay. Will break on old boxes that require port-IO
|
||||
delay for certain operations. Should work on most new machines.
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -250,15 +250,11 @@ static inline void flush_write_buffers(void)
|
|||
|
||||
#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 int io_delay_type;
|
||||
extern void io_delay_init(void);
|
||||
|
||||
#if defined(CONFIG_PARAVIRT)
|
||||
#include <asm/paravirt.h>
|
||||
#else
|
||||
|
|
|
@ -35,15 +35,11 @@
|
|||
* - 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 int io_delay_type;
|
||||
extern void io_delay_init(void);
|
||||
|
||||
static inline void slow_down_io(void)
|
||||
{
|
||||
native_io_delay();
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#ifdef CONFIG_X86
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/io.h>
|
||||
#endif
|
||||
|
||||
static int deprecated_sysctl_warning(struct __sysctl_args *args);
|
||||
|
@ -727,6 +728,14 @@ static struct ctl_table kern_table[] = {
|
|||
.mode = 0644,
|
||||
.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
|
||||
#if defined(CONFIG_MMU)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue