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

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
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -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
+72 −7
Original line number Diff line number Diff line
@@ -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
	  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
	  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.
	  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
+49 −57
Original line number Diff line number Diff line
/*
 * 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

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);
}
int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
EXPORT_SYMBOL_GPL(io_delay_type);

#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;
}

+3 −7
Original line number Diff line number Diff line
@@ -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
+3 −7
Original line number Diff line number Diff line
@@ -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();
Loading