linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] x86: provide a DMI based port 0x80 I/O delay override
@ 2007-12-30  3:34 Rene Herman
  2007-12-30  9:30 ` Linus Torvalds
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-30  3:34 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: dpreed, Islam Amer, Alan Cox, hpa, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel

[-- Attachment #1: Type: text/plain, Size: 1676 bytes --]

Hi Linus.

[ resend, forgot the CC to linux-kernel. sorry ]

This fixes "hwclock" triggered boottime hangs for a few HP/Compaq laptops
and might as such be applicable to 2.6.24 still.

The kernel's use of an outb to port 0x80 as an I/O delay disagrees with
these machines (after ACPI is live, that is) and this provides for a DMI
based switch to alternate port 0xed for them.

Complete changelog inside the patch.

An evolved version of this patch that also supplies udelay(2) and <nothing>
as I/O delay lives in the x86.git tree as well but Alan Cox suggested those
choices shouldn't yet be provided as he's finding races in drivers on SMP
without the bus-locking outb.

As a minimal version I thought you might perhaps want to take this as a
specific fix for the afflicted laptops for 2.6.24. H. Peter Anvin earlier
agreed it would be minimal enough for that.

It was tested on both of the afflicted machines the DMI strings cover and
doesn't change anything on others by default. It also introduces a bootparam
io_delay=<standard|alternate> to make (or override) the choice manually.

   Documentation/kernel-parameters.txt |    6 ++
   arch/x86/boot/compressed/misc_32.c  |    8 +--
   arch/x86/boot/compressed/misc_64.c  |    8 +--
   arch/x86/kernel/Makefile_32         |    2
   arch/x86/kernel/Makefile_64         |    2
   arch/x86/kernel/io_delay.c          |   77
++++++++++++++++++++++++++++++++++++
   arch/x86/kernel/setup_32.c          |    2
   arch/x86/kernel/setup_64.c          |    2
   include/asm-x86/io_32.h             |    6 --
   include/asm-x86/io_64.h             |   27 +++++++-----
   10 files changed, 115 insertions(+), 25 deletions(-)

Rene.


[-- Attachment #2: dmi-port80-minimal-bootparam.diff --]
[-- Type: text/plain, Size: 11204 bytes --]

commit b2a10c0b8e6c1c73b940e60fae4cbe9db9ca9e3b
Author: Rene Herman <rene.herman@gmail.com>
Date:   Mon Dec 17 21:23:55 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP/Compaq) laptops experience trouble from our port 0x80
    I/O delay writes. This patch provides for a DMI based switch to the
    "alternate diagnostic port" 0xed (as used by some BIOSes as well)
    for these.
    
    David P. Reed confirmed that using port 0xed works and provides a
    proper delay on his HP Pavilion dv9000z, Islam Amer comfirmed that
    it does so on a Compaq Presario V6000. Both are Quanta boards, type
    30B9 and 30B7 respectively and are the (only) machines for which
    the DMI based switch triggers. HP Pavilion dv6000z is expected to
    also need this but its DMI info hasn't been verified yet.
    
    The symptoms of _not_ working are a hanging machine, with "hwclock"
    use being a direct trigger and therefore the bootup often hanging
    already on these machines.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist, but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but still leaves:
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally various drivers are racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    An early boot parameter to make the choice manually (and override any
    possible DMI based decision) is also provided:
    
    	io_delay=standard|alternate
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as tested by David P. Reed. He moreover reported that booting with
    "acpi=off" also fixed things and seeing as how ACPI isn't touched
    until after this DMI based I/O port switch leaving the ones in the
    boot code be is safe.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>
    Tested-by: David P. Reed <dpreed@reed.com>
    Tested-by: Islam Amer <pharon@gmail.com>

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 33121d6..6948e25 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -785,6 +785,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			for translation below 32 bit and if not available
 			then look in the higher range.
 
+	io_delay=	[X86-32,X86-64] I/O delay port
+		standard
+			Use the 0x80 standard I/O delay port (default)
+		alternate
+			Use the 0xed alternate I/O delay port
+
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..77a8bcd
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,77 @@
+/*
+ * I/O delay strategies for inb_p/outb_p
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+/*
+ * Allow for a DMI based override of port 0x80
+ */
+#define IO_DELAY_PORT_STD 0x80
+#define IO_DELAY_PORT_ALT 0xed
+
+static unsigned short io_delay_port __read_mostly = IO_DELAY_PORT_STD;
+
+void native_io_delay(void)
+{
+	asm volatile ("outb %%al, %w0" : : "d" (io_delay_port));
+}
+EXPORT_SYMBOL(native_io_delay);
+
+static int __init dmi_io_delay_port_alt(const struct dmi_system_id *id)
+{
+	printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident);
+	io_delay_port = IO_DELAY_PORT_ALT;
+	return 0;
+}
+
+static struct dmi_system_id __initdata dmi_io_delay_port_alt_table[] = {
+	{
+		.callback	= dmi_io_delay_port_alt,
+		.ident		= "Compaq Presario V6000",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B7")
+		}
+	},
+	{
+		.callback	= dmi_io_delay_port_alt,
+		.ident		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{
+	}
+};
+
+static int __initdata io_delay_override;
+
+static int __init io_delay_param(char *s)
+{
+	if (!s)
+		return -EINVAL;
+
+	if (!strcmp(s, "standard"))
+		io_delay_port = IO_DELAY_PORT_STD;
+	else if (!strcmp(s, "alternate"))
+		io_delay_port = IO_DELAY_PORT_ALT;
+	else
+		return -EINVAL;
+
+	io_delay_override = 1;
+	return 0;
+}
+
+early_param("io_delay", io_delay_param);
+
+void __init io_delay_init(void)
+{
+	if (!io_delay_override)
+		dmi_check_system(dmi_io_delay_port_alt_table);
+}
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..690b8f4 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..b2d4994 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,18 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
+static inline void slow_down_io(void)
+{
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +55,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \


^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30  3:34 [PATCH] x86: provide a DMI based port 0x80 I/O delay override Rene Herman
@ 2007-12-30  9:30 ` Linus Torvalds
  2007-12-30 12:48   ` Andi Kleen
                     ` (3 more replies)
  0 siblings, 4 replies; 186+ messages in thread
From: Linus Torvalds @ 2007-12-30  9:30 UTC (permalink / raw)
  To: Rene Herman
  Cc: dpreed, Islam Amer, Alan Cox, hpa, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel



On Sun, 30 Dec 2007, Rene Herman wrote:
> 
> This fixes "hwclock" triggered boottime hangs for a few HP/Compaq laptops
> and might as such be applicable to 2.6.24 still.

It's not a regression as far as I can see (ie we've always done that port 
80 access for slow-down), and quite frankly, I think the code is horribly 
ugly.

Using a DMI quirk for something like this is just not maintainable. Are we 
going to live with doing new quirks forever? I'd rather just remove the 
slowdown entirely (obviously that is not for 2.6.24 either, though!), and 
drivers that then are shown to really need it could use their *own* ports.

		Linus

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30  9:30 ` Linus Torvalds
@ 2007-12-30 12:48   ` Andi Kleen
  2007-12-30 13:05     ` Ingo Molnar
  2007-12-30 13:03   ` Ingo Molnar
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 186+ messages in thread
From: Andi Kleen @ 2007-12-30 12:48 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, dpreed, Islam Amer, Alan Cox, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

> drivers that then are shown to really need it could use their *own* ports.

The i8259 driver uses it and it is known to be needed on some old chipsets.
But it doesn't really have any "own" ports to use afaik.

-Andi

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30  9:30 ` Linus Torvalds
  2007-12-30 12:48   ` Andi Kleen
@ 2007-12-30 13:03   ` Ingo Molnar
  2007-12-30 14:14   ` Rene Herman
  2007-12-30 14:47   ` Alan Cox
  3 siblings, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 13:03 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, dpreed, Islam Amer, Alan Cox, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel


* Linus Torvalds <torvalds@linux-foundation.org> wrote:

> > This fixes "hwclock" triggered boottime hangs for a few HP/Compaq 
> > laptops and might as such be applicable to 2.6.24 still.
> 
> It's not a regression as far as I can see (ie we've always done that 
> port 80 access for slow-down), and quite frankly, I think the code is 
> horribly ugly.
> 
> Using a DMI quirk for something like this is just not maintainable. 
> Are we going to live with doing new quirks forever? I'd rather just 
> remove the slowdown entirely (obviously that is not for 2.6.24 either, 
> though!), and drivers that then are shown to really need it could use 
> their *own* ports.

yep, that's exactly the plan: in x86.git we've got it all set up so that 
we can switch over to ioport=nodelay by default in v2.6.25, and then get 
rid of all the iodelay infrastructure in 2.6.26 altogether if things 
work out fine (which is the expectation from all test feedback so far).

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 12:48   ` Andi Kleen
@ 2007-12-30 13:05     ` Ingo Molnar
  2007-12-30 16:08       ` Andi Kleen
  0 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 13:05 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, Alan Cox, hpa,
	Pavel Machek, Ingo Molnar, Thomas Gleixner, Linux Kernel


* Andi Kleen <andi@firstfloor.org> wrote:

> > drivers that then are shown to really need it could use their *own* 
> > ports.
> 
> The i8259 driver uses it and it is known to be needed on some old 
> chipsets. But it doesn't really have any "own" ports to use afaik.

we'll solve that via an i8259-specific quirk. That is a lot cleaner and 
maintainable than the current generic, always-enabled "opt out" 
port-0x80 quirk.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30  9:30 ` Linus Torvalds
  2007-12-30 12:48   ` Andi Kleen
  2007-12-30 13:03   ` Ingo Molnar
@ 2007-12-30 14:14   ` Rene Herman
  2007-12-30 14:47   ` Alan Cox
  3 siblings, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-30 14:14 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: dpreed, Islam Amer, Alan Cox, hpa, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel

On 30-12-07 10:30, Linus Torvalds wrote:

> On Sun, 30 Dec 2007, Rene Herman wrote:

>> This fixes "hwclock" triggered boottime hangs for a few HP/Compaq laptops
>> and might as such be applicable to 2.6.24 still.
> 
> It's not a regression as far as I can see (ie we've always done that port 
> 80 access for slow-down), and quite frankly, I think the code is horribly 
> ugly.

It is indeed not a regression. Submitted it as a stop-gap measure for those 
specific afflicted machines but I guess they'll mostly be able to google up 
the problem and patch by now as well..

> Using a DMI quirk for something like this is just not maintainable. Are we 
> going to live with doing new quirks forever? I'd rather just remove the 
> slowdown entirely (obviously that is not for 2.6.24 either, though!), and 
> drivers that then are shown to really need it could use their *own* ports.

And yes, "elegant" it is neither. It's a bit of a pesky problem though. Port 
0x80 is a decidedly non-random port selection in so far that it's just about 
the only available port with guaranteed (in a PC sense) effects -- various 
chipsets make specific efforts to forward port 0x80 writes onto ISA due to 
its use as a POST port by the PC BIOS meaning the outb outside its bus-level 
effects also has fairly well defined timing characteristics. In practice, a 
udelay(2) is going to satisfy the delay property though -- but doesn't do 
anything for the other things the outb() does.

The legacy PIT, PIC and DMA and KB controllers have been mentioned in this 
and previous incarnations of this same thread as hardware that in some 
implementations need the outb to function properly but ofcourse, no _sane_ 
implementations do. With an arch that purports to support just about 
anything though there's some fairly justified fear, uncertainty, doubt that 
the ones to break aren't going to be found and reported quickly/easily. In 
itself, that could mean it's also not something to be overly worried about, 
but still not nice.

With the various races in (legacy) drivers additionally an early suggestion 
by Andi Kleen to leave the outb in place for a DMI year < X (or no DMI 
available) and just do nothing for > X might in fact be justified.

Rene.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30  9:30 ` Linus Torvalds
                     ` (2 preceding siblings ...)
  2007-12-30 14:14   ` Rene Herman
@ 2007-12-30 14:47   ` Alan Cox
  2007-12-30 15:28     ` Ingo Molnar
  3 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 14:47 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, dpreed, Islam Amer, hpa, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel

> slowdown entirely (obviously that is not for 2.6.24 either, though!), and 
> drivers that then are shown to really need it could use their *own* ports.

*No* - that is the one thing they cannot do. The _p cycles on ISA for 2MHz
parts on a standard ISA bus needs the delay to come off another device. 

For modern systems we should just use tsc delays, but we have to fix all
the drivers first as right now 0x80 causes posting and we have some PCI
users (I think probably all bogus), and we need to fix the tons of
locking errors that are mostly covered by the inb 0x80 being an
indivisible operation so not getting split by interrupts/SMP.

I've been going through the drivers that use it - the biggest mess
appears to be in the watchdog drivers all of which copied an original
lack of locking from the mid 1990s caused by umm.. me. I guess my past is
catching up with me ;)

Some of the ISA network users (like the scc driver) are going to be quite
foul to fix but most of it looks quite sane.

The X server also appears to touch 0x80 in some cases but we can hope
only on ancient hardware.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 14:47   ` Alan Cox
@ 2007-12-30 15:28     ` Ingo Molnar
  2007-12-30 15:38       ` Alan Cox
  2007-12-30 15:47       ` Rene Herman
  0 siblings, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 15:28 UTC (permalink / raw)
  To: Alan Cox
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> For modern systems we should just use tsc delays, but we have to fix 
> all the drivers first as right now 0x80 causes posting and we have 
> some PCI users (I think probably all bogus), and we need to fix the 
> tons of locking errors that are mostly covered by the inb 0x80 being 
> an indivisible operation so not getting split by interrupts/SMP.

i dont get your last point. Firstly, we do an "outb $0x80" not an inb. 
Secondly, outb $0x80 has no PCI posting side-effects AFAICS. Thirdly, 
even assuming that it has PCI posting side-effects, how can any locking 
error be covered up by an outb 0x80 sticking together with the inb it 
does before it? The sequence we emit is:

  inbb $some_port
  outb $0x80

and i see that the likelyhood of getting such sequences from two CPUs 
'mixed up' are low, but how can this have any smp locking side-effects? 
How can this provide any workaround/coverup?

> I've been going through the drivers that use it - the biggest mess 
> appears to be in the watchdog drivers all of which copied an original 
> lack of locking from the mid 1990s caused by umm.. me. I guess my past 
> is catching up with me ;)

heh :-)

> The X server also appears to touch 0x80 in some cases but we can hope 
> only on ancient hardware.

do you have any memories about the outb_p() use of misc_32.c:

        pos = (x + cols * y) * 2;       /* Update cursor position */
        outb_p(14, vidport);
        outb_p(0xff & (pos >> 9), vidport+1);
        outb_p(15, vidport);
        outb_p(0xff & (pos >> 1), vidport+1);

was this ever needed? This is so early in the bootup that can we cannot 
do any sensible delay. Perhaps we could try a natural delay sequence via 
inb from 0x3cc:

        outb(14, vidport);
         inb(0x3cc); /* delay */
        outb(0xff & (pos >> 9), vidport+1);
         inb(0x3cc); /* delay */
        outb(15, vidport);
         inb(0x3cc); /* delay */
        outb(0xff & (pos >> 1), vidport+1);
         inb(0x3cc); /* delay */

as a dummy delay (totally untested).

Reading from the 0x3cc port does not impact the cursor position update 
sequence IIRC - i think the vidport is even ignored for the input 
direction by most hardware, there's a separate input register. The 0x3cc 
port is a well-defined VGA register which should be unused on non-VGA 
hardware. (which makes it a perfect delay register in any case)

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 15:28     ` Ingo Molnar
@ 2007-12-30 15:38       ` Alan Cox
  2007-12-30 16:01         ` Ingo Molnar
  2007-12-30 17:10         ` Juergen Beisert
  2007-12-30 15:47       ` Rene Herman
  1 sibling, 2 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-30 15:38 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> i dont get your last point. Firstly, we do an "outb $0x80" not an inb. 

outb not inb sorry yes

> Secondly, outb $0x80 has no PCI posting side-effects AFAICS. Thirdly, 

It does. The last mmio write cycle to the bridge gets pushed out before
the 0x80 cycle goes to the PCI bridge, times out and goes to the LPC bus.

I still don't believe any of our _p users in PCI space are actually real
- but someone needs to look at the scsi ones.

> even assuming that it has PCI posting side-effects, how can any locking 
> error be covered up by an outb 0x80 sticking together with the inb it 
> does before it? The sequence we emit is:
> 
>   inbb $some_port
>   outb $0x80
> 
> and i see that the likelyhood of getting such sequences from two CPUs 
> 'mixed up' are low, but how can this have any smp locking side-effects? 
> How can this provide any workaround/coverup?

We issue inb port
We issue outb 0x80

The CPU core stalls and the LPC bus stalls

On the other CPU we issue another access to the LPC bus because our
locking is wrong. With the 0x80 outb use this stalls so the delay is
applied unless the two inb's occur perfectly in time. With a udelay() the
udelay can be split and we get a second access which breaks the needed
device delay. We end up relying on the bus locking non splitting
properties of the 0x80 port access to paper over bugs - see the watchdog
fix example I sent you about a week ago.

That btw is another argument for removing 0x80 usage as much as possible
- its bad for real time.

> do you have any memories about the outb_p() use of misc_32.c:
> 
>         pos = (x + cols * y) * 2;       /* Update cursor position */
>         outb_p(14, vidport);
>         outb_p(0xff & (pos >> 9), vidport+1);
>         outb_p(15, vidport);
>         outb_p(0xff & (pos >> 1), vidport+1);
> 
> was this ever needed? This is so early in the bootup that can we cannot 

None - but we don't care. The problems with 0x80 and the wacko HP systems
occur once ACPI is enabled so we are fine using 0x80. I don't myself know
why the _p versions ended up being used. A rummage through archives found
me nothing useful on this but notes that outb not outw is required for
some devices.

For that matter does anyone actually have video cards old enough for us
to care actually still in use with Linux today ? 

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 15:28     ` Ingo Molnar
  2007-12-30 15:38       ` Alan Cox
@ 2007-12-30 15:47       ` Rene Herman
  2007-12-30 16:07         ` Ingo Molnar
  2007-12-30 18:40         ` Linus Torvalds
  1 sibling, 2 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-30 15:47 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

On 30-12-07 16:28, Ingo Molnar wrote:

> Reading from the 0x3cc port does not impact the cursor position update 
> sequence IIRC - i think the vidport is even ignored for the input 
> direction by most hardware, there's a separate input register. The 0x3cc 
> port is a well-defined VGA register which should be unused on non-VGA 
> hardware. (which makes it a perfect delay register in any case)

Hardly. Duron 1300 on AMD756:

rene@7ixe4:~/src/port80$ su -c ./port80
cycles: out 2400, in 2401
rene@7ixe4:~/src/port80$ su -c ./port3cc
cycles: out 459, in 394

As stated a few dozen times by now already, port 0x80 is _decidedly_ _non_ 
_random_

Rene.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 15:38       ` Alan Cox
@ 2007-12-30 16:01         ` Ingo Molnar
  2007-12-30 16:48           ` Alan Cox
  2007-12-30 17:10         ` Juergen Beisert
  1 sibling, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 16:01 UTC (permalink / raw)
  To: Alan Cox
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > i dont get your last point. Firstly, we do an "outb $0x80" not an 
> > inb.
> 
> outb not inb sorry yes
> 
> > Secondly, outb $0x80 has no PCI posting side-effects AFAICS. 
> > Thirdly,
> 
> It does. The last mmio write cycle to the bridge gets pushed out 
> before the 0x80 cycle goes to the PCI bridge, times out and goes to 
> the LPC bus.

ok. Is it more of a "gets flushed due to timing out", or a 
specified-for-sure POST flushing property of all out 0x80 cycles going 
to the PCI bridge? I thought PCI posting policy is up to the CPU, it can 
delay PCI space writes arbitrarily (within reasonable timeouts) as long 
as no read is done from the _same_ IO space address. Note that the port 
0x80 cycle is neither a read, nor for the same address.

> I still don't believe any of our _p users in PCI space are actually 
> real - but someone needs to look at the scsi ones.

i'm wondering, how safe would it be to just dumbly replace outb_p() 
with:

	out(port);
	in(port);

in these drivers. Side-effects of inb() would not be unheard of for the 
ancient IO ports, but for even relatively old SCSI hardware, would that 
really be a problem?

this would give us explicit PCI posting.

> > even assuming that it has PCI posting side-effects, how can any locking 
> > error be covered up by an outb 0x80 sticking together with the inb it 
> > does before it? The sequence we emit is:
> > 
> >   inbb $some_port
> >   outb $0x80
> > 
> > and i see that the likelyhood of getting such sequences from two CPUs 
> > 'mixed up' are low, but how can this have any smp locking side-effects? 
> > How can this provide any workaround/coverup?
> 
> We issue inb port
> We issue outb 0x80
> 
> The CPU core stalls and the LPC bus stalls
> 
> On the other CPU we issue another access to the LPC bus because our 
> locking is wrong. With the 0x80 outb use this stalls so the delay is 
> applied unless the two inb's occur perfectly in time. With a udelay() 
> the udelay can be split and we get a second access which breaks the 
> needed device delay. We end up relying on the bus locking non 
> splitting properties of the 0x80 port access to paper over bugs - see 
> the watchdog fix example I sent you about a week ago.

ah, i understand. So i guess a stupid udelay_serialized() which takes a 
global spinlock would solve these sort of races? But i guess making them 
more likely to trigger would lead to a better kernel in the end ...

> > do you have any memories about the outb_p() use of misc_32.c:
> > 
> >         pos = (x + cols * y) * 2;       /* Update cursor position */
> >         outb_p(14, vidport);
> >         outb_p(0xff & (pos >> 9), vidport+1);
> >         outb_p(15, vidport);
> >         outb_p(0xff & (pos >> 1), vidport+1);
> > 
> > was this ever needed? This is so early in the bootup that can we cannot 
> 
> None - but we don't care. The problems with 0x80 and the wacko HP 
> systems occur once ACPI is enabled so we are fine using 0x80. I don't 
> myself know why the _p versions ended up being used. A rummage through 
> archives found me nothing useful on this but notes that outb not outw 
> is required for some devices.
> 
> For that matter does anyone actually have video cards old enough for 
> us to care actually still in use with Linux today ?

we had port 0x80 removal patches floating in the past decade, and i'm 
sure if it broke anything for sure we'd know about it. It was always 
this "general scope impact" property of it that scared us away from 
doing it - but we'll do the plunge in v2.6.25 and make io_delay=udelay 
the default, hm? Thomas has a real 386DX system, if that doesnt break 
then nothing would i guess ;-) We wont forget about needed PCI posting 
driver fixups either because the _p() API use would still be in place. 
By 2.6.26 we could remove all of them.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 15:47       ` Rene Herman
@ 2007-12-30 16:07         ` Ingo Molnar
  2007-12-30 16:27           ` Rene Herman
  2007-12-30 18:40         ` Linus Torvalds
  1 sibling, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 16:07 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel


* Rene Herman <rene.herman@keyaccess.nl> wrote:

> On 30-12-07 16:28, Ingo Molnar wrote:
>
>> Reading from the 0x3cc port does not impact the cursor position update 
>> sequence IIRC - i think the vidport is even ignored for the input 
>> direction by most hardware, there's a separate input register. The 0x3cc 
>> port is a well-defined VGA register which should be unused on non-VGA 
>> hardware. (which makes it a perfect delay register in any case)
>
> Hardly. Duron 1300 on AMD756:

but that does not matter at all: that's not '90s era hardware that we 
are (slightly) worried about wrt. IO delays in misc_32.c. (i.e. on 
_real_ ISA systems)

> rene@7ixe4:~/src/port80$ su -c ./port80
> cycles: out 2400, in 2401
> rene@7ixe4:~/src/port80$ su -c ./port3cc
> cycles: out 459, in 394

of course, since VGA is implemented in the southbridge or on the video 
card, so it's much faster than a true ISA cycle.

the only (minor) worry we have here is really ancient systems relying on 
delays there. Modern VGA hardware most definitely does not need any such 
delays.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 13:05     ` Ingo Molnar
@ 2007-12-30 16:08       ` Andi Kleen
  2007-12-30 16:28         ` Ingo Molnar
  0 siblings, 1 reply; 186+ messages in thread
From: Andi Kleen @ 2007-12-30 16:08 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Andi Kleen, Linus Torvalds, Rene Herman, dpreed, Islam Amer,
	Alan Cox, hpa, Pavel Machek, Ingo Molnar, Thomas Gleixner,
	Linux Kernel

On Sun, Dec 30, 2007 at 02:05:44PM +0100, Ingo Molnar wrote:
> 
> * Andi Kleen <andi@firstfloor.org> wrote:
> 
> > > drivers that then are shown to really need it could use their *own* 
> > > ports.
> > 
> > The i8259 driver uses it and it is known to be needed on some old 
> > chipsets. But it doesn't really have any "own" ports to use afaik.
> 
> we'll solve that via an i8259-specific quirk. That is a lot cleaner and 
> maintainable than the current generic, always-enabled "opt out" 
> port-0x80 quirk.

You mean using pci quirks + udelay? Will be probably challenging to collect
PCI-IDs for that. And there might be old systems needing it without PCI.
They likely won't have DMI either.

In theory you could make it a DMI year cut off of course (and assume old
if no DMI, although that happens occasionally with new systems too); but
that is generally considered ugly.

I don't think it's a big problem to keep delays of some form by default in 8259 --
people who care about performance should be definitely using APIC mode instead.

-Andi

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:07         ` Ingo Molnar
@ 2007-12-30 16:27           ` Rene Herman
  2007-12-30 17:06             ` Ingo Molnar
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-30 16:27 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

On 30-12-07 17:07, Ingo Molnar wrote:

> * Rene Herman <rene.herman@keyaccess.nl> wrote:
> 
>> On 30-12-07 16:28, Ingo Molnar wrote:
>>
>>> hardware. (which makes it a perfect delay register in any case)

>> Hardly. Duron 1300 on AMD756:
> 
> but that does not matter at all: that's not '90s era hardware that we 
> are (slightly) worried about wrt. IO delays in misc_32.c. (i.e. on 
> _real_ ISA systems)

Real ISA systems will also generally respond faster to it than the unused 
port (this thing actually has an ISA bus but not VGA on it ofcourse) which 
means that "a perfect delay register" it is not. But yes, I have an actual 
Am386DX-40 with ISA VGA up and running which also doesn't care either way, 
about the ones in misc_32.c or anywhere else for that matter.

Me myself never having seen anything actually care since using that machine 
actively was in fact the reason I got involved so don't get me wrong; doing 
away with 0x80 use would be quite sensible. It's just that various machines 
that _do_ need it (and which were reported to exist) are by now gathering 
dust in basements and will not timely respond/test this. Which, again, also 
means their possible regression might not be considered all that regressive 
but still; if x86 should support anything under the sun still it's a 
sensible worry.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:08       ` Andi Kleen
@ 2007-12-30 16:28         ` Ingo Molnar
  2007-12-30 18:21           ` Andi Kleen
  0 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 16:28 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, Alan Cox, hpa,
	Pavel Machek, Ingo Molnar, Thomas Gleixner, Linux Kernel


* Andi Kleen <andi@firstfloor.org> wrote:

> > > The i8259 driver uses it and it is known to be needed on some old 
> > > chipsets. But it doesn't really have any "own" ports to use afaik.
> > 
> > we'll solve that via an i8259-specific quirk. That is a lot cleaner 
> > and maintainable than the current generic, always-enabled "opt out" 
> > port-0x80 quirk.
> 
> You mean using pci quirks + udelay? Will be probably challenging to 
> collect PCI-IDs for that. And there might be old systems needing it 
> without PCI. They likely won't have DMI either.
> 
> In theory you could make it a DMI year cut off of course (and assume 
> old if no DMI, although that happens occasionally with new systems 
> too); but that is generally considered ugly.
> 
> I don't think it's a big problem to keep delays of some form by 
> default in 8259 -- people who care about performance should be 
> definitely using APIC mode instead.

do you remember which old systems/chipsets were affected by this 
problem? We had many - meanwhile fixed - PIC related problems, maybe 
it's a red herring and the delay just papered it over.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:01         ` Ingo Molnar
@ 2007-12-30 16:48           ` Alan Cox
  2007-12-30 17:08             ` Ingo Molnar
  2007-12-30 18:14             ` Rene Herman
  0 siblings, 2 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-30 16:48 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> ok. Is it more of a "gets flushed due to timing out", or a 
> specified-for-sure POST flushing property of all out 0x80 cycles going 
> to the PCI bridge? I thought PCI posting policy is up to the CPU, it can 
> delay PCI space writes arbitrarily (within reasonable timeouts) as long 
> as no read is done from the _same_ IO space address. Note that the port 
> 0x80 cycle is neither a read, nor for the same address.

Its what appears to happen reliably on real computers.

> i'm wondering, how safe would it be to just dumbly replace outb_p() 
> with:
> 
> 	out(port);
> 	in(port);

Catastrophic I imagine. If the delay is for timing access then you've just
broken the timing, if the port has side effects you've just broken the
driver.

> in these drivers. Side-effects of inb() would not be unheard of for the 
> ancient IO ports, but for even relatively old SCSI hardware, would that 
> really be a problem?

The specific drivers need reviewing. There are very few uses in PCI space
so it's a minor job.

> ah, i understand. So i guess a stupid udelay_serialized() which takes a 
> global spinlock would solve these sort of races? But i guess making them 
> more likely to trigger would lead to a better kernel in the end ...

Better to just fix the drivers. I don't think that will take too many
days after everyone is back working.

> doing it - but we'll do the plunge in v2.6.25 and make io_delay=udelay 
> the default, hm? Thomas has a real 386DX system, if that doesnt break 

For processors with TSC I think we should aim for 2.6.25 to do this and
to have the major other _p fixups done. I pity whoever does stuff like
the scc drivers but most of the rest isn't too bad.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:27           ` Rene Herman
@ 2007-12-30 17:06             ` Ingo Molnar
  2007-12-30 17:54               ` Rene Herman
  2007-12-30 18:29               ` Alan Cox
  0 siblings, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 17:06 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel


* Rene Herman <rene.herman@keyaccess.nl> wrote:

>>> Hardly. Duron 1300 on AMD756:
>>
>> but that does not matter at all: that's not '90s era hardware that we 
>> are (slightly) worried about wrt. IO delays in misc_32.c. (i.e. on 
>> _real_ ISA systems)
>
> Real ISA systems will also generally respond faster to it than the 
> unused port (this thing actually has an ISA bus but not VGA on it 
> ofcourse) which means that "a perfect delay register" it is not. But 
> yes, I have an actual Am386DX-40 with ISA VGA up and running which 
> also doesn't care either way, about the ones in misc_32.c or anywhere 
> else for that matter.

yeah - and that's typical of most _p() use: most of them are totally 
bogus, but the global existence of the delay was used as a "it _might_ 
break system" boogey-man against replacing it.

so _IF_ we do any delay in x86 platform drivers, we at most do a delay 
on the order of the round-trip latency to the same piece of hardware we 
are handling. That isolates the quirk to the same hardware category, 
instead of creating these cross-dependencies and assumed dependencies on 
fixed, absolute timings. (and most hardware timing bugs are not absolute 
but depend on some bus speed/frequency, thus round-trip latency of that 
hardware is a good approximation of that. The round-trip to the same 
hardware also correctly adds any assumed PCI posting dependencies.)

So the current plan is to go with an io_delay=udelay default in v2.6.25, 
to give this a migration window, and io_delay=none in v2.6.26 [and a 
complete removal of arch/x86/kernel/io_delay.c], once the _p() uses are 
fixed up. This is gradual enough to notice any regressions we care about 
and also makes it nicely bisectable and gradual.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:48           ` Alan Cox
@ 2007-12-30 17:08             ` Ingo Molnar
  2007-12-30 18:14             ` Rene Herman
  1 sibling, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 17:08 UTC (permalink / raw)
  To: Alan Cox
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > ah, i understand. So i guess a stupid udelay_serialized() which 
> > takes a global spinlock would solve these sort of races? But i guess 
> > making them more likely to trigger would lead to a better kernel in 
> > the end ...
> 
> Better to just fix the drivers. I don't think that will take too many 
> days after everyone is back working.

ok.

> > doing it - but we'll do the plunge in v2.6.25 and make 
> > io_delay=udelay the default, hm? Thomas has a real 386DX system, if 
> > that doesnt break
> 
> For processors with TSC I think we should aim for 2.6.25 to do this 
> and to have the major other _p fixups done. I pity whoever does stuff 
> like the scc drivers but most of the rest isn't too bad.

ok, sounds good to me. The current io_delay= stuff for v2.6.25 is 
already shaped as a debugging/transition helper, towards complete 
elimination of _p() uses.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 15:38       ` Alan Cox
  2007-12-30 16:01         ` Ingo Molnar
@ 2007-12-30 17:10         ` Juergen Beisert
  2007-12-30 20:50           ` H. Peter Anvin
  1 sibling, 1 reply; 186+ messages in thread
From: Juergen Beisert @ 2007-12-30 17:10 UTC (permalink / raw)
  To: linux-kernel
  Cc: Alan Cox, Ingo Molnar, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, hpa, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner

On Sunday 30 December 2007 16:38, Alan Cox wrote:
> > do you have any memories about the outb_p() use of misc_32.c:
> >
> >         pos = (x + cols * y) * 2;       /* Update cursor position */
> >         outb_p(14, vidport);
> >         outb_p(0xff & (pos >> 9), vidport+1);
> >         outb_p(15, vidport);
> >         outb_p(0xff & (pos >> 1), vidport+1);
> >
> > was this ever needed? This is so early in the bootup that can we cannot
>
> None - but we don't care.

Was this embedded outb to 0x80 for delay only? Maybe I'm wrong. But in the 
case above it forces the chipselect signal to deselect the hardware between 
the access to vidport and vidport+1. Some devices need this to latch the 
values correctly. Otherwise the chipselect signal would be active for all 
four accesses in the example above (and only data and addresses are changing 
from device's view).

Juergen

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 17:06             ` Ingo Molnar
@ 2007-12-30 17:54               ` Rene Herman
  2007-12-30 18:29               ` Alan Cox
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-30 17:54 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

On 30-12-07 18:06, Ingo Molnar wrote:

> * Rene Herman <rene.herman@keyaccess.nl> wrote:

>> Real ISA systems will also generally respond faster to it than the 
>> unused port (this thing actually has an ISA bus but not VGA on it 
>> ofcourse) which means that "a perfect delay register" it is not. But 
>> yes, I have an actual Am386DX-40 with ISA VGA up and running which 
>> also doesn't care either way, about the ones in misc_32.c or anywhere 
>> else for that matter.
> 
> yeah - and that's typical of most _p() use: most of them are totally 
> bogus, but the global existence of the delay was used as a "it _might_ 
> break system" boogey-man against replacing it.

No delaying at all does break a few systems.

> so _IF_ we do any delay in x86 platform drivers, we at most do a delay 
> on the order of the round-trip latency to the same piece of hardware we 
> are handling.

Given that part of the problem is 2 MHz devices on a 8 MHz bus, you can't do 
this generally.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:48           ` Alan Cox
  2007-12-30 17:08             ` Ingo Molnar
@ 2007-12-30 18:14             ` Rene Herman
  2007-12-30 18:39               ` Alan Cox
  2007-12-31 12:23               ` Alan Cox
  1 sibling, 2 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-30 18:14 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On 30-12-07 17:48, Alan Cox wrote:

> For processors with TSC I think we should aim for 2.6.25 to do this and 
> to have the major other _p fixups done. I pity whoever does stuff like 
> the scc drivers but most of the rest isn't too bad.

I'm by the way looking at drivers/net/wd.c which my 386 uses for its dual 
mode NE2000/WD8013 clone ISA NIC and while it specifically needs no delay at 
all it seems, the mixed use of out and outb_p seems to suggest that someone 
once thought about that. Would you advice sticking in a udelay(2) manually 
there?

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 16:28         ` Ingo Molnar
@ 2007-12-30 18:21           ` Andi Kleen
  0 siblings, 0 replies; 186+ messages in thread
From: Andi Kleen @ 2007-12-30 18:21 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Andi Kleen, Linus Torvalds, Rene Herman, dpreed, Islam Amer,
	Alan Cox, hpa, Pavel Machek, Ingo Molnar, Thomas Gleixner,
	Linux Kernel

> do you remember which old systems/chipsets were affected by this 
> problem? We had many - meanwhile fixed - PIC related problems, maybe 
> it's a red herring and the delay just papered it over.

Some old VIA chipsets at least iirc. Might be more.

-Andi

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 17:06             ` Ingo Molnar
  2007-12-30 17:54               ` Rene Herman
@ 2007-12-30 18:29               ` Alan Cox
  2007-12-30 18:43                 ` Andi Kleen
  2007-12-30 20:46                 ` Ingo Molnar
  1 sibling, 2 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-30 18:29 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rene Herman, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> So the current plan is to go with an io_delay=udelay default in v2.6.25, 
> to give this a migration window, and io_delay=none in v2.6.26 [and a 
> complete removal of arch/x86/kernel/io_delay.c], once the _p() uses are 
> fixed up. This is gradual enough to notice any regressions we care about 
> and also makes it nicely bisectable and gradual.

You will break systems if you blindly go around disabling _p delays for
ISA and LPC bus devices. The DEC Hinote laptops for example are well
known for requiring the correct ISA and other keyboard controller delays.
I don't expect anyone to test with a hinote or see it until it hits
Debian or similar 'low resource' friendly devices.

A 2.6.26 plan for io_delay=none is very very foolish indeed. We don't burn
the processor manuals, overclock the CPU and use undefined behaviour
hacks, we shouldn't do the same for I/O devices. Your claim of
bisectability is also completely confused and wrong. If, for example, you
write to an SCC without delays then the chances are it will work most
times. Bisecting doesn't work for random timing dependant failures.

We have four categories of _p users

- Devices that don't need it -> Eliminate use
- Old Devices that do need it -> Codify use and fix locking
- Legacy Devices that we don't need to use on modern systems -> Avoid use
- Devices that sometimes need it -> Evaluate options

There is absolutely no point in breaking, overclocking and introducing
random unreliabilities (that may be stepping or even device instance
specific) into device drivers. Quite the reverse in fact - the way to
drive out _p misuse for debugging is to make it *very* visible. An
io_delay=debug which beeps the keyboard buzzer each _p access will be
most informative and lead to far better and correct debugging.

The components in question for the typical user of a modern system are:
	ISA DMA controller (doesn't get used)
	Keyboard interface (notoriously sensitive to timing, going USB)
	PIC (use the APIC instead)
	Legacy Timers (use the newer timers instead)
	CMOS (slow as **** anyway so udelay 2 doesn't matter)
	Floppy (dying out and slow anyway)

So there is nothing to gain from going with "No delay" and everything to
lose. What we actually want to do is to make it as visible as possible so
we can avoid it whenever possible.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:14             ` Rene Herman
@ 2007-12-30 18:39               ` Alan Cox
  2007-12-30 19:33                 ` Rene Herman
  2007-12-31 12:23               ` Alan Cox
  1 sibling, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 18:39 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On Sun, 30 Dec 2007 19:14:40 +0100
Rene Herman <rene.herman@keyaccess.nl> wrote:

> On 30-12-07 17:48, Alan Cox wrote:
> 
> > For processors with TSC I think we should aim for 2.6.25 to do this and 
> > to have the major other _p fixups done. I pity whoever does stuff like 
> > the scc drivers but most of the rest isn't too bad.
> 
> I'm by the way looking at drivers/net/wd.c which my 386 uses for its dual 
> mode NE2000/WD8013 clone ISA NIC and while it specifically needs no delay at 
> all it seems, the mixed use of out and outb_p seems to suggest that someone 
> once thought about that. Would you advice sticking in a udelay(2) manually 
> there?

I would need to dig out the documentation and NE2000 reference code if I
even still have them. From memory NE2K needs them but I don't know
offhand if the WD80x3 devices do, or if only some of them do. It'll also
depend on the port - the DPRAM is different to the 8390.

Don Becker wrote the drivers and at the time he tuned them carefully for
performance so I would expect delays to be the ones needed

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 15:47       ` Rene Herman
  2007-12-30 16:07         ` Ingo Molnar
@ 2007-12-30 18:40         ` Linus Torvalds
  2007-12-30 20:34           ` Ingo Molnar
                             ` (2 more replies)
  1 sibling, 3 replies; 186+ messages in thread
From: Linus Torvalds @ 2007-12-30 18:40 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Alan Cox, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel



On Sun, 30 Dec 2007, Rene Herman wrote:
> 
> rene@7ixe4:~/src/port80$ su -c ./port80
> cycles: out 2400, in 2401
> rene@7ixe4:~/src/port80$ su -c ./port3cc
> cycles: out 459, in 394
> 
> As stated a few dozen times by now already, port 0x80 is _decidedly_ _non_
> _random_

Oh, I agree 100% that port 80 is not random. It's very much selected on 
purpose.

The reason we use port 80 is because it's commonly used as the BIOS POST 
debug port, which means that it's been a reasonable "safe" port to use, 
since nobody would be so crazy as to actually hook up a real device behind 
that port (and since it is below 0x100, it's also part of the "motherboard 
range", so you won't have any crazy plug-in devices either).

Pretty much all other ports in the low 256 bytes of IO have been used at 
some point or other, because people put special motherboard devices in and 
pick from the very limited list of open ports at random. So there are 
ports that are not commonly used (notably 0xB0-0xBF and 0xE0-0xEF), but 
they are quite often used for stuff like the magic Sony VAIO rocker-button 
devices etc.

So 0x80 _is_ special. We've been able to use it for 15+ years with 
basically nobody being so insane as to put an anything there.

However, I'd like to point out that the *timings* aren't special per se. 
The only reason you see such slow accesses to port 80 is not because port 
80 is special from a timing standpoint, but because it falls under the 
heading of "no device wanted to accept the access", and it wasn't decoded 
by any bridge or device. So it hits the "access timed out" case, which is 
just about the slowest access you can have.

But that does't mean that other ports won't have the same timings. Also, 
it doesn't mean that we really need to have exactly *those* timings.

But yes, the timeout timing is pretty convenient, because it's basically 
almost universally always going to take one microsecond to time out, 
regardless of speed of CPU. It's been impressively stable over the years. 

But do we *need* it that stable? It probably would be perfectly fine to 
pick something that gets faster with CPU's getting faster, because it's 
generally only really old devices that need that delay in the first place. 

In other words, the really *traditional* delay is not to do an IO port 
access at all, but to just do two short unconditional jumps. That was 
enough of a slowdown on the old machines, and the old machines are likely 
the only machines that really care about or want the slowdown in the first 
place!

In other words, what I'm trying to say is:

 - yes, "port 80" is very much special

 - yes, the timings on any port that is unconnected (or connected to some 
   interal ISA bus like the LPC often is) have been impressively stable 
   over the years at about 1us.

 - but no, I don't think we really need those special timings. The fact 
   is, hardware manufacturers have been *so* careful about backwards 
   compatibility, that they generally made sure that the "two short jumps" 
   delay (which is no delay at all these days!) _also_ continued working.

I also think that the worries about PCI write posting are unnecessary. IO 
port accesses (ie a regular "inb()" and "outb()" even _without_ the "_p()" 
format slowdown) are already synchronous not only by the CPU but by all 
chipsets. That's why that "outb" to port 0x80 takes a microsecond: because 
unlike a MMIO write, it's not only synchronous all the way to the chipset, 
it's even synchronous as far as the CPU core is concerned too (which is 
also why all high-performance devices avoid PIO like the plague).

So even if that "port 80" access will also cause PCI postings to be 
flushed, so would the actual IO access that accompanies it, so I don't 
think that is a very strong argument. 

With all that said: it is certainly possible that the 1us timing makes a 
difference on some machine, and it is certainly *also* theoretically 
possible that there is a buggy chipset that posts too much, and the port 
80 access might make a difference, but it's not all that likely, and I 
suspect we'd be better off handling those devices/drivers on a one-by-one 
basis as we find them.

			Linus

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:29               ` Alan Cox
@ 2007-12-30 18:43                 ` Andi Kleen
  2007-12-30 20:46                 ` Ingo Molnar
  1 sibling, 0 replies; 186+ messages in thread
From: Andi Kleen @ 2007-12-30 18:43 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, Rene Herman, Linus Torvalds, dpreed, Islam Amer,
	hpa, Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> A 2.6.26 plan for io_delay=none is very very foolish indeed. We don't burn

It also seems quite risky to me; at least if not paired with a DMI 
year master switch. 

Switching to udelay() by default should be probably ok though.

-Andi

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:39               ` Alan Cox
@ 2007-12-30 19:33                 ` Rene Herman
  2007-12-30 20:00                   ` Linus Torvalds
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-30 19:33 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On 30-12-07 19:39, Alan Cox wrote:

> On Sun, 30 Dec 2007 19:14:40 +0100
> Rene Herman <rene.herman@keyaccess.nl> wrote:

>> I'm by the way looking at drivers/net/wd.c which my 386 uses for its dual 
>> mode NE2000/WD8013 clone ISA NIC and while it specifically needs no delay at 
>> all it seems, the mixed use of out and outb_p seems to suggest that someone 
>> once thought about that. Would you advice sticking in a udelay(2) manually 
>> there?
> 
> I would need to dig out the documentation and NE2000 reference code if I
> even still have them. From memory NE2K needs them but I don't know
> offhand if the WD80x3 devices do, or if only some of them do. It'll also
> depend on the port - the DPRAM is different to the 8390.
> 
> Don Becker wrote the drivers and at the time he tuned them carefully for
> performance so I would expect delays to be the ones needed

This NIC (a Networth UTP16B) has a National Semiconductor DP83905 AT/LANTIC 
for which I'm reading the software developers guide now. It doesn't seem to 
list specific delays...

I also just now dug up a "WDC (C) 1987" WD8003EBT and a "Novell, Inc (C) 
1990" NE1000, both 8-bit ISA NICs and the ownership of which, I would 
suggest, makes me a really cool person. Both are coax and a little clumsy to 
test but that 1987 one is probably going to be close to the oldest type around.

I've been testing with the 386's own 2.2.26 kernel upto now but I'll try and 
compile a 2.6 system on there with uclibc and busybox or some such and test 
more.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 19:33                 ` Rene Herman
@ 2007-12-30 20:00                   ` Linus Torvalds
  2007-12-30 20:09                     ` Rene Herman
  2007-12-30 21:20                     ` David P. Reed
  0 siblings, 2 replies; 186+ messages in thread
From: Linus Torvalds @ 2007-12-30 20:00 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, Ingo Molnar, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel



On Sun, 30 Dec 2007, Rene Herman wrote:
> 
> I also just now dug up a "WDC (C) 1987" WD8003EBT and a "Novell, Inc (C) 1990"
> NE1000, both 8-bit ISA NICs and the ownership of which, I would suggest, makes
> me a really cool person.

.. I'm also told that mentioning this is a really good way to pick up any 
hot chicks in singles bars.

"If you've got it, flaunt it".

Please let us know how it turns out for you,

			Linus

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:00                   ` Linus Torvalds
@ 2007-12-30 20:09                     ` Rene Herman
  2007-12-30 21:20                     ` David P. Reed
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-30 20:09 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Alan Cox, Ingo Molnar, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

On 30-12-07 21:00, Linus Torvalds wrote:

> On Sun, 30 Dec 2007, Rene Herman wrote:
>> I also just now dug up a "WDC (C) 1987" WD8003EBT and a "Novell, Inc (C) 1990"
>> NE1000, both 8-bit ISA NICs and the ownership of which, I would suggest, makes
>> me a really cool person.
> 
> .. I'm also told that mentioning this is a really good way to pick up any 
> hot chicks in singles bars.
> 
> "If you've got it, flaunt it".
> 
> Please let us know how it turns out for you,

Ah, check, thanks, will do!

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:40         ` Linus Torvalds
@ 2007-12-30 20:34           ` Ingo Molnar
  2007-12-30 21:28             ` Alan Cox
  2007-12-30 21:13           ` Alan Cox
  2007-12-31 13:21           ` Pavel Machek
  2 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 20:34 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, Alan Cox, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel


* Linus Torvalds <torvalds@linux-foundation.org> wrote:

> So even if that "port 80" access will also cause PCI postings to be 
> flushed, so would the actual IO access that accompanies it, so I don't 
> think that is a very strong argument.
> 
> With all that said: it is certainly possible that the 1us timing makes 
> a difference on some machine, and it is certainly *also* theoretically 
> possible that there is a buggy chipset that posts too much, and the 
> port 80 access might make a difference, but it's not all that likely, 
> and I suspect we'd be better off handling those devices/drivers on a 
> one-by-one basis as we find them.

yeah, wholeheartedly agreed, and this is what x86.git is heading 
towards. All test feedback so far is positive. With strong tools like 
bisection there's no reason why we couldnt approach it this way. If this 
change breaks anything, it will be bisected down to the patch below. In 
fact even io_delay=udelay would be wrong because any problem will be 
less clearly triggerable and thus less bisectable/debuggable.

	Ingo

----------------------->
Subject: x86: make io_delay=none the default
From: Ingo Molnar <mingo@elte.hu>

make io_delay=none the default. This is the first step towards removing 
all the legacy io-delay API uses.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/Kconfig.debug |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-x86.q/arch/x86/Kconfig.debug
===================================================================
--- linux-x86.q.orig/arch/x86/Kconfig.debug
+++ linux-x86.q/arch/x86/Kconfig.debug
@@ -133,7 +133,7 @@ config IO_DELAY_TYPE_NONE
 
 choice
 	prompt "IO delay type"
-	default IO_DELAY_0X80
+	default IO_DELAY_NONE
 
 config IO_DELAY_0X80
 	bool "port 0x80 based port-IO delay [recommended]"

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:29               ` Alan Cox
  2007-12-30 18:43                 ` Andi Kleen
@ 2007-12-30 20:46                 ` Ingo Molnar
  2007-12-30 21:07                   ` Rene Herman
                                     ` (2 more replies)
  1 sibling, 3 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 20:46 UTC (permalink / raw)
  To: Alan Cox
  Cc: Rene Herman, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > So the current plan is to go with an io_delay=udelay default in v2.6.25, 
> > to give this a migration window, and io_delay=none in v2.6.26 [and a 
> > complete removal of arch/x86/kernel/io_delay.c], once the _p() uses are 
> > fixed up. This is gradual enough to notice any regressions we care about 
> > and also makes it nicely bisectable and gradual.
> 
> You will break systems if you blindly go around disabling _p delays 
> for ISA and LPC bus devices. The DEC Hinote laptops for example are 
> well known for requiring the correct ISA and other keyboard controller 
> delays. I don't expect anyone to test with a hinote or see it until it 
> hits Debian or similar 'low resource' friendly devices.

well, using io_delay=udelay is not 'blindly disabling'. io_delay=none 
would be the end goal, once all _p() API uses are eliminated by 
transformation. In drivers/ alone that's more than 1000 callsites, so 
it's quite frequently used, and wont go away overnight.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 17:10         ` Juergen Beisert
@ 2007-12-30 20:50           ` H. Peter Anvin
  2007-12-31  1:03             ` David P. Reed
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-30 20:50 UTC (permalink / raw)
  To: Juergen Beisert
  Cc: linux-kernel, Alan Cox, Ingo Molnar, Linus Torvalds, Rene Herman,
	dpreed, Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner

Juergen Beisert wrote:
> On Sunday 30 December 2007 16:38, Alan Cox wrote:
>>> do you have any memories about the outb_p() use of misc_32.c:
>>>
>>>         pos = (x + cols * y) * 2;       /* Update cursor position */
>>>         outb_p(14, vidport);
>>>         outb_p(0xff & (pos >> 9), vidport+1);
>>>         outb_p(15, vidport);
>>>         outb_p(0xff & (pos >> 1), vidport+1);
>>>
>>> was this ever needed? This is so early in the bootup that can we cannot
>> None - but we don't care.
> 
> Was this embedded outb to 0x80 for delay only? Maybe I'm wrong. But in the 
> case above it forces the chipselect signal to deselect the hardware between 
> the access to vidport and vidport+1. Some devices need this to latch the 
> values correctly. Otherwise the chipselect signal would be active for all 
> four accesses in the example above (and only data and addresses are changing 
> from device's view).
> 

Presumably you're talking about an actual ISA bus here.  On those, you 
don't really have a chip select; but you'd expect the latch to happen on 
the rising edge of IOW#, not on an internally generated chip select.

Now, I think there is a specific reason to believe that EGA/VGA (but 
perhaps not CGA/MDA) didn't need these kinds of hacks: the video cards 
of the day was touched, directly, by an interminable number of DOS 
applications.  CGA/MDA generally *were not*, due to the unsynchronized 
memory of the original versions (writing could cause snow), so most 
applications tended to fall back to using the BIOS access methods for 
CGA and MDA.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:46                 ` Ingo Molnar
@ 2007-12-30 21:07                   ` Rene Herman
  2007-12-30 21:25                     ` Ingo Molnar
  2007-12-30 21:29                   ` Alan Cox
  2007-12-31 13:11                   ` Pavel Machek
  2 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-30 21:07 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

On 30-12-07 21:46, Ingo Molnar wrote:
> * Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
> 
>>> So the current plan is to go with an io_delay=udelay default in v2.6.25, 
>>> to give this a migration window, and io_delay=none in v2.6.26 [and a 
>>> complete removal of arch/x86/kernel/io_delay.c], once the _p() uses are 
>>> fixed up. This is gradual enough to notice any regressions we care about 
>>> and also makes it nicely bisectable and gradual.
>> You will break systems if you blindly go around disabling _p delays 
>> for ISA and LPC bus devices. The DEC Hinote laptops for example are 
>> well known for requiring the correct ISA and other keyboard controller 
>> delays. I don't expect anyone to test with a hinote or see it until it 
>> hits Debian or similar 'low resource' friendly devices.
> 
> well, using io_delay=udelay is not 'blindly disabling'.

On the other hand, the patch you just posted that makes io_delay=none the 
default _is_ blindly disabling. So that wasn't for consumption?

io_delay=udelay additionally blindly disables the race-hiding effect the 
outb has on SMP and that Alan is seeing so many of. Should also wait for 
more driver review.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:40         ` Linus Torvalds
  2007-12-30 20:34           ` Ingo Molnar
@ 2007-12-30 21:13           ` Alan Cox
  2007-12-31 15:29             ` Christer Weinigel
  2007-12-31 13:21           ` Pavel Machek
  2 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 21:13 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, Ingo Molnar, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

> But that does't mean that other ports won't have the same timings. Also, 
> it doesn't mean that we really need to have exactly *those* timings.

For ISA bus you want "at least" those timings. That is an easy case
anyway - ISA bus boxes, old processors and generally no TSC so we can
fall back to 0x80 - we know from 15 years experience the problem only
occurs with recent non ISA systems that have borked firmware.

Lots of ISA hardware does really need the delays and most of it will be
on old processors as well naturally enough.

> I also think that the worries about PCI write posting are unnecessary. IO 
> port accesses (ie a regular "inb()" and "outb()" even _without_ the "_p()" 
> format slowdown) are already synchronous not only by the CPU but by all 

Ok then the SCSI examples should be fine (although as I said I think they
are possibly bogus anyway)

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:00                   ` Linus Torvalds
  2007-12-30 20:09                     ` Rene Herman
@ 2007-12-30 21:20                     ` David P. Reed
  2007-12-30 21:36                       ` Alan Cox
  1 sibling, 1 reply; 186+ messages in thread
From: David P. Reed @ 2007-12-30 21:20 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, Alan Cox, Ingo Molnar, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

I am so happy that there will be a way for people who don't build their 
own kernels to run Linux on their HP and Compaq laptops that have 
problems with gazillions of writes to port 80, and I'm also happy that 
some of the strange driver code will be cleaned up over time.  Thank you 
all.  Some thoughts you all might consider, take or leave, in this 
process, from an old engineering manager who once had to worry about QA 
for software on nearly every personal computer model in the 1980-1992 
period:

You know, there is a class of devices that are defined to use port 
0x80...  it's that historically useful class of devices that show/record 
the POST diagnostics.   It certainly was not designed for "delay" 
purposes.   In fact, some of those same silly devices are still used in 
industry during manufacturing test.   I wonder what would happen if 
Windows were not part of manufacturing test, and instead Linux were the 
"standard" for some category of machines...

When I was still working at Lotus in the late '80's, when we still 
supported machines like 286's, there were lots of problems with timing 
loops in drivers in applications (even Win 3.0 had some in hard disk 
drivers, as did some of our printer drivers, ...), as clock speeds 
continued to ramp.  There were major news stories of machines that 
"crashed when xyz application or zyx peripheral were added".  It was 
Intel, as I recall, that started "publicly" berating companies in the PC 
industry for using the "two short jumps" solutions, and suggesting that 
they measure the processor speed at bootup, using the BIOS standard for 
doing that with the int 15 BIOS elapsed time calls, and always use 
"calibrated" timing loops.   Which all of us who supported device 
drivers started to do  (remember, apps had device drivers in those days 
for many devices that talked directly with the registers).

I was impressed when I dug into Linux eventually, that this operating 
system "got it right" by measuring the timing during boot and creating a 
udelay function that really worked!

So I have to say, that when I was tracing down the problem that 
originally kicked off this thread, which was that just accessing the RTC 
using the standard CMOS_READ macros in a loop caused a hang, that these 
"outb al,80h" things were there.   And I noticed your skeptical comment 
in the code, Linus.  Knowing that there was never in any of the 
documented RTC chipsets a need for a pause between accesses (going back 
to my days at Software Arts working on just about every old machine 
there was...) I changed it on a lark to do no pause at all.   And my 
machine never hung...

Now what's interesting is that the outb to port 80 is *faster* than an 
outb to an unused port, on my machine.  So there's something there - 
actually accepting the bus transaction.   In the ancient 5150 PC, 80 was 
unused because it was the DMA controller port that drove memory refresh, 
and had no meaning.

Now my current hypothesis (not having access to quanta's design specs 
for a board they designed and have shipped in quantity, or having taken 
the laptop apart recently) is that there is logic there on port 80, 
doing something.  Perhaps even "POST diagnostic recording" as every PC 
since the XT has supported... perhaps supporting post-crash 
dignostics...   And that that something has a buffer, perhaps even in 
the "Embedded Controller" that may need emptying periodically.   It 
takes several tens of thousands of "outb" to port 80 to hang the 
hardware solid - so something is either rare or overflowing.  In any 
case, if this hypothesis is correct - the hardware may have an erratum, 
but the hardware is doing a very desirable thing - standardizing on an 
error mechanism that was already in the "standard" as an option...  It's 
Linux that is using a "standard" in a wrong way (a diagnostic port as a 
delay).

So I say all this, mainly to point out that Linux has done timing loops 
right (udelay and ndelay) - except one place where there was some 
skepticism expressed, right there in the code.   Linus may have some 
idea why it was thought important to do an essential delay with a bus 
transaction that had uncertain timing.   My hypothesis is that 
"community" projects have the danger of "magical theories" and 
"coolness" overriding careful engineering design practices.

Cleaning up that "clever hack" that seemed so good at the time is hugely 
difficult, especially when the driver writer didn't write down why he 
used it.  

Thus I would suggest that the _p functions be deprecated, and if there 
needs to be a timing-delay after in/out instructions, define 
in_pause(port, nsec_delay) with an explicit delay.   And if the delay is 
dependent on bus speeds, define a bus-speed ratio calibration.

Thus in future driver writing, people will be forced to think clearly 
about what the timing characteristics of their device on its bus must 
be.   That presupposes that driver writers understand the timing 
issues.   If they do not, they should not be writing drivers.






^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:07                   ` Rene Herman
@ 2007-12-30 21:25                     ` Ingo Molnar
  0 siblings, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 21:25 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, Linus Torvalds, dpreed, Islam Amer, hpa, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel


* Rene Herman <rene.herman@keyaccess.nl> wrote:

> On 30-12-07 21:46, Ingo Molnar wrote:
>> * Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>>
>>>> So the current plan is to go with an io_delay=udelay default in v2.6.25, 
>>>> to give this a migration window, and io_delay=none in v2.6.26 [and a 
>>>> complete removal of arch/x86/kernel/io_delay.c], once the _p() uses are 
>>>> fixed up. This is gradual enough to notice any regressions we care about 
>>>> and also makes it nicely bisectable and gradual.
>>> You will break systems if you blindly go around disabling _p delays for 
>>> ISA and LPC bus devices. The DEC Hinote laptops for example are well 
>>> known for requiring the correct ISA and other keyboard controller delays. 
>>> I don't expect anyone to test with a hinote or see it until it hits 
>>> Debian or similar 'low resource' friendly devices.
>>
>> well, using io_delay=udelay is not 'blindly disabling'.
>
> On the other hand, the patch you just posted that makes io_delay=none 
> the default _is_ blindly disabling. So that wasn't for consumption?

if you want to see the current x86.git intention then do:

 git-clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6.git
 cd linux-2.6.git
 git-branch x86
 git-checkout x86
 git-pull git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git mm

right now the default is io_delay=udelay.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:34           ` Ingo Molnar
@ 2007-12-30 21:28             ` Alan Cox
  2007-12-30 21:54               ` Ingo Molnar
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 21:28 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> fact even io_delay=udelay would be wrong because any problem will be 
> less clearly triggerable and thus less bisectable/debuggable.

And if this eats someones disk because you drive the hardware out of spec
you are going to sit there and tell them to bisect it ? Lovely. 

Ingo - put the christmas wine away and have a coffee. Now think first.
You won't bisect obscure timing triggered problems, and the _p users are
almost all for hardware where performance doesn't matter one iota (eg
CMOS).

This isn't even all down to the chipset internal logic - several of my
boxes have external CMOS NVRAM/RTC chips which are probably the same
design (if a little smaller) as ten years ago.

io_delay = none is exactly the same thing as CPU overclocking. Hard to
debug, unpredictable and stupid.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:46                 ` Ingo Molnar
  2007-12-30 21:07                   ` Rene Herman
@ 2007-12-30 21:29                   ` Alan Cox
  2007-12-30 22:03                     ` Ingo Molnar
  2007-12-31 13:11                   ` Pavel Machek
  2 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 21:29 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rene Herman, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On Sun, 30 Dec 2007 21:46:50 +0100
Ingo Molnar <mingo@elte.hu> wrote:

> well, using io_delay=udelay is not 'blindly disabling'. io_delay=none 
> would be the end goal, once all _p() API uses are eliminated by 
> transformation. 

io_delay = none is not the end goal. Correctness is the end goal.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:20                     ` David P. Reed
@ 2007-12-30 21:36                       ` Alan Cox
  2007-12-30 23:14                         ` David P. Reed
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 21:36 UTC (permalink / raw)
  To: David P. Reed
  Cc: Linus Torvalds, Rene Herman, Ingo Molnar, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> Now what's interesting is that the outb to port 80 is *faster* than an 
> outb to an unused port, on my machine.  So there's something there - 
> actually accepting the bus transaction.   In the ancient 5150 PC, 80 was 

Yes and I even told you a while back how to verify where it is. From the
timing you get its not on the LPC bus but chipset core so pretty
certainly an SMM trap as other systems with the same chipset don't have
the bug. Probably all that is needed is a BIOS upgrade

Alan



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:28             ` Alan Cox
@ 2007-12-30 21:54               ` Ingo Molnar
  0 siblings, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 21:54 UTC (permalink / raw)
  To: Alan Cox
  Cc: Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> You won't bisect obscure timing triggered problems, and the _p users 
> are almost all for hardware where performance doesn't matter one iota 
> (eg CMOS).

actually, people have, and i have too. But i agree that io_delay=none 
would be stupid now, and would probably be stupid in v2.6.26 too.

i also have a debug patch that counts the number of _p() API uses and 
prints a stacktrace (once per bootup) if it occurs [wrote it 2 weeks 
ago] - so i agree with you that we can do this more gradually and more 
intelligently. As long as it does not turn into a BKL situation. It's 
2008 in a day and we've still got the NFS client code running under the 
BKL - quite ridiculous IMO.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:29                   ` Alan Cox
@ 2007-12-30 22:03                     ` Ingo Molnar
  0 siblings, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 22:03 UTC (permalink / raw)
  To: Alan Cox
  Cc: Rene Herman, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> On Sun, 30 Dec 2007 21:46:50 +0100
> Ingo Molnar <mingo@elte.hu> wrote:
> 
> > well, using io_delay=udelay is not 'blindly disabling'. io_delay=none 
> > would be the end goal, once all _p() API uses are eliminated by 
> > transformation. 
> 
> io_delay = none is not the end goal. Correctness is the end goal.

the end goal will be for io_delay=none to be a NOP, because nothing will 
use the _p() ops anymore.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:36                       ` Alan Cox
@ 2007-12-30 23:14                         ` David P. Reed
  2007-12-31  0:23                           ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: David P. Reed @ 2007-12-30 23:14 UTC (permalink / raw)
  To: Alan Cox
  Cc: Linus Torvalds, Rene Herman, Ingo Molnar, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

Alan Cox wrote:
>> Now what's interesting is that the outb to port 80 is *faster* than an 
>> outb to an unused port, on my machine.  So there's something there - 
>> actually accepting the bus transaction.   In the ancient 5150 PC, 80 was 
>>     
>
> Yes and I even told you a while back how to verify where it is. From the
> timing you get its not on the LPC bus but chipset core so pretty
> certainly an SMM trap as other systems with the same chipset don't have
> the bug. Probably all that is needed is a BIOS upgrade
>
>   
Actually, I could see whether it was SMM trapping due to AMD MSR's that 
would allow such trapping, performance or debug registers.  Nothing was 
set to trap with SMI or other traps on any port outputs.   But I'm 
continuing to investigate for a cause.  It would be nice if it were a 
BIOS-fixable problem.  It would be even nicer if the BIOS were GPL...

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 23:14                         ` David P. Reed
@ 2007-12-31  0:23                           ` H. Peter Anvin
  2007-12-31 11:59                             ` Alan Cox
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-31  0:23 UTC (permalink / raw)
  To: David P. Reed
  Cc: Alan Cox, Linus Torvalds, Rene Herman, Ingo Molnar, Islam Amer,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

David P. Reed wrote:
> Alan Cox wrote:
>>> Now what's interesting is that the outb to port 80 is *faster* than 
>>> an outb to an unused port, on my machine.  So there's something there 
>>> - actually accepting the bus transaction.   In the ancient 5150 PC, 
>>> 80 was     
>>
>> Yes and I even told you a while back how to verify where it is. From the
>> timing you get its not on the LPC bus but chipset core so pretty
>> certainly an SMM trap as other systems with the same chipset don't have
>> the bug. Probably all that is needed is a BIOS upgrade
>>
>>   
> Actually, I could see whether it was SMM trapping due to AMD MSR's that 
> would allow such trapping, performance or debug registers.  Nothing was 
> set to trap with SMI or other traps on any port outputs.   But I'm 
> continuing to investigate for a cause.  It would be nice if it were a 
> BIOS-fixable problem.  It would be even nicer if the BIOS were GPL...

If it was an SMM trap, I would expect it to be trapped in the SuperIO chip.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:50           ` H. Peter Anvin
@ 2007-12-31  1:03             ` David P. Reed
  2007-12-31  1:40               ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: David P. Reed @ 2007-12-31  1:03 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Juergen Beisert, linux-kernel, Alan Cox, Ingo Molnar,
	Linus Torvalds, Rene Herman, Islam Amer, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner



H. Peter Anvin wrote:
> Now, I think there is a specific reason to believe that EGA/VGA (but 
> perhaps not CGA/MDA) didn't need these kinds of hacks: the video cards 
> of the day was touched, directly, by an interminable number of DOS 
> applications.  CGA/MDA generally *were not*, due to the unsynchronized 
> memory of the original versions (writing could cause snow), so most 
> applications tended to fall back to using the BIOS access methods for 
> CGA and MDA.
>
A little history... not that it really matters, but some might be 
interested in a 55-year-old hacker's sentimental recollections...As 
someone who actually wrote drivers for CGA and MDA on the original IBM 
PC, I can tell you that back to back I/O *port* writes and reads were 
perfectly fine.  The "snow" problem had nothing to do with I/O ports.  
It had to do with the memory on the CGA adapter card not being dual 
ported, and in high-res (80x25) character mode (only!) a CPU read or 
write access caused a read of the adapter memory by the 
character-generator to fail, causing one character-position of the 
current scanline being output to get all random bits, which was then put 
through the character-generator and generated whatever the character 
generator did with 8 random bits of character or attributes as an index 
into the character generator's font table.

In particular, the solution in both the BIOS and in Visicalc, 1-2-3, and 
other products that did NOT use the BIOS or DOS for I/O to the CGA or 
MDA because they were Dog Slow, was to detect the CGA, and do a *very* 
tight loop doing "inb" instructions from one of the CGA status 
registers, looking for a 0-1 transition on the horizontal retrace flag.  
It would then do a write to display memory with all interrupts locked 
out, because that was all it could do during the horizontal retrace, 
given the speed of the processor.  One of the hacks I did in those days 
(I wrote the CGA driver for Visicalc Advanced Version and several other 
Software Arts programs, some of which were sold to Lotus when they 
bought our assets, and hired me, in 1985) was to measure the "horizontal 
retrace time" and the "vertical blanking interval" when the program 
started, and compile screen-writing code that squeezed as many writes as 
possible into both horizontal retraces and vertical retraces.   That was 
actually a "selling point" for spreadsheets - the reviewers actually 
measured whether you could use the down-arrow key in auto-repeat mode 
and keep the screen scrolling at the relevant rate!  That was hard on an 
8088 or 80286 processor, with a CGA card.

It was great when EGA and VGA came out, but we still had to support the 
CGA long after.  Which is why I fully understand the need not to break 
old machines.  We had to run on every machine that was claimed to be "PC 
compatible" - many of which were hardly so compatible  (the PS/2 model 
50 had a completely erroneous serial chip that claimed to emulate the 
original 8250, but had an immense pile of bugs, for example, that IBM 
begged ISVs to call a software problem and fix so they didn't get sued).

The IBM PC bus (predecessor of the current ISA bus, which came from the 
PC-AT's 16-bit bus), did just fine electrically - any I/O port-specific 
timing problems had to do with the timing of the chips attached to the 
bus.  For example, if a bus write to a port was routed into a particular 
chip, the timing of that chip's subsequent processing might be such that 
it was not ready to respond to another read or write.)  That's not a 
"signalling" problem - it has nothing to do with capacitance on the bus, 
e.g., but a functional speed problem in the chip (if on the motherboard) 
or the adapter card.

Rant off.  This has nothing, of course, to do with present issues.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31  1:03             ` David P. Reed
@ 2007-12-31  1:40               ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-31  1:40 UTC (permalink / raw)
  To: David P. Reed
  Cc: Juergen Beisert, linux-kernel, Alan Cox, Ingo Molnar,
	Linus Torvalds, Rene Herman, Islam Amer, Pavel Machek,
	Ingo Molnar, Andi Kleen, Thomas Gleixner

David P. Reed wrote:
> 
> 
> H. Peter Anvin wrote:
>> Now, I think there is a specific reason to believe that EGA/VGA (but 
>> perhaps not CGA/MDA) didn't need these kinds of hacks: the video cards 
>> of the day was touched, directly, by an interminable number of DOS 
>> applications.  CGA/MDA generally *were not*, due to the unsynchronized 
>> memory of the original versions (writing could cause snow), so most 
>> applications tended to fall back to using the BIOS access methods for 
>> CGA and MDA.
>>
> A little history... not that it really matters, but some might be 
> interested in a 55-year-old hacker's sentimental recollections...As 
> someone who actually wrote drivers for CGA and MDA on the original IBM 
> PC, I can tell you that back to back I/O *port* writes and reads were 
> perfectly fine.  The "snow" problem had nothing to do with I/O ports.  
> It had to do with the memory on the CGA adapter card not being dual 
> ported, and in high-res (80x25) character mode (only!) a CPU read or 
> write access caused a read of the adapter memory by the 
> character-generator to fail, causing one character-position of the 
> current scanline being output to get all random bits, which was then put 
> through the character-generator and generated whatever the character 
> generator did with 8 random bits of character or attributes as an index 
> into the character generator's font table.
> 

[Additional history snipped]

This is all true of course (and a useful history lesson to those not 
familiar with it) but what I wrote above is still true: due to the lack 
of synchronized memory (it doesn't have to be dual-ported, just 
synchronized, if it has enough bandwidth), most DOS applications *in the 
i386+ timeframe* just invoked the BIOS rather than dealing with the 
synchronization needs themselves (anything compiled with a Borland 
compiler using their conio library, for example.)

Hence the variety of software that poked directly at CGA/MDA as opposed 
to EGA/VGA was smaller, but I never claimed it was uncommon.

	-hpa



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31  0:23                           ` H. Peter Anvin
@ 2007-12-31 11:59                             ` Alan Cox
  2007-12-31 18:19                               ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-31 11:59 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: David P. Reed, Linus Torvalds, Rene Herman, Ingo Molnar,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

On Sun, 30 Dec 2007 16:23:20 -0800
"H. Peter Anvin" <hpa@zytor.com> wrote:

> > continuing to investigate for a cause.  It would be nice if it were a 
> > BIOS-fixable problem.  It would be even nicer if the BIOS were GPL...
> 
> If it was an SMM trap, I would expect it to be trapped in the SuperIO chip.

Many SuperIO chips do port 0x80, but they do it over the LPC and they do
it in hardware to the parallel port data lines. The timings posted for
0x80 on his box are really a bit fast for LPC.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:14             ` Rene Herman
  2007-12-30 18:39               ` Alan Cox
@ 2007-12-31 12:23               ` Alan Cox
  2007-12-31 14:35                 ` Rene Herman
  1 sibling, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-31 12:23 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On Sun, 30 Dec 2007 19:14:40 +0100
Rene Herman <rene.herman@keyaccess.nl> wrote:

> On 30-12-07 17:48, Alan Cox wrote:
> 
> > For processors with TSC I think we should aim for 2.6.25 to do this and 
> > to have the major other _p fixups done. I pity whoever does stuff like 
> > the scc drivers but most of the rest isn't too bad.
> 
> I'm by the way looking at drivers/net/wd.c which my 386 uses for its dual 
> mode NE2000/WD8013 clone ISA NIC and while it specifically needs no delay at 
> all it seems, the mixed use of out and outb_p seems to suggest that someone 
> once thought about that. Would you advice sticking in a udelay(2) manually 
> there?

I dug out the reference drivers. The reference drivers use the delay and
the 8390 datasheet confirms it is neccessary.

The Crynwr driver has some interesting things to say

| The National 8390 Chip (NIC) requires 4 bus clocks between successive
| chip selects (National DP8390 Data Sheet Addendum, June 1990)

Also " To establish a minimum delay, an I/O instruction must be used. A
good rule of ; thumb is that ISA I/O instructions take ~1.0 microseconds
and MCA I/O ; instructions take ~0.5 microseconds. Reading the NMI Status
Register (0x61) ; is a good way to pause on all machines."

But all the official drivers use pauses and the manual says they are
needed for correct, reliable behaviour - at least with a genuine 8390.





^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 13:21           ` Pavel Machek
@ 2007-12-31 12:29             ` Alan Cox
  0 siblings, 0 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-31 12:29 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Linus Torvalds, Rene Herman, Ingo Molnar, dpreed, Islam Amer,
	hpa, Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

> "You plug in PCI DEBUG card and it overclocks your machine" is bad
> scenario.. (I don't know if it does... can PCI card emulate ISA timings?)

Easily. Its a bit more restricted by later spec revisions but it can halt
your box of a week or two if it wants. Video cards used to pull this
stunt for marketing benchmark numbers.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:46                 ` Ingo Molnar
  2007-12-30 21:07                   ` Rene Herman
  2007-12-30 21:29                   ` Alan Cox
@ 2007-12-31 13:11                   ` Pavel Machek
  2008-01-01 16:48                     ` Ingo Molnar
  2 siblings, 1 reply; 186+ messages in thread
From: Pavel Machek @ 2007-12-31 13:11 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, Rene Herman, Linus Torvalds, dpreed, Islam Amer, hpa,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

On Sun 2007-12-30 21:46:50, Ingo Molnar wrote:
> 
> * Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
> 
> > > So the current plan is to go with an io_delay=udelay default in v2.6.25, 
> > > to give this a migration window, and io_delay=none in v2.6.26 [and a 
> > > complete removal of arch/x86/kernel/io_delay.c], once the _p() uses are 
> > > fixed up. This is gradual enough to notice any regressions we care about 
> > > and also makes it nicely bisectable and gradual.
> > 
> > You will break systems if you blindly go around disabling _p delays 
> > for ISA and LPC bus devices. The DEC Hinote laptops for example are 
> > well known for requiring the correct ISA and other keyboard controller 
> > delays. I don't expect anyone to test with a hinote or see it until it 
> > hits Debian or similar 'low resource' friendly devices.
> 
> well, using io_delay=udelay is not 'blindly disabling'. io_delay=none 
> would be the end goal, once all _p() API uses are eliminated by 
> transformation. In drivers/ alone that's more than 1000 callsites, so 
> it's quite frequently used, and wont go away overnight.

IOW elimination of broken inb_p()/outb_p() interfaces is the ultimate
goal. Agreed.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:40         ` Linus Torvalds
  2007-12-30 20:34           ` Ingo Molnar
  2007-12-30 21:13           ` Alan Cox
@ 2007-12-31 13:21           ` Pavel Machek
  2007-12-31 12:29             ` Alan Cox
  2 siblings, 1 reply; 186+ messages in thread
From: Pavel Machek @ 2007-12-31 13:21 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Rene Herman, Ingo Molnar, Alan Cox, dpreed, Islam Amer, hpa,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel

Hi!

> > rene@7ixe4:~/src/port80$ su -c ./port80
> > cycles: out 2400, in 2401
> > rene@7ixe4:~/src/port80$ su -c ./port3cc
> > cycles: out 459, in 394
> > 
> > As stated a few dozen times by now already, port 0x80 is _decidedly_ _non_
> > _random_
> 
> Oh, I agree 100% that port 80 is not random. It's very much selected on 
> purpose.
> 
> The reason we use port 80 is because it's commonly used as the BIOS POST 
> debug port, which means that it's been a reasonable "safe" port to use, 
> since nobody would be so crazy as to actually hook up a real device behind 
> that port (and since it is below 0x100, it's also part of the "motherboard 
> range", so you won't have any crazy plug-in devices either).

Eh?

I have two mainboards here that have debug displays hooked to port
0x80. I have PCI DEBUG card that has display on port 0x80.

"You plug in PCI DEBUG card and it overclocks your machine" is bad
scenario.. (I don't know if it does... can PCI card emulate ISA timings?)
								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 12:23               ` Alan Cox
@ 2007-12-31 14:35                 ` Rene Herman
  2007-12-31 15:56                   ` Alan Cox
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-31 14:35 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

[-- Attachment #1: Type: text/plain, Size: 1628 bytes --]

On 31-12-07 13:23, Alan Cox wrote:

> I dug out the reference drivers. The reference drivers use the delay and
> the 8390 datasheet confirms it is neccessary.

Great, thanks for that.

> The Crynwr driver has some interesting things to say
> 
> | The National 8390 Chip (NIC) requires 4 bus clocks between successive
> | chip selects (National DP8390 Data Sheet Addendum, June 1990)

Okay, that's pretty specific. Given that these things exist on actual ISA 
cards and "I/O recovery time" BIOS settings that are availabe also on these 
old 386s already it's probably still at least somewhat debatable how much 
linux drivers really need to care even in this case -- but let's ignore that.

> Also " To establish a minimum delay, an I/O instruction must be used. A
> good rule of ; thumb is that ISA I/O instructions take ~1.0 microseconds
> and MCA I/O ; instructions take ~0.5 microseconds. Reading the NMI Status
> Register (0x61) ; is a good way to pause on all machines."
> 
> But all the official drivers use pauses and the manual says they are
> needed for correct, reliable behaviour - at least with a genuine 8390.

Okay. Am about to go stuff my face with new years celebrations but will 
definitely try to make that old WD8003 hickup.

By the way, expected, but before anyone else mentions it -- no, reading from 
port 0x61 is not a reliable delay today. Duron 1300 / AMD756:

rene@7ixe4:~/src/port80$ su -c ./portime
out 0x80: 2400 cycles
in  0x80: 2400 cycles
in  0x61: 2400 cycles

But PII 400 / Intel 440BX:

rene@6bap:~/port80$ su -c ./portime
out 0x80: 545 cycles
in  0x80: 254 cycles
in  0x61: 254 cycles

Rene.

[-- Attachment #2: portime.c --]
[-- Type: text/plain, Size: 1274 bytes --]

/* gcc -W -Wall -O2 -o portime portime.c */

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include <sys/io.h>

#define LOOPS 10000

inline uint64_t rdtsc(void)
{
	uint32_t hi, lo;

	asm ("rdtsc": "=d" (hi), "=a" (lo));

	return (uint64_t)hi << 32 | lo;
}

inline void serialize(void)
{
	asm ("cpuid": : : "eax", "ebx", "ecx", "edx");
}

int main(void)
{
	uint64_t tsc0, tsc1, tsc2, tsc3, tsc4;
	uint64_t out, in8, in6;
	int i;

	if (iopl(3) < 0) {
		perror("iopl");
		return EXIT_FAILURE;
	}

	asm ("cli");
	tsc0 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
	 	serialize();	
		serialize();
	}
	tsc1 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("outb %al, $0x80");
		serialize();
	}
	tsc2 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("inb $0x80, %%al": : : "al");
		serialize();
	}
	tsc3 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("inb $0x61, %%al": : : "al");
		serialize();
	}
	tsc4 = rdtsc();
	asm ("sti");

	out = ((tsc2 - tsc1) - (tsc1 - tsc0)) / LOOPS;
	in8 = ((tsc3 - tsc2) - (tsc1 - tsc0)) / LOOPS;
	in6 = ((tsc4 - tsc3) - (tsc1 - tsc0)) / LOOPS;

	printf("out 0x80: %llu cycles\n", out);
	printf("in  0x80: %llu cycles\n", in8);
	printf("in  0x61: %llu cycles\n", in6);

	return EXIT_SUCCESS;
}

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:13           ` Alan Cox
@ 2007-12-31 15:29             ` Christer Weinigel
  0 siblings, 0 replies; 186+ messages in thread
From: Christer Weinigel @ 2007-12-31 15:29 UTC (permalink / raw)
  To: Alan Cox
  Cc: Linus Torvalds, Rene Herman, Ingo Molnar, dpreed, Islam Amer,
	hpa, Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On Sun, 30 Dec 2007 21:13:29 +0000
Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > But that does't mean that other ports won't have the same timings.
> > Also, it doesn't mean that we really need to have exactly *those*
> > timings.
> 
> For ISA bus you want "at least" those timings. That is an easy case
> anyway - ISA bus boxes, old processors and generally no TSC so we can
> fall back to 0x80 - we know from 15 years experience the problem only
> occurs with recent non ISA systems that have borked firmware.
> 
> Lots of ISA hardware does really need the delays and most of it will
> be on old processors as well naturally enough.

If I recall correctly, the MediaGX/Geode processor does need _p for the
PIT accesses, and that CPU family does have a TSC (even though the TSC
stops at times so is hard to use).  I also seem to remember that the
breakage did not happen very often, but running a system without _p
overnight usually showed one hiccup where a read from the counter got
corrupted.

So unless I'm wrong (which I very well could be, it's been a couple of
years since I was debugging the PIT code on a misbehaving Geode SC1200
based system) there is at least one fairly modern CPU, which is used in
lots of embedded systems, and in active use, which does need the _p.

Just a data point... It's not only ancient systems that need _p.

  /Christer

-- 
"Just how much can I get away with and still go to heaven?"

Christer Weinigel <christer@weinigel.se>  http://www.weinigel.se

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 14:35                 ` Rene Herman
@ 2007-12-31 15:56                   ` Alan Cox
  2007-12-31 20:22                     ` Ondrej Zary
  2008-01-02  3:01                     ` Rene Herman
  0 siblings, 2 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-31 15:56 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> Okay. Am about to go stuff my face with new years celebrations but will 
> definitely try to make that old WD8003 hickup.

Have fun. Is it an 8390 or an 83905 ?

> By the way, expected, but before anyone else mentions it -- no, reading from 
> port 0x61 is not a reliable delay today. Duron 1300 / AMD756:

No big suprise - the comment is from about 1992.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 11:59                             ` Alan Cox
@ 2007-12-31 18:19                               ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-31 18:19 UTC (permalink / raw)
  To: Alan Cox
  Cc: David P. Reed, Linus Torvalds, Rene Herman, Ingo Molnar,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Alan Cox wrote:
> On Sun, 30 Dec 2007 16:23:20 -0800
> "H. Peter Anvin" <hpa@zytor.com> wrote:
> 
>>> continuing to investigate for a cause.  It would be nice if it were a 
>>> BIOS-fixable problem.  It would be even nicer if the BIOS were GPL...
>> If it was an SMM trap, I would expect it to be trapped in the SuperIO chip.
> 
> Many SuperIO chips do port 0x80, but they do it over the LPC and they do
> it in hardware to the parallel port data lines. The timings posted for
> 0x80 on his box are really a bit fast for LPC.

Ah, that would eliminate the SuperIO chip.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 15:56                   ` Alan Cox
@ 2007-12-31 20:22                     ` Ondrej Zary
  2007-12-31 21:25                       ` Alan Cox
  2008-01-02  3:01                     ` Rene Herman
  1 sibling, 1 reply; 186+ messages in thread
From: Ondrej Zary @ 2007-12-31 20:22 UTC (permalink / raw)
  To: Alan Cox
  Cc: Rene Herman, Ingo Molnar, Linus Torvalds, dpreed, Islam Amer,
	hpa, Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On Monday 31 December 2007 16:56:00 Alan Cox wrote:
> > Okay. Am about to go stuff my face with new years celebrations but will
> > definitely try to make that old WD8003 hickup.
>
> Have fun. Is it an 8390 or an 83905 ?
>

What about HP PCLan 16/TP+ cards? I have one that runs 24/7 in a 486 box 
(2.6.20.6 kernel) and one spare. It has some VLSI HP chip and also ST-NIC 
DP83902AV - is that a good candidate for testing?

I also have WD8013EP with DP8390DV chip - that's probably even better.

-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 20:22                     ` Ondrej Zary
@ 2007-12-31 21:25                       ` Alan Cox
  2007-12-31 21:47                         ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-31 21:25 UTC (permalink / raw)
  To: Ondrej Zary
  Cc: Rene Herman, Ingo Molnar, Linus Torvalds, dpreed, Islam Amer,
	hpa, Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

> What about HP PCLan 16/TP+ cards? I have one that runs 24/7 in a 486 box 
> (2.6.20.6 kernel) and one spare. It has some VLSI HP chip and also ST-NIC 
> DP83902AV - is that a good candidate for testing?

What are you trying to test. The documentation explicitly says you need
the delays and that the delays are in bus clocks not microseconds. That
means the existing code is correct and it needs a delay dependant on the
ISA bus clock frequency (somewhere between 6 and 12MHz). Note that the
delay depends on the bus clock frequency not time.

We don't do overclocking, we don't support overclocking, please do not
overclock your ethernet chip.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 21:25                       ` Alan Cox
@ 2007-12-31 21:47                         ` H. Peter Anvin
  2007-12-31 23:24                           ` Alan Cox
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-31 21:47 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ondrej Zary, Rene Herman, Ingo Molnar, Linus Torvalds, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Alan Cox wrote:
>> What about HP PCLan 16/TP+ cards? I have one that runs 24/7 in a 486 box 
>> (2.6.20.6 kernel) and one spare. It has some VLSI HP chip and also ST-NIC 
>> DP83902AV - is that a good candidate for testing?
> 
> What are you trying to test. The documentation explicitly says you need
> the delays and that the delays are in bus clocks not microseconds. That
> means the existing code is correct and it needs a delay dependant on the
> ISA bus clock frequency (somewhere between 6 and 12MHz). Note that the
> delay depends on the bus clock frequency not time.
> 
> We don't do overclocking, we don't support overclocking, please do not
> overclock your ethernet chip.
> 

However, assuming a bus clock of 6 MHz should be safe (167 ns).

4 bus clocks would be 667 ns, or we can round it up to 1 ms to deal with 
bus delay effects.

None of this really helps with *memory-mapped* 8390, though, since 
memory mapped writes can be posted.  Putting any IOIO transaction in the 
middle has the effect of flushing the posting queues; an MMIO read would 
   also work.  The WD80x3 cards were memory-mapped, in particular (and 
were some of the very first cards supported by Linux.)

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 21:47                         ` H. Peter Anvin
@ 2007-12-31 23:24                           ` Alan Cox
  2007-12-31 23:41                             ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-31 23:24 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ondrej Zary, Rene Herman, Ingo Molnar, Linus Torvalds, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

> However, assuming a bus clock of 6 MHz should be safe (167 ns).

Agreed - or ISA timings directly. Boxes using WD80x3 are not going to
have a TSC so might as well stick with port 0x80 as they have done just
fine for the past 15 years.

> None of this really helps with *memory-mapped* 8390, though, since 
> memory mapped writes can be posted.  Putting any IOIO transaction in the 

ISA isn't posted only PCI.

PCI 8390 clones seem to be a mix of ASICs and 8390x chips with
some quite disgusting FPGA glue logic.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 23:24                           ` Alan Cox
@ 2007-12-31 23:41                             ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-31 23:41 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ondrej Zary, Rene Herman, Ingo Molnar, Linus Torvalds, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Alan Cox wrote:
>> However, assuming a bus clock of 6 MHz should be safe (167 ns).
> 
> Agreed - or ISA timings directly. Boxes using WD80x3 are not going to
> have a TSC so might as well stick with port 0x80 as they have done just
> fine for the past 15 years.
> 
>> None of this really helps with *memory-mapped* 8390, though, since 
>> memory mapped writes can be posted.  Putting any IOIO transaction in the 
> 
> ISA isn't posted only PCI.
> 
> PCI 8390 clones seem to be a mix of ASICs and 8390x chips with
> some quite disgusting FPGA glue logic.
> 

ISA isn't posted no, but on several chipsets the upstream PCI bus will 
post MMIO writes to ISA space regardless of the spec.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 13:11                   ` Pavel Machek
@ 2008-01-01 16:48                     ` Ingo Molnar
  0 siblings, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2008-01-01 16:48 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Alan Cox, Rene Herman, Linus Torvalds, dpreed, Islam Amer, hpa,
	Ingo Molnar, Andi Kleen, Thomas Gleixner, Linux Kernel


* Pavel Machek <pavel@ucw.cz> wrote:

> > well, using io_delay=udelay is not 'blindly disabling'. 
> > io_delay=none would be the end goal, once all _p() API uses are 
> > eliminated by transformation. In drivers/ alone that's more than 
> > 1000 callsites, so it's quite frequently used, and wont go away 
> > overnight.
> 
> IOW elimination of broken inb_p()/outb_p() interfaces is the ultimate 
> goal. Agreed.

yeah - although i'd not call it "broken", it's simply historic, and due 
to the side-effects of the _implementation_, a few non-standard uses 
(such as reliance on PCI posting/flushing effects) grew.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 15:56                   ` Alan Cox
  2007-12-31 20:22                     ` Ondrej Zary
@ 2008-01-02  3:01                     ` Rene Herman
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-02  3:01 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, Linus Torvalds, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

On 31-12-07 16:56, Alan Cox wrote:

>> Okay. Am about to go stuff my face with new years celebrations but will 
>> definitely try to make that old WD8003 hickup.
> 
> Have fun. Is it an 8390 or an 83905 ?

A DP8390BN. And I have a DP8390CN on a 3Com Etherlink II. The NE1000 has a 
DP83901AV, my new-fangled Networth combo WD/NE cards DP83905s.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-08  0:10                                       ` [linux-kernel] " David P. Reed
@ 2008-01-09 21:01                                         ` Matthieu castet
  0 siblings, 0 replies; 186+ messages in thread
From: Matthieu castet @ 2008-01-09 21:01 UTC (permalink / raw)
  To: linux-kernel

Hi,

David P. Reed <dpreed <at> reed.com> writes:

> And actually, if I had looked at the /sys/bus/pnp definitions, rather 
> than /proc/ioports, I would have noticed that port 80 was part of a 
> PNP0C02 resource set.   That means exactly one thing:  ACPI says that 
> port 80 is NOT free to be used, for delays or anything else.

I have some computers where port 0x80 is claimed by 8237A DMA controller [1]
But in this case it seems a lasy acpi programmer that doesn't want to convert
the hole in  0x80-0x8f range...


PS : I post from gmane web interface, so I can't keep CC.

[1]
This happen with a old 7 years old siemens PIII and a new hp core2duo.
state = active
io 0x0-0xf
io 0x80-0x8f
io 0xc0-0xdf
dma 4 


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-09 17:27                                                                 ` Maciej W. Rozycki
@ 2008-01-09 18:18                                                                   ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-09 18:18 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Rene Herman, Alan Cox, David P. Reed, Rene Herman, Ingo Molnar,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

Maciej W. Rozycki wrote:
> On Tue, 1 Jan 2008, H. Peter Anvin wrote:
> 
>> It's specifically a side effect *we don't care about*, except in the
>> by-now-somewhat-exotic case of 386+387 (where we indeed can't use it once user
>> code has touched the FPU -- but we can fall back to 0x80 on those, a very
>> small number of systems.)  486+ doesn't use this interface under Linux, since
>> Linux uses the proper exception path on those processors.  If Compaq had wired
>> up the proper signals on the first 386 PC motherboards, we wouldn't have cared
>> about it on the 386 either.
> 
>  It was actually IBM who broke it with the 80286-based PC/AT because of 
> the BIOS compatibility -- the vector #0x10 had already been claimed by the 
> original PC for the video software interrupt call (apparently against 
> Intel's recommendation not to use low 32 interrupt vectors for such 
> purposes), so it could not have been reused as is for FP exception 
> handling without breaking existing software.  I suppose a more complicated 
> piece of glue logic could have been used along the lines of what 
> eventually went into the i486, but presumably the relatively low level of 
> integration of the PC/AT made such additional circuits hard to justify 
> even if it indeed was considered.
> 

Supposedly the reason was that the DOS-less "cassette BASIC" delivered 
by Microsoft used all the INT instructions except the reserved ones as a 
weird bytecode interpreter.  Bill Gates was fond of that kind of hacks.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:44                                                               ` H. Peter Anvin
  2008-01-01 22:35                                                                 ` Rene Herman
@ 2008-01-09 17:27                                                                 ` Maciej W. Rozycki
  2008-01-09 18:18                                                                   ` H. Peter Anvin
  1 sibling, 1 reply; 186+ messages in thread
From: Maciej W. Rozycki @ 2008-01-09 17:27 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rene Herman, Alan Cox, David P. Reed, Rene Herman, Ingo Molnar,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On Tue, 1 Jan 2008, H. Peter Anvin wrote:

> It's specifically a side effect *we don't care about*, except in the
> by-now-somewhat-exotic case of 386+387 (where we indeed can't use it once user
> code has touched the FPU -- but we can fall back to 0x80 on those, a very
> small number of systems.)  486+ doesn't use this interface under Linux, since
> Linux uses the proper exception path on those processors.  If Compaq had wired
> up the proper signals on the first 386 PC motherboards, we wouldn't have cared
> about it on the 386 either.

 It was actually IBM who broke it with the 80286-based PC/AT because of 
the BIOS compatibility -- the vector #0x10 had already been claimed by the 
original PC for the video software interrupt call (apparently against 
Intel's recommendation not to use low 32 interrupt vectors for such 
purposes), so it could not have been reused as is for FP exception 
handling without breaking existing software.  I suppose a more complicated 
piece of glue logic could have been used along the lines of what 
eventually went into the i486, but presumably the relatively low level of 
integration of the PC/AT made such additional circuits hard to justify 
even if it indeed was considered.

  Maciej

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-08 13:17                               ` Bodo Eggert
@ 2008-01-08 14:38                                 ` Alan Cox
  0 siblings, 0 replies; 186+ messages in thread
From: Alan Cox @ 2008-01-08 14:38 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: Bodo Eggert, H. Peter Anvin, Christer Weinigel, Ingo Molnar,
	David P. Reed, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> As long as there is no port 80 card or a similar device using it. If 
> there is a port 80 card, ISA acess needing the delay does break

Such cards are very unusual on ISA machines and it hasn't been a problem
in fifteen years. All the alternatives are vastly higher risk

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-08 12:51                                       ` Bodo Eggert
  2008-01-08 14:09                                         ` Rene Herman
@ 2008-01-08 14:31                                         ` Alan Cox
  1 sibling, 0 replies; 186+ messages in thread
From: Alan Cox @ 2008-01-08 14:31 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: Rene Herman, H. Peter Anvin, Bodo Eggert, Christer Weinigel,
	Ingo Molnar, David P. Reed, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> OTOH, the DOS drivers I heared about use delays and would break on 
> underclocked ISA busses if the n * ISA_HZ delay was needed. Maybe
> somebody having a configurable ISA bus speed and some problematic
> chips can test it ...

I've been looking at DOS reference drivers - they almost all use I/O port
based delays.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-08 12:51                                       ` Bodo Eggert
@ 2008-01-08 14:09                                         ` Rene Herman
  2008-01-08 14:31                                         ` Alan Cox
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-08 14:09 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: H. Peter Anvin, Christer Weinigel, Ingo Molnar, Alan Cox,
	David P. Reed, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On 08-01-08 13:51, Bodo Eggert wrote:

> On Tue, 8 Jan 2008, Rene Herman wrote:

>>>> Is this only about the ones then left for things like legacy PIC and PIT?
>>>> Does anyone care about just sticking in a udelay(2) (or 1) there as a
>>>> replacement and call it a day?
>>>>
>>> PIT is problematic because the PIT may be necessary for udelay setup.
>> Yes, can initialise loops_per_jiffy conservatively. Just didn't quite get why
>> you guys are talking about an ISA bus speed parameter.
> 
> If the ISA bus is below 8 MHz, we might need a longer delay. If we default
> to the longer delay, the delay will be too long for more than 99,99 % of 
> all systems, not counting i586+. Especially if the driver is fine-tuned to 
> give maximum throughput, this may be bad.

Yes, and I repeat -- old legacy ISA drivers can stay as they are. They've 
been doing what they've been doing for 15 years and given that the systems 
that break don't use them there is no practical upside to changing them and 
a big downside particularly with respect to difficulty of testing.

A somewhat overly long delay shouldn't be particularly problematic for the 
few remaining legacy hardware users _outside_ drivers/

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 23:25                             ` Alan Cox
@ 2008-01-08 13:17                               ` Bodo Eggert
  2008-01-08 14:38                                 ` Alan Cox
  0 siblings, 1 reply; 186+ messages in thread
From: Bodo Eggert @ 2008-01-08 13:17 UTC (permalink / raw)
  To: Alan Cox
  Cc: Bodo Eggert, H. Peter Anvin, Christer Weinigel, Ingo Molnar,
	David P. Reed, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On Mon, 7 Jan 2008, Alan Cox wrote:

> > But overclocking is not the problem for udelay, it would err to the safe 
> > side. The problem would be a BUS having < 8 MHz, and since the days of 
> > 80286, they are hard to find. IMO having an option to set the bus speed
> > for those systems should be enough.
> 
> If you get it wrong you risk data corruption. Not good, not clever, not
> appropriate. Basically the use of port 0x80 is the right thing to do for
> ISA devices and as 15 odd years of use has shown works reliably and
> solidly for ISA systems.

As long as there is no port 80 card or a similar device using it. If 
there is a port 80 card, ISA acess needing the delay does break, cause
the data corruption you fear and does cause this thread to be started.
Pest, Cholera ...

OTOH, maybe the 6-MHz-delay is the same as the 8-MHz-delay, and the kernel 
parameter is not needed.
-- 
Fun things to slip into your budget
A Romulan Cloaking device:
	The PHB won't know what it is but will be to chicken to ask

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 23:26                                     ` Rene Herman
  2008-01-08  0:10                                       ` [linux-kernel] " David P. Reed
@ 2008-01-08 12:51                                       ` Bodo Eggert
  2008-01-08 14:09                                         ` Rene Herman
  2008-01-08 14:31                                         ` Alan Cox
  1 sibling, 2 replies; 186+ messages in thread
From: Bodo Eggert @ 2008-01-08 12:51 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Bodo Eggert, Christer Weinigel, Ingo Molnar,
	Alan Cox, David P. Reed, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On Tue, 8 Jan 2008, Rene Herman wrote:
> On 08-01-08 00:24, H. Peter Anvin wrote:
> > Rene Herman wrote:

> > > Is this only about the ones then left for things like legacy PIC and PIT?
> > > Does anyone care about just sticking in a udelay(2) (or 1) there as a
> > > replacement and call it a day?
> > > 
> > 
> > PIT is problematic because the PIT may be necessary for udelay setup.
> 
> Yes, can initialise loops_per_jiffy conservatively. Just didn't quite get why
> you guys are talking about an ISA bus speed parameter.

If the ISA bus is below 8 MHz, we might need a longer delay. If we default
to the longer delay, the delay will be too long for more than 99,99 % of 
all systems, not counting i586+. Especially if the driver is fine-tuned to 
give maximum throughput, this may be bad.

OTOH, the DOS drivers I heared about use delays and would break on 
underclocked ISA busses if the n * ISA_HZ delay was needed. Maybe
somebody having a configurable ISA bus speed and some problematic
chips can test it ...

-- 
Fun things to slip into your budget
"I [Meow Cat] sliped in 'Legal fees for firing Jim (Jim's my [his] boss).'
Jim approved the budget and was fired when upper management saw the budget."

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 19:38                       ` Bodo Eggert
  2008-01-07 19:46                         ` H. Peter Anvin
@ 2008-01-08  3:15                         ` Christer Weinigel
  1 sibling, 0 replies; 186+ messages in thread
From: Christer Weinigel @ 2008-01-08  3:15 UTC (permalink / raw)
  To: 7eggert
  Cc: Ingo Molnar, Alan Cox, David P. Reed, H. Peter Anvin,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On Mon, 07 Jan 2008 20:38:09 +0100
Bodo Eggert <7eggert@gmx.de> wrote:

> Christer Weinigel <christer@weinigel.se> wrote:
> 
> > How do you find out the speed of the ISA bus?  AFAIK there is no
> > standardized way to do that.  On the Geode SC2200 the ISA bus speed
> > is usually the PCI clock divided by 4 giving 33MHz/4=8.3MHz or
> > 30/4=7.5MHz, but with no external ISA devices it's possible to
> > overclock the ISA bus to /3 to run it at 11MHz or so.  But without
> > poking at some CPU and southbridge specific registers to find out
> > the PCI bus speed and the ISA bus divisor you can't really tell.
> 
> If you overclock, you are on your own. IIRC I've used 13,3 MHz for
> some time and used a lower PIO mode to compensate.

That would not be overclocking, rather that the hardware designer would
have determined that on that specific hardware design, all peripherals
are able to run at 12MHz.  

Also note that on some other system the hardware designer might have
decided to have a slower ISA clock, to save power, fulfil some EMI
requirement or whatever.

> > So if you do udelay based on a 6MHz clock (I think you can safely
> > assume that any 386 based system runs the ISA bus at least that
> > fast) you'll waste at least 30% and maybe even 100% more time for
> > the delay after every _p call.
> 
> Defaulting to 8 MHz and offering an option to set another clock speed
> (like idebus=) should be OK.

Sounds like a big regression to have to start using a command line
option, when the current state of affairs is "it just works".

  /Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 23:24                                   ` H. Peter Anvin
@ 2008-01-07 23:26                                     ` Rene Herman
  2008-01-08  0:10                                       ` [linux-kernel] " David P. Reed
  2008-01-08 12:51                                       ` Bodo Eggert
  0 siblings, 2 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-07 23:26 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Bodo Eggert, Christer Weinigel, Ingo Molnar, Alan Cox,
	David P. Reed, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On 08-01-08 00:24, H. Peter Anvin wrote:

> Rene Herman wrote:
>>
>> Is this only about the ones then left for things like legacy PIC and 
>> PIT? Does anyone care about just sticking in a udelay(2) (or 1) there 
>> as a replacement and call it a day?
>>
> 
> PIT is problematic because the PIT may be necessary for udelay setup.

Yes, can initialise loops_per_jiffy conservatively. Just didn't quite get 
why you guys are talking about an ISA bus speed parameter.

Rene.


Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 22:02                           ` Bodo Eggert
  2008-01-07 22:10                             ` H. Peter Anvin
@ 2008-01-07 23:25                             ` Alan Cox
  2008-01-08 13:17                               ` Bodo Eggert
  1 sibling, 1 reply; 186+ messages in thread
From: Alan Cox @ 2008-01-07 23:25 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: H. Peter Anvin, 7eggert, Christer Weinigel, Ingo Molnar,
	David P. Reed, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> But overclocking is not the problem for udelay, it would err to the safe 
> side. The problem would be a BUS having < 8 MHz, and since the days of 
> 80286, they are hard to find. IMO having an option to set the bus speed
> for those systems should be enough.

If you get it wrong you risk data corruption. Not good, not clever, not
appropriate. Basically the use of port 0x80 is the right thing to do for
ISA devices and as 15 odd years of use has shown works reliably and
solidly for ISA systems.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 22:59                                 ` Rene Herman
@ 2008-01-07 23:24                                   ` H. Peter Anvin
  2008-01-07 23:26                                     ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-07 23:24 UTC (permalink / raw)
  To: Rene Herman
  Cc: Bodo Eggert, Christer Weinigel, Ingo Molnar, Alan Cox,
	David P. Reed, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> 
> Is this only about the ones then left for things like legacy PIC and 
> PIT? Does anyone care about just sticking in a udelay(2) (or 1) there as 
> a replacement and call it a day?
> 

PIT is problematic because the PIT may be necessary for udelay setup.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 22:27                               ` Bodo Eggert
@ 2008-01-07 22:59                                 ` Rene Herman
  2008-01-07 23:24                                   ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2008-01-07 22:59 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: H. Peter Anvin, Christer Weinigel, Ingo Molnar, Alan Cox,
	David P. Reed, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 07-01-08 23:27, Bodo Eggert wrote:

> On Mon, 7 Jan 2008, H. Peter Anvin wrote:

>> There might have been a few 386/20's clocking the ISA bus at ­­÷3 (6.67
>> MHz) rather than ÷2 (10 MHz) or ÷2.5 (8 MHz).
> 
> Yes, and the remaining users should set the kernel option. Both of them. 
> The question is: How will they be told about the new kernel option?

What exactly are you guys still talking about? Alan is looking at drivers 
and finds that in them outb_p is generally correct and correctly specified 
in bus-clocks for at least some (8390 was quoted). In those legacy drivers, 
the _p ops can simply stay and can use the 15-year old proven 0x80 outb.

(with molnar suggesting they be renamed isa_in/outb_p and me suggesting that 
if someone would be doing _that_ they might as well split them manually in 
outb(); slow_down_io() possibly renaming slow_down_io() to isa_io_delay() or 
similar).

Is this only about the ones then left for things like legacy PIC and PIT? 
Does anyone care about just sticking in a udelay(2) (or 1) there as a 
replacement and call it a day?

Rene.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 22:10                             ` H. Peter Anvin
@ 2008-01-07 22:27                               ` Bodo Eggert
  2008-01-07 22:59                                 ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: Bodo Eggert @ 2008-01-07 22:27 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Bodo Eggert, Christer Weinigel, Ingo Molnar, Alan Cox,
	David P. Reed, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: TEXT/PLAIN, Size: 784 bytes --]

On Mon, 7 Jan 2008, H. Peter Anvin wrote:
> Bodo Eggert wrote:

> > But overclocking is not the problem for udelay, it would err to the safe
> > side. The problem would be a BUS having < 8 MHz, and since the days of
> > 80286, they are hard to find. IMO having an option to set the bus speed
> > for those systems should be enough.
> > 
> 
> There might have been a few 386/20's clocking the ISA bus at ­­÷3
> (6.67 MHz) rather than ÷2 (10 MHz) or ÷2.5 (8 MHz).

Yes, and the remaining users should set the kernel option. Both of them.
The question is: How will they be told about the new kernel option?
-- 
A man inserted an advertisement in the classified: Wife Wanted."
The next day he received a hundred letters. They all said the
same thing: "You can have mine."

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 22:02                           ` Bodo Eggert
@ 2008-01-07 22:10                             ` H. Peter Anvin
  2008-01-07 22:27                               ` Bodo Eggert
  2008-01-07 23:25                             ` Alan Cox
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-07 22:10 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: Christer Weinigel, Ingo Molnar, Alan Cox, David P. Reed,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

Bodo Eggert wrote:
> 
> But overclocking is not the problem for udelay, it would err to the safe 
> side. The problem would be a BUS having < 8 MHz, and since the days of 
> 80286, they are hard to find. IMO having an option to set the bus speed
> for those systems should be enough.
> 

There might have been a few 386/20's clocking the ISA bus at ­­÷3
(6.67 MHz) rather than ÷2 (10 MHz) or ÷2.5 (8 MHz).

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 19:46                         ` H. Peter Anvin
@ 2008-01-07 22:02                           ` Bodo Eggert
  2008-01-07 22:10                             ` H. Peter Anvin
  2008-01-07 23:25                             ` Alan Cox
  0 siblings, 2 replies; 186+ messages in thread
From: Bodo Eggert @ 2008-01-07 22:02 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: 7eggert, Christer Weinigel, Ingo Molnar, Alan Cox, David P. Reed,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On Mon, 7 Jan 2008, H. Peter Anvin wrote:
> Bodo Eggert wrote:
> > Christer Weinigel <christer@weinigel.se> wrote:

> > > How do you find out the speed of the ISA bus?  AFAIK there is no
> > > standardized way to do that.  On the Geode SC2200 the ISA bus speed is
> > > usually the PCI clock divided by 4 giving 33MHz/4=8.3MHz or
> > > 30/4=7.5MHz, but with no external ISA devices it's possible to
> > > overclock the ISA bus to /3 to run it at 11MHz or so.  But without
> > > poking at some CPU and southbridge specific registers to find out the
> > > PCI bus speed and the ISA bus divisor you can't really tell.
> > 
> > If you overclock, you are on your own. IIRC I've used 13,3 MHz for some time
> > and used a lower PIO mode to compensate.
> > 
> > > So if you do udelay based on a 6MHz clock (I think you can safely
> > > assume that any 386 based system runs the ISA bus at least that fast)
> > > you'll waste at least 30% and maybe even 100% more time for the delay
> > > after every _p call.
> > 
> > Defaulting to 8 MHz and offering an option to set another clock speed
> > (like idebus=) should be OK.
> > 
> 
> The formalization of the ISA bus which was part of the EISA specification
> settled on 8.33 MHz maximum nominal frequency.  There were, however, some
> earlier designs which used up to 12 MHz nominal; I'm not sure if that applied
> to 386s though.

I've used up to 13,3 MHz on my 386DX40, but it was way out of spec and
I had to use a lower PIO mode to compensate. IIRC, one of my cards forced
me to settle for 10 MHz. Wikipedia claims there were systems having
16 MHz ISA bus, and systems underclocking themselves when accessing ISA.
I remember having optional and mandatory waitstates, too, but I'm not
100 % sure it was on ISA. I think they were ...

But overclocking is not the problem for udelay, it would err to the safe 
side. The problem would be a BUS having < 8 MHz, and since the days of 
80286, they are hard to find. IMO having an option to set the bus speed
for those systems should be enough.

-- 
knghtbrd:<JHM> AIX - the Unix from the universe where Spock has a beard.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-07 19:38                       ` Bodo Eggert
@ 2008-01-07 19:46                         ` H. Peter Anvin
  2008-01-07 22:02                           ` Bodo Eggert
  2008-01-08  3:15                         ` Christer Weinigel
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-07 19:46 UTC (permalink / raw)
  To: 7eggert
  Cc: Christer Weinigel, Ingo Molnar, Alan Cox, David P. Reed,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

Bodo Eggert wrote:
> Christer Weinigel <christer@weinigel.se> wrote:
> 
>> How do you find out the speed of the ISA bus?  AFAIK there is no
>> standardized way to do that.  On the Geode SC2200 the ISA bus speed is
>> usually the PCI clock divided by 4 giving 33MHz/4=8.3MHz or
>> 30/4=7.5MHz, but with no external ISA devices it's possible to
>> overclock the ISA bus to /3 to run it at 11MHz or so.  But without
>> poking at some CPU and southbridge specific registers to find out the
>> PCI bus speed and the ISA bus divisor you can't really tell.
> 
> If you overclock, you are on your own. IIRC I've used 13,3 MHz for some time
> and used a lower PIO mode to compensate.
> 
>> So if you do udelay based on a 6MHz clock (I think you can safely
>> assume that any 386 based system runs the ISA bus at least that fast)
>> you'll waste at least 30% and maybe even 100% more time for the delay
>> after every _p call.
> 
> Defaulting to 8 MHz and offering an option to set another clock speed
> (like idebus=) should be OK.
> 

The formalization of the ISA bus which was part of the EISA 
specification settled on 8.33 MHz maximum nominal frequency.  There 
were, however, some earlier designs which used up to 12 MHz nominal; I'm 
not sure if that applied to 386s though.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
       [not found]                     ` <9GVKU-7SS-25@gated-at.bofh.it>
@ 2008-01-07 19:38                       ` Bodo Eggert
  2008-01-07 19:46                         ` H. Peter Anvin
  2008-01-08  3:15                         ` Christer Weinigel
  0 siblings, 2 replies; 186+ messages in thread
From: Bodo Eggert @ 2008-01-07 19:38 UTC (permalink / raw)
  To: Christer Weinigel, Ingo Molnar, Alan Cox, David P. Reed,
	H. Peter Anvin, Rene Herman, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Christer Weinigel <christer@weinigel.se> wrote:

> How do you find out the speed of the ISA bus?  AFAIK there is no
> standardized way to do that.  On the Geode SC2200 the ISA bus speed is
> usually the PCI clock divided by 4 giving 33MHz/4=8.3MHz or
> 30/4=7.5MHz, but with no external ISA devices it's possible to
> overclock the ISA bus to /3 to run it at 11MHz or so.  But without
> poking at some CPU and southbridge specific registers to find out the
> PCI bus speed and the ISA bus divisor you can't really tell.

If you overclock, you are on your own. IIRC I've used 13,3 MHz for some time
and used a lower PIO mode to compensate.

> So if you do udelay based on a 6MHz clock (I think you can safely
> assume that any 386 based system runs the ISA bus at least that fast)
> you'll waste at least 30% and maybe even 100% more time for the delay
> after every _p call.

Defaulting to 8 MHz and offering an option to set another clock speed
(like idebus=) should be OK.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-02 15:35                                                                       ` Rene Herman
@ 2008-01-02 15:50                                                                         ` Rene Herman
  0 siblings, 0 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-02 15:50 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On 02-01-08 16:35, Rene Herman wrote:
 > On 02-01-08 14:47, Alan Cox wrote:
 >
 >>> ok, you are right. How about we go with one of your suggestions:
 >>> rename the API family to isa_*_p() in the affected ISA drivers? That
 >>> makes it perfectly clear that this is an ISA related historic quirk
 >>> that we just cannot properly emulate in an acceptable fashion. It
 >>> will also make the least amount of changes to these truly historic
 >>> drivers.
 >>
 >> Works for me. We need to build two versions of 8390.c now but thats no
 >> big deal and sorts PCMCIA out too.
 >
 > For no binary changes at all, and if going through all those outb_p()
 > users anyway, might/could as well just manually split them then:
 >
 > outb_p() --> outb();
 >              slow_down_io();
 >
 > and then just leave out the slow_down_io() call in the non-ISA spots.
 > slow_down_io() could be renamed isa_io_delay() or anything (paravirt is
 > a little annoying there) if someone cares but then it's a complete
 > identity transformation for any driver that does care.
 >
 > Would IMO also make for a somewhat better API than an isa_outb_p() as
 > there's nothing particurly ISA about the outb method itself -- many ISA
 > drivers use plain outb() as well.

Would just need this bit of io.h arch unification from the orignal patch and 
that's it:

diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..97cb8c6 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,20 @@
    *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
    */

-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+static inline void native_io_delay(void)
+{
+	asm volatile("outb %%al,$0x80" : : : "memory");
+}

+static inline void slow_down_io(void)
+{
+	native_io_delay();
  #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO 
__SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
  #endif
+}

  /*
   * Talk about misusing macros..
@@ -50,21 +57,21 @@
  static inline void out##s(unsigned x value, unsigned short port) {

  #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" 
(port))

  #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" 
(port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }

  #define __IN1(s) \
  static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;

  #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))

-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) 
,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }

  #define __INS(s) \
  static inline void ins##s(unsigned short port, void * addr, unsigned long 
count) \


^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-02 13:47                                                                     ` Alan Cox
@ 2008-01-02 15:35                                                                       ` Rene Herman
  2008-01-02 15:50                                                                         ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2008-01-02 15:35 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On 02-01-08 14:47, Alan Cox wrote:

>> ok, you are right. How about we go with one of your suggestions: rename 
>> the API family to isa_*_p() in the affected ISA drivers? That makes it 
>> perfectly clear that this is an ISA related historic quirk that we just 
>> cannot properly emulate in an acceptable fashion. It will also make the 
>> least amount of changes to these truly historic drivers.
> 
> Works for me. We need to build two versions of 8390.c now but thats no
> big deal and sorts PCMCIA out too.

For no binary changes at all, and if going through all those outb_p() users 
anyway, might/could as well just manually split them then:

outb_p() --> outb();
              slow_down_io();

and then just leave out the slow_down_io() call in the non-ISA spots. 
slow_down_io() could be renamed isa_io_delay() or anything (paravirt is a 
little annoying there) if someone cares but then it's a complete identity 
transformation for any driver that does care.

Would IMO also make for a somewhat better API than an isa_outb_p() as 
there's nothing particurly ISA about the outb method itself -- many ISA 
drivers use plain outb() as well.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-02 10:04                                                                   ` Ingo Molnar
@ 2008-01-02 13:47                                                                     ` Alan Cox
  2008-01-02 15:35                                                                       ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2008-01-02 13:47 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: David P. Reed, H. Peter Anvin, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> ok, you are right. How about we go with one of your suggestions: rename 
> the API family to isa_*_p() in the affected ISA drivers? That makes it 
> perfectly clear that this is an ISA related historic quirk that we just 
> cannot properly emulate in an acceptable fashion. It will also make the 
> least amount of changes to these truly historic drivers.

Works for me. We need to build two versions of 8390.c now but thats no
big deal and sorts PCMCIA out too.

> The main maintenance thing we are interested in is to have no subsequent 
> new uses of this API and to eliminate these accesses from modern 
> hardware - and naming it clearly 'ISA' and making it dependent on 
> CONFIG_ISA would likely achieve that purpose.

Agreed - will see if EISA/VLB cases come up but thats trivial.

> oh, another thing: there are 100+ mails in this thread while there are 
> only 3 mails in the thread that lists 61 not-yet-fixed-in-2.6.24 
> regressions:

That would be because I'm trying to stop 100 new extra regressions ;)

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:07                                                                 ` Alan Cox
@ 2008-01-02 10:04                                                                   ` Ingo Molnar
  2008-01-02 13:47                                                                     ` Alan Cox
  0 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2008-01-02 10:04 UTC (permalink / raw)
  To: Alan Cox
  Cc: David P. Reed, H. Peter Anvin, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > udelay is supposed to be reliable. If someone runs a new kernel and 
> > has no TSC (which might happen even on modern hardware or with 
> > notsc) _and_ finds that udelay is not calibrated well enough then 
> > that's a kernel bug we want to fix.
> 
> You miss the point entirely. The delay is in bus clocks not CPU 
> clocks, not tsc clocks not PIT clocks, and it is permitted to vary by 
> a factor of two. So you'll worst case halve the speed of network 
> packet up/download even if your udelay is accurate.

ok, you are right. How about we go with one of your suggestions: rename 
the API family to isa_*_p() in the affected ISA drivers? That makes it 
perfectly clear that this is an ISA related historic quirk that we just 
cannot properly emulate in an acceptable fashion. It will also make the 
least amount of changes to these truly historic drivers.

The main maintenance thing we are interested in is to have no subsequent 
new uses of this API and to eliminate these accesses from modern 
hardware - and naming it clearly 'ISA' and making it dependent on 
CONFIG_ISA would likely achieve that purpose.

oh, another thing: there are 100+ mails in this thread while there are 
only 3 mails in the thread that lists 61 not-yet-fixed-in-2.6.24 
regressions:

|  Listed regressions statistics:
|
|  Date          Total  Pending  Unresolved
|  ----------------------------------------
|  Today           139       38          23

which is a sad proportion of attention :-/

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:21                                                                   ` H. Peter Anvin
  2008-01-01 23:05                                                                     ` Christer Weinigel
@ 2008-01-02 10:00                                                                     ` Ingo Molnar
  1 sibling, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2008-01-02 10:00 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Christer Weinigel, Alan Cox, David P. Reed, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol


* H. Peter Anvin <hpa@zytor.com> wrote:

> Christer Weinigel wrote:
>>
>> out 80h, al is only two bytes.  Any alternative that has been suggested
>> in this discussion will use more space.  mov dx, alt_port; out dx, al
>> will be larger, a function call will definitely be a lot larger. People
>> have been making changes to the kernel to save a couple of hundred
>> bytes of text size.
>>
>
> If text size becomes a problem in this case, then we can use an 
> alternatives-like mechanism to fix up the kernel.  However, 
> realistically this probably should be a function call *combined with* 
> the out and in; that reduces the impact somewhat.

and that's exactly what x86.git#mm does now.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-02  0:55                                                                       ` Christer Weinigel
  2008-01-02  1:00                                                                         ` Rene Herman
@ 2008-01-02  2:27                                                                         ` H. Peter Anvin
  1 sibling, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-02  2:27 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Rene Herman, Alan Cox, David P. Reed, Rene Herman, Ingo Molnar,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

Christer Weinigel wrote:
> 
> Both 0xed and 0xf0 are mapped to internal functions on the AMD Elan
> SC400 processor.  It is an AMD 486 based system on a chip and since AMD
> just knew that it would never have a math coprocessor, they reused the
> 0xf0-0xf2 range for the PCMCIA controller.  I guess the AMD Elan SC500
> will have similar problems.
> 
> I seem to recall that back when I was working with the Elan SC400
> (sometime around 1998?) there were discussions about finding an
> alternate delay port because outb to 0x80 messed up the debug port.  I
> think the Elan stopped those discussions because just about every port
> on the Elan was reused for some alternate purpose.  
> 

Yeah, the Elan is not supportable anyway without a CONFIG option (it's 
broken in so many ways), so it doesn't really apply.  It's a fuckwit design.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-02  0:55                                                                       ` Christer Weinigel
@ 2008-01-02  1:00                                                                         ` Rene Herman
  2008-01-02  2:27                                                                         ` H. Peter Anvin
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-02  1:00 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: H. Peter Anvin, Alan Cox, David P. Reed, Rene Herman,
	Ingo Molnar, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On 02-01-08 01:55, Christer Weinigel wrote:

> On Wed, 02 Jan 2008 00:11:54 +0100
> Rene Herman <rene.herman@keyaccess.nl> wrote:
> 
>> Well, on the PIIX it is and I guess on anything where it's _not_
>> fully internal an 0xf0 write wouldn't have any effect on IRQ13...
>>
>> When you earlier mentioned this it seemed 0xed switched on DMI would
>> be good enough, but well.
>>
>> Alan, do you have an opinion on the port 0xf0 write? It should
>> probably still be combined with a replacement/deletion for new
>> machines due to the bus-locking "bad for real-time" thing you
>> mentioned earlier but in the short run it could be a fairly
>> low-impact replacement on anything except a 386+387
> 
> Both 0xed and 0xf0 are mapped to internal functions on the AMD Elan
> SC400 processor.  It is an AMD 486 based system on a chip and since AMD
> just knew that it would never have a math coprocessor, they reused the
> 0xf0-0xf2 range for the PCMCIA controller.  I guess the AMD Elan SC500
> will have similar problems.
> 
> I seem to recall that back when I was working with the Elan SC400
> (sometime around 1998?) there were discussions about finding an
> alternate delay port because outb to 0x80 messed up the debug port.  I
> think the Elan stopped those discussions because just about every port
> on the Elan was reused for some alternate purpose.  

Okay, thanks much. So 0xf0 would be unuseable on 386+387 and AMD Elan SC400 
and could possibly change timing on an unknown number of systems due to not 
being put on the bus.

0x80 only fails for some recent HP laptops instead so it seems there would 
be not enough cause to go with 0xf0 onstead of 0x80 as the default choice; 
if we're quirking around machines anyway it might as well be the DMI based 
quirking currently suggested.

Rene.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 23:11                                                                     ` Rene Herman
  2008-01-02  0:25                                                                       ` Rene Herman
@ 2008-01-02  0:55                                                                       ` Christer Weinigel
  2008-01-02  1:00                                                                         ` Rene Herman
  2008-01-02  2:27                                                                         ` H. Peter Anvin
  1 sibling, 2 replies; 186+ messages in thread
From: Christer Weinigel @ 2008-01-02  0:55 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Alan Cox, David P. Reed, Rene Herman,
	Ingo Molnar, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On Wed, 02 Jan 2008 00:11:54 +0100
Rene Herman <rene.herman@keyaccess.nl> wrote:

> Well, on the PIIX it is and I guess on anything where it's _not_
> fully internal an 0xf0 write wouldn't have any effect on IRQ13...
> 
> When you earlier mentioned this it seemed 0xed switched on DMI would
> be good enough, but well.
> 
> Alan, do you have an opinion on the port 0xf0 write? It should
> probably still be combined with a replacement/deletion for new
> machines due to the bus-locking "bad for real-time" thing you
> mentioned earlier but in the short run it could be a fairly
> low-impact replacement on anything except a 386+387

Both 0xed and 0xf0 are mapped to internal functions on the AMD Elan
SC400 processor.  It is an AMD 486 based system on a chip and since AMD
just knew that it would never have a math coprocessor, they reused the
0xf0-0xf2 range for the PCMCIA controller.  I guess the AMD Elan SC500
will have similar problems.

I seem to recall that back when I was working with the Elan SC400
(sometime around 1998?) there were discussions about finding an
alternate delay port because outb to 0x80 messed up the debug port.  I
think the Elan stopped those discussions because just about every port
on the Elan was reused for some alternate purpose.  

  /Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 23:11                                                                     ` Rene Herman
@ 2008-01-02  0:25                                                                       ` Rene Herman
  2008-01-02  0:55                                                                       ` Christer Weinigel
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-02  0:25 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Alan Cox, David P. Reed, Ingo Molnar, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 02-01-08 00:11, Rene Herman wrote:

> On 01-01-08 23:39, H. Peter Anvin wrote:
> 
>>>> Yes, we do.  It's exactly this side effect which makes this safer 
>>>> than either 0x80 or 0xED -- it's a port that *guaranteed* can't be 
>>>> reclaimed for other purposes without breaking MS-DOS compatibility.
>>>
>>> I see that with CR0.NE set (*) we indeed don't care about IGNNE#...
>>>
>>> However, I'm worried about this comment in arch/x86/kernel/i8259_32.c
>>>
>>> ===
>>> /*
>>>  * New motherboards sometimes make IRQ 13 be a PCI interrupt,
>>>  * so allow interrupt sharing.
>>>  */
>>> ===
>>>
>>> Is it really safe to just blindly negate IRQ13 on everything out 
>>> there, from regular PC through funky embedded thingies?
>>
>> It's not any IRQ 13, it's IRQ 13 from the FPU.
> 
> Well, on the PIIX it is and I guess on anything where it's _not_ fully 
> internal an 0xf0 write wouldn't have any effect on IRQ13...
> 
> When you earlier mentioned this it seemed 0xed switched on DMI would be 
> good enough, but well.
> 
> Alan, do you have an opinion on the port 0xf0 write? It should probably 
> still be combined with a replacement/deletion for new machines due to 
> the bus-locking "bad for real-time" thing you mentioned earlier but in 
> the short run it could be a fairly low-impact replacement on anything 
> except a 386+387
> 
> We should do a another timing measurement survey and it makes for 
> sligtly worse code if we indeed feel it's not safe enough to write 
> anything other than 0, but otherwise it's quite minimal.

Thinking about this, my main worry about 0xf0 as a 0x80 replacement would be 
systems that have elected to _not_ let port 0xf0 writes flow through to ISA 
changing the timing-characteristics. Given that it's a known port, someone 
may have elected to just keep it fully internal.

Upto now the datasheets I've read do put it on ISA...

Rene.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 23:12                                                                       ` Alan Cox
@ 2008-01-02  0:23                                                                         ` Christer Weinigel
  0 siblings, 0 replies; 186+ messages in thread
From: Christer Weinigel @ 2008-01-02  0:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: H. Peter Anvin, Ingo Molnar, David P. Reed, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On Tue, 1 Jan 2008 23:12:50 +0000
Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > Besides the above there are only a handful of _p uses outside of
> > real ISA device drivers, and those should not be relevant for a
> > modern PC unless somebody wants to use an 8390 based PCMCIA card,
> > but we could tell them "don't do that then".
> 
> We need to build 8390.c twice anyway - once for PCI once for ISA with
> the _p changes whichever way it gets done. PCMCIA can use whichever
> we decide is right. Anyone know if PCMCIA is guaranteed to be 8MHz ?

It's not.  It's perfectly ok to drive a PCMCIA bus slower than that,
IIRC we used a much slower clock speed than that on a StrongARM
platform I worked a couple of years ago.  

The PCMCIA CIS (Card information services) allows the following device
speeds: 100, 150, 200 and 250 ns.  The memory card spec also allows 600
and 300 ns.  The standard I/O card cycle speed is 255 ns.  I believe
that is "the shortest access time for a read/write cycle", and I can't
tell if that is comparable to one ISA clock cycles or if it's
comparable to 8 ISA bus cycles.

On the other hand, there is no clock line in a PCMCIA connector, so for
PCMCIA devices any delays should be absolute times, or based on some
clock that is internal to the card.  How that fits with the 8390 data
sheet talking about bus clocks, I don't know.

  /Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 23:05                                                                     ` Christer Weinigel
@ 2008-01-01 23:12                                                                       ` Alan Cox
  2008-01-02  0:23                                                                         ` Christer Weinigel
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2008-01-01 23:12 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: H. Peter Anvin, Ingo Molnar, David P. Reed, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

> Besides the above there are only a handful of _p uses outside of real
> ISA device drivers, and those should not be relevant for a modern PC
> unless somebody wants to use an 8390 based PCMCIA card, but we could
> tell them "don't do that then".

We need to build 8390.c twice anyway - once for PCI once for ISA with the
_p changes whichever way it gets done. PCMCIA can use whichever we decide
is right. Anyone know if PCMCIA is guaranteed to be 8MHz ?

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 22:39                                                                   ` H. Peter Anvin
@ 2008-01-01 23:11                                                                     ` Rene Herman
  2008-01-02  0:25                                                                       ` Rene Herman
  2008-01-02  0:55                                                                       ` Christer Weinigel
  0 siblings, 2 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-01 23:11 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Alan Cox, David P. Reed, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 01-01-08 23:39, H. Peter Anvin wrote:

>>> Yes, we do.  It's exactly this side effect which makes this safer 
>>> than either 0x80 or 0xED -- it's a port that *guaranteed* can't be 
>>> reclaimed for other purposes without breaking MS-DOS compatibility.
>>
>> I see that with CR0.NE set (*) we indeed don't care about IGNNE#...
>>
>> However, I'm worried about this comment in arch/x86/kernel/i8259_32.c
>>
>> ===
>> /*
>>  * New motherboards sometimes make IRQ 13 be a PCI interrupt,
>>  * so allow interrupt sharing.
>>  */
>> ===
>>
>> Is it really safe to just blindly negate IRQ13 on everything out 
>> there, from regular PC through funky embedded thingies?
> 
> It's not any IRQ 13, it's IRQ 13 from the FPU.

Well, on the PIIX it is and I guess on anything where it's _not_ fully 
internal an 0xf0 write wouldn't have any effect on IRQ13...

When you earlier mentioned this it seemed 0xed switched on DMI would be good 
enough, but well.

Alan, do you have an opinion on the port 0xf0 write? It should probably 
still be combined with a replacement/deletion for new machines due to the 
bus-locking "bad for real-time" thing you mentioned earlier but in the short 
run it could be a fairly low-impact replacement on anything except a 386+387

We should do a another timing measurement survey and it makes for sligtly 
worse code if we indeed feel it's not safe enough to write anything other 
than 0, but otherwise it's quite minimal.

Rene.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:21                                                                   ` H. Peter Anvin
@ 2008-01-01 23:05                                                                     ` Christer Weinigel
  2008-01-01 23:12                                                                       ` Alan Cox
  2008-01-02 10:00                                                                     ` Ingo Molnar
  1 sibling, 1 reply; 186+ messages in thread
From: Christer Weinigel @ 2008-01-01 23:05 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Alan Cox, David P. Reed, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On Tue, 01 Jan 2008 13:21:47 -0800
"H. Peter Anvin" <hpa@zytor.com> wrote:

> Christer Weinigel wrote:
> > 
> > out 80h, al is only two bytes.  Any alternative that has been
> > suggested in this discussion will use more space.  mov dx,
> > alt_port; out dx, al will be larger, a function call will
> > definitely be a lot larger. People have been making changes to the
> > kernel to save a couple of hundred bytes of text size.
> 
> If text size becomes a problem in this case, then we can use an 
> alternatives-like mechanism to fix up the kernel.  However, 
> realistically this probably should be a function call *combined with* 
> the out and in; that reduces the impact somewhat.

That's a very good point.  So for the PIT it should be possible to have
two clocksources, one with the _p and one without, that one can switch
between with a kernel command line option.  So there shouldn't be any
slowdown at all due to that.

The i8259 init code is not time critical, so should be able to use a
"reasonable" delay.  

Besides the above there are only a handful of _p uses outside of real
ISA device drivers, and those should not be relevant for a modern PC
unless somebody wants to use an 8390 based PCMCIA card, but we could
tell them "don't do that then".

But I'd better shut up and let Alan continue on his review of the _p
use in the drivers.

  /Christer



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 22:35                                                                 ` Rene Herman
@ 2008-01-01 22:39                                                                   ` H. Peter Anvin
  2008-01-01 23:11                                                                     ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 22:39 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, David P. Reed, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
>>
>> Yes, we do.  It's exactly this side effect which makes this safer than 
>> either 0x80 or 0xED -- it's a port that *guaranteed* can't be 
>> reclaimed for other purposes without breaking MS-DOS compatibility.
> 
> I see that with CR0.NE set (*) we indeed don't care about IGNNE#...
> 
> However, I'm worried about this comment in arch/x86/kernel/i8259_32.c
> 
> ===
> /*
>  * New motherboards sometimes make IRQ 13 be a PCI interrupt,
>  * so allow interrupt sharing.
>  */
> ===
> 
> Is it really safe to just blindly negate IRQ13 on everything out there, 
> from regular PC through funky embedded thingies?
> 

It's not any IRQ 13, it's IRQ 13 from the FPU.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:44                                                               ` H. Peter Anvin
@ 2008-01-01 22:35                                                                 ` Rene Herman
  2008-01-01 22:39                                                                   ` H. Peter Anvin
  2008-01-09 17:27                                                                 ` Maciej W. Rozycki
  1 sibling, 1 reply; 186+ messages in thread
From: Rene Herman @ 2008-01-01 22:35 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Alan Cox, David P. Reed, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 1633 bytes --]

On 01-01-08 22:44, H. Peter Anvin wrote:

> Rene Herman wrote:
>> On 01-01-08 22:15, H. Peter Anvin wrote:
>>
>>> I have mentioned this before... I think writing zero to port 0xf0 
>>> would be an acceptable pause interface (to the extent where we need 
>>> an I/O port) except on 386 with 387 present; on those systems we can 
>>> fall back to 0x80.
>>
>> PII 400 / Intel 440 BX (PIIX4):
>>
>> rene@6bap:~/port80$ su -c ./portime
>> out 0x80: 544 cycles
>> in  0x80: 254 cycles
>> in  0x61: 254 cycles
>> out 0xf0: 544 cycles
>>
>> The Intel PIIX/PIIX3 datasheet specifically mentions that both reads 
>> and writes at 0xf0 "flow through to the ISA bus".
>>
>> However, more complete, it says:
>>
>> "Writing to this register causes the PIIX/PIIX3 to assert IGNNE#. The 
>> PIIX/PIIX3 also negates IRQ13 (internal to the PIIX). Note that IGNNE# 
>> is not asserted unless FERR# is active. Reads/writes flow through to 
>> the ISA bus".
>>
>> We don't want the side-effects, do we?
>>
> 
> Yes, we do.  It's exactly this side effect which makes this safer than 
> either 0x80 or 0xED -- it's a port that *guaranteed* can't be reclaimed 
> for other purposes without breaking MS-DOS compatibility.

I see that with CR0.NE set (*) we indeed don't care about IGNNE#...

However, I'm worried about this comment in arch/x86/kernel/i8259_32.c

===
/*
  * New motherboards sometimes make IRQ 13 be a PCI interrupt,
  * so allow interrupt sharing.
  */
===

Is it really safe to just blindly negate IRQ13 on everything out there, from 
regular PC through funky embedded thingies?

(*) bit 5:

rene@7ixe4:~/src/local$ ./smsw
msw: 0x3b

Rene.

[-- Attachment #2: smsw.c --]
[-- Type: text/plain, Size: 180 bytes --]

/* gcc -W -Wall -o smsw smsw.c */

#include <stdio.h>
#include <stdint.h>

int main(void)
{
	uint16_t msw;

	asm ("smsw %0": "=r" (msw));
	printf("msw: %#hx\n", msw);
	return 0;
}

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:42                                                                     ` Christer Weinigel
  2008-01-01 21:42                                                                       ` Rene Herman
@ 2008-01-01 21:50                                                                       ` H. Peter Anvin
  1 sibling, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 21:50 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Ingo Molnar, Alan Cox, David P. Reed, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Christer Weinigel wrote:
> 
> And once again, the _p in the code that talks to the PIT is very much
> non-bogus.  And it is a critical path that's called a lot.  The i8253
> PIT and the i8259 interrupt controller are probably the only ones that
> are relevant on a modern machine, and it seems that even some fairly
> modern chipsets have limitations on how fast you can drive them.
> 

I actually analyzed the case of the PIT in the case of the 
implementation of a real chipset.  In our case, running the PIT at 
1.19318 MHz when the rest of the chipset core was running at 100 MHz 
introduced a huge amount of extra complexity and we really wanted to get 
rid of it.  As it turns out, the PIT interface is ill-defined if run at 
a higher frequency; you can get undefined values as a result of a write 
followed by a read if there is no intervening PIT clock, which of course 
in the standard interface never happens.  So in the end, we had to build 
all the synchronizers, backpressure controls and other crap that went 
along with an additional clock domain.

As a result of that experience, I really don't think you will *ever* see 
a PIT that runs at a modern frequency.

Building a 100 MHz PIC, however, was not a problem, and being able to 
sink accesses at full speed meant we didn't have to implement flow control.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:35                                                             ` Rene Herman
@ 2008-01-01 21:44                                                               ` H. Peter Anvin
  2008-01-01 22:35                                                                 ` Rene Herman
  2008-01-09 17:27                                                                 ` Maciej W. Rozycki
  0 siblings, 2 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 21:44 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, David P. Reed, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> On 01-01-08 22:15, H. Peter Anvin wrote:
> 
>> I have mentioned this before... I think writing zero to port 0xf0 
>> would be an acceptable pause interface (to the extent where we need an 
>> I/O port) except on 386 with 387 present; on those systems we can fall 
>> back to 0x80.
> 
> PII 400 / Intel 440 BX (PIIX4):
> 
> rene@6bap:~/port80$ su -c ./portime
> out 0x80: 544 cycles
> in  0x80: 254 cycles
> in  0x61: 254 cycles
> out 0xf0: 544 cycles
> 
> The Intel PIIX/PIIX3 datasheet specifically mentions that both reads and 
> writes at 0xf0 "flow through to the ISA bus".
> 
> However, more complete, it says:
> 
> "Writing to this register causes the PIIX/PIIX3 to assert IGNNE#. The 
> PIIX/PIIX3 also negates IRQ13 (internal to the PIIX). Note that IGNNE# 
> is not asserted unless FERR# is active. Reads/writes flow through to the 
> ISA bus".
> 
> We don't want the side-effects, do we?
> 

Yes, we do.  It's exactly this side effect which makes this safer than 
either 0x80 or 0xED -- it's a port that *guaranteed* can't be reclaimed 
for other purposes without breaking MS-DOS compatibility.

It's specifically a side effect *we don't care about*, except in the 
by-now-somewhat-exotic case of 386+387 (where we indeed can't use it 
once user code has touched the FPU -- but we can fall back to 0x80 on 
those, a very small number of systems.)  486+ doesn't use this interface 
under Linux, since Linux uses the proper exception path on those 
processors.  If Compaq had wired up the proper signals on the first 386 
PC motherboards, we wouldn't have cared about it on the 386 either.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:42                                                                     ` Christer Weinigel
@ 2008-01-01 21:42                                                                       ` Rene Herman
  2008-01-01 21:50                                                                       ` H. Peter Anvin
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2008-01-01 21:42 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Ingo Molnar, Alan Cox, David P. Reed, H. Peter Anvin,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On 01-01-08 22:42, Christer Weinigel wrote:

> The data sheet for the Intel M8259A says:
> 
>     End of /RD to Next Command: 300 ns
>     End of /WR to Next Command: 370 ns
> 
> On the other hand, I don't know how all the i8253/i8259 clones or the
> numerous variants of Super I/O chips behave.  It wouldn't surprise me
> if some Super I/O chip uses the ISA bus clock to latch the values
> internally so that the delay is dependent on the bus frequency instead.

I wouldn't even be surprised if most all would...

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:01                                                                   ` Ingo Molnar
  2008-01-01 21:26                                                                     ` Alan Cox
@ 2008-01-01 21:42                                                                     ` Christer Weinigel
  2008-01-01 21:42                                                                       ` Rene Herman
  2008-01-01 21:50                                                                       ` H. Peter Anvin
  1 sibling, 2 replies; 186+ messages in thread
From: Christer Weinigel @ 2008-01-01 21:42 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On Tue, 1 Jan 2008 22:01:43 +0100
Ingo Molnar <mingo@elte.hu> wrote:

> > out 80h, al is only two bytes.  Any alternative that has been 
> > suggested in this discussion will use more space.  mov dx,
> > alt_port; out dx, al will be larger, a function call will
> > definitely be a lot larger. People have been making changes to the
> > kernel to save a couple of hundred bytes of text size.
> 
> i've done dozens of patches that saved much less of text size, so
> yes, i very much care about code size. But it has been stated in this
> thread that most of the _p() API uses in the kernel today are bogus.
> So eventually getting rid of the bogus ones will be a net code size 
> _reduction_. (But even that is besides the point, we prefer clean and 
> easier to maintain code.)

And once again, the _p in the code that talks to the PIT is very much
non-bogus.  And it is a critical path that's called a lot.  The i8253
PIT and the i8259 interrupt controller are probably the only ones that
are relevant on a modern machine, and it seems that even some fairly
modern chipsets have limitations on how fast you can drive them.

BTW, I just checked the Intel M8253 data sheet (dead tree variant), and
it says under A.C Characteristics, READ CYCLE:

    Recovery Time Between /READ and Any Other Control Signal: 1 us

So at least for the original M8253 a udelay(1) might be more
appropriate than outb_p, since the delay is not expressed in clock
cycles but absolute time.

The data sheet for the Intel M8259A says:

    End of /RD to Next Command: 300 ns
    End of /WR to Next Command: 370 ns

On the other hand, I don't know how all the i8253/i8259 clones or the
numerous variants of Super I/O chips behave.  It wouldn't surprise me
if some Super I/O chip uses the ISA bus clock to latch the values
internally so that the delay is dependent on the bus frequency instead.

> > I don't know if the difference in code size or the udelay will be 
> > significantly slower, but I think it might be.
> 
> ok, "I dont know but it might be slower" is a perfectly fine
> statement instead of your original "it will be slower".

I didn't say that, I said I'm afraid it will be slower. :-)

  /Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:15                                                           ` H. Peter Anvin
@ 2008-01-01 21:35                                                             ` Rene Herman
  2008-01-01 21:44                                                               ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2008-01-01 21:35 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Alan Cox, David P. Reed, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 858 bytes --]

On 01-01-08 22:15, H. Peter Anvin wrote:

> I have mentioned this before... I think writing zero to port 0xf0 would 
> be an acceptable pause interface (to the extent where we need an I/O 
> port) except on 386 with 387 present; on those systems we can fall back 
> to 0x80.

PII 400 / Intel 440 BX (PIIX4):

rene@6bap:~/port80$ su -c ./portime
out 0x80: 544 cycles
in  0x80: 254 cycles
in  0x61: 254 cycles
out 0xf0: 544 cycles

The Intel PIIX/PIIX3 datasheet specifically mentions that both reads and 
writes at 0xf0 "flow through to the ISA bus".

However, more complete, it says:

"Writing to this register causes the PIIX/PIIX3 to assert IGNNE#. The 
PIIX/PIIX3 also negates IRQ13 (internal to the PIIX). Note that IGNNE# is 
not asserted unless FERR# is active. Reads/writes flow through to the ISA bus".

We don't want the side-effects, do we?

Rene.

[-- Attachment #2: portime.c --]
[-- Type: text/plain, Size: 1513 bytes --]

/* gcc -W -Wall -O2 -o portime portime.c */

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

#include <sys/io.h>

#define LOOPS 10000

inline uint64_t rdtsc(void)
{
	uint32_t hi, lo;

	asm ("rdtsc": "=d" (hi), "=a" (lo));

	return (uint64_t)hi << 32 | lo;
}

inline void serialize(void)
{
	asm ("cpuid": : : "eax", "ebx", "ecx", "edx");
}

int main(void)
{
	uint64_t tsc0, tsc1, tsc2, tsc3, tsc4, tsc5;
	uint64_t out80, in80, in61, outf0;
	int i;

	if (iopl(3) < 0) {
		perror("iopl");
		return EXIT_FAILURE;
	}

	asm ("cli");
	tsc0 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
	 	serialize();	
		serialize();
	}
	tsc1 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("outb %al, $0x80");
		serialize();
	}
	tsc2 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("inb $0x80, %%al": : : "al");
		serialize();
	}
	tsc3 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("inb $0x61, %%al": : : "al");
		serialize();
	}
	tsc4 = rdtsc();
	for (i = 0; i < LOOPS; i++) {
		serialize();
		asm ("outb %b0, $0xf0": : "a" (0));
		serialize();
	}
	tsc5 = rdtsc();
	asm ("sti");

	out80 = ((tsc2 - tsc1) - (tsc1 - tsc0)) / LOOPS;
	in80  = ((tsc3 - tsc2) - (tsc1 - tsc0)) / LOOPS;
	in61  = ((tsc4 - tsc3) - (tsc1 - tsc0)) / LOOPS;
	outf0 = ((tsc5 - tsc4) - (tsc1 - tsc0)) / LOOPS;

	printf("out 0x80: %llu cycles\n", out80);
	printf("in  0x80: %llu cycles\n", in80);
	printf("in  0x61: %llu cycles\n", in61);
	printf("out 0xf0: %llu cycles\n", outf0);

	return EXIT_SUCCESS;
}

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 21:01                                                                   ` Ingo Molnar
@ 2008-01-01 21:26                                                                     ` Alan Cox
  2008-01-01 21:42                                                                     ` Christer Weinigel
  1 sibling, 0 replies; 186+ messages in thread
From: Alan Cox @ 2008-01-01 21:26 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Christer Weinigel, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

> very much care about code size. But it has been stated in this thread 
> that most of the _p() API uses in the kernel today are bogus. So 

You missed a word "wrongly". It has been "wrongly stated"

I've been going through the ISA cases which are the majority. Generally
speaking they are correct. We have a couple of "interesting" PCI users
who most definitely want udelay() or removal of _p. We have various
chipset cases which want looking at in detail. The ISA drivers however
are both the main user and mostly right.

> ok, "I dont know but it might be slower" is a perfectly fine statement 
> instead of your original "it will be slower".

If you use wall clock timings it will be slower.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 20:55                                                                     ` Christer Weinigel
@ 2008-01-01 21:24                                                                       ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 21:24 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Rene Herman, Ingo Molnar, Alan Cox, David P. Reed, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

Christer Weinigel wrote:
> 
>> For that matter does anyone actually have video cards old enough for us
>> to care actually still in use with Linux today ? 
> 
> I'm afraid that some PC104 systems may still use ancient video cards.
> 

PC/104 is actual ISA, not even LPC...

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 19:35                                                                 ` Christer Weinigel
  2008-01-01 19:59                                                                   ` Rene Herman
  2008-01-01 21:01                                                                   ` Ingo Molnar
@ 2008-01-01 21:21                                                                   ` H. Peter Anvin
  2008-01-01 23:05                                                                     ` Christer Weinigel
  2008-01-02 10:00                                                                     ` Ingo Molnar
  2 siblings, 2 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 21:21 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Ingo Molnar, Alan Cox, David P. Reed, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Christer Weinigel wrote:
> 
> out 80h, al is only two bytes.  Any alternative that has been suggested
> in this discussion will use more space.  mov dx, alt_port; out dx, al
> will be larger, a function call will definitely be a lot larger. People
> have been making changes to the kernel to save a couple of hundred
> bytes of text size.
> 

If text size becomes a problem in this case, then we can use an 
alternatives-like mechanism to fix up the kernel.  However, 
realistically this probably should be a function call *combined with* 
the out and in; that reduces the impact somewhat.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 15:57                                                       ` David P. Reed
@ 2008-01-01 21:16                                                         ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 21:16 UTC (permalink / raw)
  To: David P. Reed
  Cc: Alan Cox, Rene Herman, Ingo Molnar, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

David P. Reed wrote:
> Alan, thank you for the pointers.  I have been doing variations on this 
> testing theme for a while - I get intrigued by a good debugging 
> challenge, and after all it's my machine...
> 
> Two relevant new data points, and then some more suggestions:
> 
> 1. It appears to be a real port.  SMI traps are not happening in the 
> normal outb to 80.  Hundreds of them execute perfectly with the expected 
> instruction counts.  If I can trace the particular event that creates 
> the hard freeze (getting really creative, here) and stop before the 
> freeze disables the entire computer, I will.  That may be an SMI, or 
> perhaps any other kind of interrupt or exception.  Maybe someone knows 
> how to safely trace through an impending SMI while doing printk's or 
> something?
> 
> 2. It appears to be the standard POST diagnostic port.  On a whim, I 
> disassembled my DSDT code, and studied it more closely.   It turns out 
> that there are a bunch of "Store(..., DBUG)" instructions scattered 
> throughout, and when you look at what DBUG is defined as, it is defined 
> as an IO Port at IO address DBGP, which is a 1-byte value = 0x80.  So 
> the ACPI BIOS thinks it has something to do with debugging.   There's a 
> little strangeness here, however, because the value sent to the port 
> occasionally has something to do with arguments to the ACPI operations 
> relating to sleep and wakeup ...  could just be that those arguments are 
> distinctive.
> 

Dumb question: if you change your iodelay function so it always writes 
zero to port 0x80, does it start working?

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 16:15                                                         ` Alan Cox
  2008-01-01 16:43                                                           ` Ingo Molnar
  2008-01-01 17:32                                                           ` David P. Reed
@ 2008-01-01 21:15                                                           ` H. Peter Anvin
  2008-01-01 21:35                                                             ` Rene Herman
  2 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2008-01-01 21:15 UTC (permalink / raw)
  To: Alan Cox
  Cc: David P. Reed, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Alan Cox wrote:
>> 80 makes me suspicious.)   That might mean that the freeze happens only
>> when certain values are written, or when they are written closely in
>> time to some other action - being used to communicate something to the
>> SMM code).   If there is some race in when Linux's port 80 writes happen
>> that happen to change the meaning of a request to the hardware or to
>> SMM, then we could be rarely stepping on
> 
> That does imply some muppet 'extended' the debug interface for power
> management on your laptop. Also pretty much proves that for such systems
> we do have to move from port 0x80 to another delay approach.
> 
> Ingo - the fact that so many ISA bus devices need _p to mean "ISA bus
> clocks" says to me we should keep the _p port 0x80 using variant for old
> systems/device combinations (eg ISA ethernet cards) which won't show up
> in any problem system (we know this from 15 odd years of testing), but
> stop using it for PCI and embedded devices on modern systems.
> 

I have mentioned this before... I think writing zero to port 0xf0 would 
be an acceptable pause interface (to the extent where we need an I/O 
port) except on 386 with 387 present; on those systems we can fall back 
to 0x80.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 20:14                                                                 ` Christer Weinigel
@ 2008-01-01 21:13                                                                   ` Alan Cox
  0 siblings, 0 replies; 186+ messages in thread
From: Alan Cox @ 2008-01-01 21:13 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Ingo Molnar, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

> How do you find out the speed of the ISA bus?  AFAIK there is no
> standardized way to do that.  On the Geode SC2200 the ISA bus speed is

It is per chipset magic registers. Fun fun fun

> usually the PCI clock divided by 4 giving 33MHz/4=8.3MHz or
> 30/4=7.5MHz, but with no external ISA devices it's possible to
> overclock the ISA bus to /3 to run it at 11MHz or so.  But without

12MHz is valid for ISA although not a good idea - even IBM issued some
systems with 12MHz ISA before discovering many vendors had assumed 8 was
it.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 18:45                                                               ` Ingo Molnar
  2008-01-01 20:14                                                                 ` Christer Weinigel
@ 2008-01-01 21:07                                                                 ` Alan Cox
  2008-01-02 10:04                                                                   ` Ingo Molnar
  1 sibling, 1 reply; 186+ messages in thread
From: Alan Cox @ 2008-01-01 21:07 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: David P. Reed, H. Peter Anvin, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> > #1 udelay has to be for the worst case bus clock (6MHz) while the 
> > #device may be at 10Mhz or even 12MHz ISA. So it slows it down stuff
> > unneccessarily- and stuff that really really is slow enough as is.
> 
> udelay is supposed to be reliable. If someone runs a new kernel and has 
> no TSC (which might happen even on modern hardware or with notsc) _and_ 
> finds that udelay is not calibrated well enough then that's a kernel bug 
> we want to fix.

You miss the point entirely. The delay is in bus clocks not CPU clocks,
not tsc clocks not PIT clocks, and it is permitted to vary by a factor of
two. So you'll worst case halve the speed of network packet up/download
even if your udelay is accurate.

> > #2 Most of the ancient wind up relics with ISA bus don't have a tsc so
> > their udelay value is kind of iffy.
> 
> iffy in what way? Again, we might be hiding real udelay bugs.

As you say - its only a few instructions so small udelays tend to be
inaccurate - overlong.

> yes, there are always risks in changing something, but using udelay is a 
> common-sense consolidation of code.

Not for ISA bus hardware. For chipset logic, for PCI yes - for ISA stuff
no. It's all about ISA clocks not wall clocks.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 19:35                                                                 ` Christer Weinigel
  2008-01-01 19:59                                                                   ` Rene Herman
@ 2008-01-01 21:01                                                                   ` Ingo Molnar
  2008-01-01 21:26                                                                     ` Alan Cox
  2008-01-01 21:42                                                                     ` Christer Weinigel
  2008-01-01 21:21                                                                   ` H. Peter Anvin
  2 siblings, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2008-01-01 21:01 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol


* Christer Weinigel <christer@weinigel.se> wrote:

> On Tue, 1 Jan 2008 19:46:59 +0100
> Ingo Molnar <mingo@elte.hu> wrote:
> 
> > 
> > * Christer Weinigel <christer@weinigel.se> wrote:
> > 
> > > What I'm afraid is that udelay will be significantly slower, [...]
> > 
> > why should it be significantly slower?
> 
> out 80h, al is only two bytes.  Any alternative that has been 
> suggested in this discussion will use more space.  mov dx, alt_port; 
> out dx, al will be larger, a function call will definitely be a lot 
> larger. People have been making changes to the kernel to save a couple 
> of hundred bytes of text size.

i've done dozens of patches that saved much less of text size, so yes, i 
very much care about code size. But it has been stated in this thread 
that most of the _p() API uses in the kernel today are bogus. So 
eventually getting rid of the bogus ones will be a net code size 
_reduction_. (But even that is besides the point, we prefer clean and 
easier to maintain code.)

> I don't know if the difference in code size or the udelay will be 
> significantly slower, but I think it might be.

ok, "I dont know but it might be slower" is a perfectly fine statement 
instead of your original "it will be slower".

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 19:59                                                                   ` Rene Herman
@ 2008-01-01 20:55                                                                     ` Christer Weinigel
  2008-01-01 21:24                                                                       ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Christer Weinigel @ 2008-01-01 20:55 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Alan Cox, David P. Reed, H. Peter Anvin,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On Tue, 01 Jan 2008 20:59:20 +0100
Rene Herman <rene.herman@keyaccess.nl> wrote:

> On 01-01-08 20:35, Christer Weinigel wrote:
> 
> > On old hardware (or anything with an ISA bus which I'd guess
> > includes the Geode SCx200 SoC which is basically a MediaGX
> > processor, a southbridge and an ISA bus with a Super I/O chip on
> > it) an out to 80h will use exactly one ISA cycle.
> 
> Not to disagree with the point but more like 8 (1 us at 8 MHz). It's
> the timeout property.

Ah, sorry, you're right of course.

> > I'm not sure what Alan meant with his comments about locking, but if
> > changing outb_p to use an udelay means that we have to add locking,
> > that is also going to affect the code size and speed.
> 
> Explained here:
> 
> http://lkml.org/lkml/2007/12/30/136
> 
> However, that's not an argument. Missing locking is a bug, and
> current outb I/O delay use hiding it doesn't change that.

Thanks, I had missed that one.

Regarding Alan's comment:

>For that matter does anyone actually have video cards old enough for us
>to care actually still in use with Linux today ? 

I'm afraid that some PC104 systems may still use ancient video cards.

  /Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 18:45                                                               ` Ingo Molnar
@ 2008-01-01 20:14                                                                 ` Christer Weinigel
  2008-01-01 21:13                                                                   ` Alan Cox
  2008-01-01 21:07                                                                 ` Alan Cox
  1 sibling, 1 reply; 186+ messages in thread
From: Christer Weinigel @ 2008-01-01 20:14 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On Tue, 1 Jan 2008 19:45:24 +0100
Ingo Molnar <mingo@elte.hu> wrote:

> 
> * Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
> 
> > > there strong counter-arguments against doing the clean thing and 
> > > adding an udelay(2) (or udelay(1)) to replace those _p() uses in
> > > ISA drivers?
> > 
> > #1 udelay has to be for the worst case bus clock (6MHz) while the 
> > #device may be at 10Mhz or even 12MHz ISA. So it slows it down stuff
> > unneccessarily- and stuff that really really is slow enough as is.
> 
> udelay is supposed to be reliable. If someone runs a new kernel and
> has no TSC (which might happen even on modern hardware or with notsc)
> _and_ finds that udelay is not calibrated well enough then that's a
> kernel bug we want to fix.

How do you find out the speed of the ISA bus?  AFAIK there is no
standardized way to do that.  On the Geode SC2200 the ISA bus speed is
usually the PCI clock divided by 4 giving 33MHz/4=8.3MHz or
30/4=7.5MHz, but with no external ISA devices it's possible to
overclock the ISA bus to /3 to run it at 11MHz or so.  But without
poking at some CPU and southbridge specific registers to find out the
PCI bus speed and the ISA bus divisor you can't really tell.

So if you do udelay based on a 6MHz clock (I think you can safely
assume that any 386 based system runs the ISA bus at least that fast)
you'll waste at least 30% and maybe even 100% more time for the delay
after every _p call.

  /Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 19:35                                                                 ` Christer Weinigel
@ 2008-01-01 19:59                                                                   ` Rene Herman
  2008-01-01 20:55                                                                     ` Christer Weinigel
  2008-01-01 21:01                                                                   ` Ingo Molnar
  2008-01-01 21:21                                                                   ` H. Peter Anvin
  2 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2008-01-01 19:59 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Ingo Molnar, Alan Cox, David P. Reed, H. Peter Anvin,
	Rene Herman, Paul Rolland, Pavel Machek, Thomas Gleixner,
	linux-kernel, Ingo Molnar, rol

On 01-01-08 20:35, Christer Weinigel wrote:

> On Tue, 1 Jan 2008 19:46:59 +0100
> Ingo Molnar <mingo@elte.hu> wrote:
> 
>> * Christer Weinigel <christer@weinigel.se> wrote:
>>
>>> What I'm afraid is that udelay will be significantly slower, [...]
>> why should it be significantly slower?
> 
> out 80h, al is only two bytes.  Any alternative that has been suggested
> in this discussion will use more space.  mov dx, alt_port; out dx, al
> will be larger, a function call will definitely be a lot larger. People
> have been making changes to the kernel to save a couple of hundred
> bytes of text size.
> 
> On old hardware (or anything with an ISA bus which I'd guess includes
> the Geode SCx200 SoC which is basically a MediaGX processor, a
> southbridge and an ISA bus with a Super I/O chip on it) an out to 80h
> will use exactly one ISA cycle.

Not to disagree with the point but more like 8 (1 us at 8 MHz). It's the 
timeout property.

> A call to udelay will need a margin,
> so it will be slightly slower.  And that's assuming that you can find
> out the speed of the ISA bus, if you can't you'll have to assume the
> slowest possible bus (6 MHz I guess) which will be a lot slower.
> 
> I don't know if the difference in code size or the udelay will be
> significantly slower, but I think it might be.

There's also the bit about microseconds being very losely defined pre 
loops_per_jiffy calibration. Per CPU-family init helps somewhat but 
certainly for family 6 (Pentium Pro, II, III -- lots of hardware with ISA 
busses therefore) speeds vary quite a bit still.

> And to take the MediaGX as an example, the TSC is not usable on that
> CPU, so Linux has to use the PIT timer for gettimeofday.  As I wrote
> in a different post, I believe the PIT on the SCx200 needs outb_p to
> work reliably.  So if outb_p becomes significantly slower that will
> affect a critical path on a very common embedded CPU.
> 
> I'm not sure what Alan meant with his comments about locking, but if
> changing outb_p to use an udelay means that we have to add locking,
> that is also going to affect the code size and speed.

Explained here:

http://lkml.org/lkml/2007/12/30/136

However, that's not an argument. Missing locking is a bug, and current outb 
I/O delay use hiding it doesn't change that.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 18:46                                                               ` Ingo Molnar
@ 2008-01-01 19:35                                                                 ` Christer Weinigel
  2008-01-01 19:59                                                                   ` Rene Herman
                                                                                     ` (2 more replies)
  0 siblings, 3 replies; 186+ messages in thread
From: Christer Weinigel @ 2008-01-01 19:35 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On Tue, 1 Jan 2008 19:46:59 +0100
Ingo Molnar <mingo@elte.hu> wrote:

> 
> * Christer Weinigel <christer@weinigel.se> wrote:
> 
> > What I'm afraid is that udelay will be significantly slower, [...]
> 
> why should it be significantly slower?

out 80h, al is only two bytes.  Any alternative that has been suggested
in this discussion will use more space.  mov dx, alt_port; out dx, al
will be larger, a function call will definitely be a lot larger. People
have been making changes to the kernel to save a couple of hundred
bytes of text size.

On old hardware (or anything with an ISA bus which I'd guess includes
the Geode SCx200 SoC which is basically a MediaGX processor, a
southbridge and an ISA bus with a Super I/O chip on it) an out to 80h
will use exactly one ISA cycle.  A call to udelay will need a margin,
so it will be slightly slower.  And that's assuming that you can find
out the speed of the ISA bus, if you can't you'll have to assume the
slowest possible bus (6 MHz I guess) which will be a lot slower.

I don't know if the difference in code size or the udelay will be
significantly slower, but I think it might be.

And to take the MediaGX as an example, the TSC is not usable on that
CPU, so Linux has to use the PIT timer for gettimeofday.  As I wrote
in a different post, I believe the PIT on the SCx200 needs outb_p to
work reliably.  So if outb_p becomes significantly slower that will
affect a critical path on a very common embedded CPU.

I'm not sure what Alan meant with his comments about locking, but if
changing outb_p to use an udelay means that we have to add locking,
that is also going to affect the code size and speed.

  /Christer






^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 17:32                                                             ` Christer Weinigel
@ 2008-01-01 18:46                                                               ` Ingo Molnar
  2008-01-01 19:35                                                                 ` Christer Weinigel
  0 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2008-01-01 18:46 UTC (permalink / raw)
  To: Christer Weinigel
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol


* Christer Weinigel <christer@weinigel.se> wrote:

> What I'm afraid is that udelay will be significantly slower, [...]

why should it be significantly slower?

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 17:32                                                             ` Alan Cox
@ 2008-01-01 18:45                                                               ` Ingo Molnar
  2008-01-01 20:14                                                                 ` Christer Weinigel
  2008-01-01 21:07                                                                 ` Alan Cox
  0 siblings, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2008-01-01 18:45 UTC (permalink / raw)
  To: Alan Cox
  Cc: David P. Reed, H. Peter Anvin, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > there strong counter-arguments against doing the clean thing and 
> > adding an udelay(2) (or udelay(1)) to replace those _p() uses in ISA 
> > drivers?
> 
> #1 udelay has to be for the worst case bus clock (6MHz) while the 
> #device may be at 10Mhz or even 12MHz ISA. So it slows it down stuff
> unneccessarily- and stuff that really really is slow enough as is.

udelay is supposed to be reliable. If someone runs a new kernel and has 
no TSC (which might happen even on modern hardware or with notsc) _and_ 
finds that udelay is not calibrated well enough then that's a kernel bug 
we want to fix.

> #2 Most of the ancient wind up relics with ISA bus don't have a tsc so
> their udelay value is kind of iffy.

iffy in what way? Again, we might be hiding real udelay bugs.

> #3 Not changing it is the lowest risk for a lot of the old ISA code 
> #that never occurs on newer boxes

Not changing the kernel _at all_ is what is the "lowest risk" option. If 
the kernel is changed, it should be tested - and if we have a buggy 
udelay, that should be fixed - because it could cause many other bugs in 
other drivers.

yes, there are always risks in changing something, but using udelay is a 
common-sense consolidation of code.

> > _will_ change a bit, no matter what we do. Alignments change, the 
> > compiler output will change (old compilers get deprecated so a new 
> > compiler might have to be picked), cache effects change - and this 
> > is inevitable. The important thing is to not eliminate the delays - 
> > but we sure dont have to keep them cycle accurate (we couldnt even 
> > if we wanted to). The only way to get the _exact same_ behavior is 
> > to not change the kernel at all.
> 
> ISA bus cycles are *slow*, the subtle processor cache and gcc 
> triggered timing changes are lost in the noise.

gcc triggered timing changes can easily add up to a LOT more - 
especially if a loop is involved and especially on older hardware. 
Remember, 1 microsecond is just a handful of instructions on real old 
hardware. The kernel's timings are _not_ immutable, never were, never 
will be.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 17:32                                                           ` David P. Reed
@ 2008-01-01 17:38                                                             ` Alan Cox
  0 siblings, 0 replies; 186+ messages in thread
From: Alan Cox @ 2008-01-01 17:38 UTC (permalink / raw)
  To: David P. Reed
  Cc: H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> 80 diagnostic codes and sending them to the "drawer" management 
> processor through a management backplane.   This is a little puzzling, 
> because you'd think they would have noticed port 80 issues, since they 
> run Linux in their systems.  Maybe not hangs, but it seems unhelpful to 

Most of the chipsets let you turn it on and off so presumably the BIOS
turns it off before running Linux. Thats certainly done by several
chipsets and we recently had a bug where a BIOS forgot to turn them off
which confused someones parallel port devices.

> Anyone know if the Linux kernels used on blade servers have been patched 
> to not do the port 80 things?  I don't think this would break anything 

I'm not aware of such, or requests for them.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 17:31                                                         ` Pavel Machek
@ 2008-01-01 17:33                                                           ` David P. Reed
  0 siblings, 0 replies; 186+ messages in thread
From: David P. Reed @ 2008-01-01 17:33 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Alan Cox, H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Pavel Machek wrote:
>> 2. there is some "meaning" to certain byte values being written (the
>> _PTS and _WAK use of arguments that come from callers to store into port
>> 80 makes me suspicious.)   That might mean that the freeze happens only
>> when certain values are written, or when they are written closely in
>> time to some other action - being used to communicate something to the
>>     
>
> There's nothing easier than always writing 0 to the 0x80 to check if
> it hangs in such case...?
> 								Pavel
>
>   
I did try that.  Machine in question does hang when you write 0 to 0x80 
in a loop a few thousand times.  This particular suspicion was that the 
problem was caused by the following sort of thing (it's a multi-cpu 
system...)

First, some ACPI code writes "meaningful value" X to  port 80 that is 
sort of a "parameter" to whatever follows.  Just because the DSDT 
disassembly *calls* it the DBUG port doesn't mean it is *only* used for 
debugging.   We (Linux) use it for timing delays, after all...

 then Linux driver writes some random value (!=X) including zero to port 80.

then ACPI writes some other values that cause SMI or some other thing to 
happen,

There are experiments that are not so simple that could rule this 
particular guess out.   I have them on my queue of experiments I might 
try (locking out ACPI).  Of course if the BIOS were GPL, we could look 
at the comments, etc...

I may today pull the laptop apart to see if I can see what chips are on 
it, besides the nvidia chipset and the processor.  That might give a 
clue as to what SuperIO or other logic chips are there.


 

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 16:15                                                         ` Alan Cox
  2008-01-01 16:43                                                           ` Ingo Molnar
@ 2008-01-01 17:32                                                           ` David P. Reed
  2008-01-01 17:38                                                             ` Alan Cox
  2008-01-01 21:15                                                           ` H. Peter Anvin
  2 siblings, 1 reply; 186+ messages in thread
From: David P. Reed @ 2008-01-01 17:32 UTC (permalink / raw)
  To: Alan Cox
  Cc: H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


Alan Cox wrote:
> That does imply some muppet 'extended' the debug interface for power
> management on your laptop. Also pretty much proves that for such systems
> we do have to move from port 0x80 to another delay approach.
>   
Alan - in googling around the net yesterday looking for SuperIO chipsets 
that claim to support port 80, I have found that "blade" servers from 
companies like IBM and HP *claim* to have a system for monitoring port 
80 diagnostic codes and sending them to the "drawer" management 
processor through a management backplane.   This is a little puzzling, 
because you'd think they would have noticed port 80 issues, since they 
run Linux in their systems.  Maybe not hangs, but it seems unhelpful to 
have a lot of noise spewing over a bus that is supposed to provide 
"management" diagnostics.  Anyway, what I did not find was whether there 
was a particular chipset that provided that port 80 feature on those 
machines.  However, if it's a common "cell" in a design, it may have 
leaked into the notebook market chipsets too.

Anyone know if the Linux kernels used on blade servers have been patched 
to not do the port 80 things?  I don't think this would break anything 
there, but it might have been a helpful patch for their purposes.  I 
don't do blades personally or at work (I focus on mobile devices these 
days, and my personal servers are discrete), so I have no knowledge.

It could be that the blade servers have BIOSes that don't do POST codes 
over port 80, but send them directly to the "drawer" management bus, of 
course.  

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 16:43                                                           ` Ingo Molnar
  2008-01-01 17:32                                                             ` Alan Cox
@ 2008-01-01 17:32                                                             ` Christer Weinigel
  2008-01-01 18:46                                                               ` Ingo Molnar
  1 sibling, 1 reply; 186+ messages in thread
From: Christer Weinigel @ 2008-01-01 17:32 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Rene Herman,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On Tue, 1 Jan 2008 17:43:38 +0100
Ingo Molnar <mingo@elte.hu> wrote:

> if someone runs a fresh new kernel on an ancient device then timings 
> _will_ change a bit, no matter what we do. Alignments change, the 
> compiler output will change (old compilers get deprecated so a new 
> compiler might have to be picked), cache effects change - and this is 
> inevitable. The important thing is to not eliminate the delays - but
> we sure dont have to keep them cycle accurate (we couldnt even if we
> wanted to). The only way to get the _exact same_ behavior is to not
> change the kernel at all.

What I'm afraid is that udelay will be significantly slower, which
might hit anything that does a lot of gettimeofday calls (poking at the
PIT timer)  on embedded 386/486 systems.  On the other hand, those
systems might not want to upgrade to 2.6 anyway.  

And why do people keep buying HP hardware?  HP seem to be quite
Linux-unfriendly on the desktop [1] and on their laptops.  Apparently
HP doesn't even bother to try Linux on any of their non-server systems.

[1] Try running Linux on a HP DC7700 machine, there seems to be a lot
of magic stuff in those machines that doesn't work well with Linux.
They had some ACPI crap that stopped FC7 from booting without a lot of
magic PCI access options and audio still does not work.  

/Christer

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 16:43                                                           ` Ingo Molnar
@ 2008-01-01 17:32                                                             ` Alan Cox
  2008-01-01 18:45                                                               ` Ingo Molnar
  2008-01-01 17:32                                                             ` Christer Weinigel
  1 sibling, 1 reply; 186+ messages in thread
From: Alan Cox @ 2008-01-01 17:32 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: David P. Reed, H. Peter Anvin, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> there strong counter-arguments against doing the clean thing and adding 
> an udelay(2) (or udelay(1)) to replace those _p() uses in ISA drivers? 

#1 udelay has to be for the worst case bus clock (6MHz) while the device
may be at 10Mhz or even 12MHz ISA. So it slows it down stuff
unneccessarily- and stuff that really really is slow enough as is.

#2 Most of the ancient wind up relics with ISA bus don't have a tsc so
their udelay value is kind of iffy.

#3 Not changing it is the lowest risk for a lot of the old ISA code that
never occurs on newer boxes

If we have an isa_inb_p() as a specific statement of "I am doing an ISA
bus dependant delay on ancient crap hardware" then we can avoid the risk
of breakage. We wouldn't use it for non ISA, and certainly not for stuff
like chipset logic which requires a more thorough fix as it occurs on all
kinds of boxes.

> _will_ change a bit, no matter what we do. Alignments change, the 
> compiler output will change (old compilers get deprecated so a new 
> compiler might have to be picked), cache effects change - and this is 
> inevitable. The important thing is to not eliminate the delays - but we 
> sure dont have to keep them cycle accurate (we couldnt even if we wanted 
> to). The only way to get the _exact same_ behavior is to not change the 
> kernel at all.

ISA bus cycles are *slow*, the subtle processor cache and gcc triggered
timing changes are lost in the noise.

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 15:59                                                       ` David P. Reed
  2008-01-01 16:15                                                         ` Alan Cox
@ 2008-01-01 17:31                                                         ` Pavel Machek
  2008-01-01 17:33                                                           ` David P. Reed
  1 sibling, 1 reply; 186+ messages in thread
From: Pavel Machek @ 2008-01-01 17:31 UTC (permalink / raw)
  To: David P. Reed
  Cc: Alan Cox, H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Hi!

> 1. It appears to be a real port.  SMI traps are not happening in the
> normal outb to 80.  Hundreds of them execute perfectly with the expected
> instruction counts.  If I can trace the particular event that creates
> the hard freeze (getting really creative, here) and stop before the
> freeze disables the entire computer, I will.  That may be an SMI, or
> perhaps any other kind of interrupt or exception.  Maybe someone knows
> how to safely trace through an impending SMI while doing printk's or
> something?
> 
> 2. It appears to be the standard POST diagnostic port.  On a whim, I
> disassembled my DSDT code, and studied it more closely.   It turns out
> that there are a bunch of "Store(..., DBUG)" instructions scattered
> throughout, and when you look at what DBUG is defined as, it is defined
> as an IO Port at IO address DBGP, which is a 1-byte value = 0x80.  So
> the ACPI BIOS thinks it has something to do with debugging.   There's a
> little strangeness here, however, because the value sent to the port
> occasionally has something to do with arguments to the ACPI operations
> relating to sleep and wakeup ...  could just be that those arguments are
> distinctive.

Maybe someone just left debugging code in production?

> In thinking about this, I recognize a couple of things.  ACPI is telling
> us something when it declares a reference to port 80 in its code.  It's
> not telling us the function of this port on this machine, but it is
> telling us that it is being used by the BIOS.   This could be a reason
> to put out a printk warning message...   'warning: port 80 is used by
> ACPI BIOS - if you are experiencing problems, you might try an alternate
> means of iodelay.'
> 
> Second, it seems likely that there are one of two possible reasons that
> the port 80 writes cause hang/freezes:
> 
> 1. buffer overflow in such a device.
> 
> 2. there is some "meaning" to certain byte values being written (the
> _PTS and _WAK use of arguments that come from callers to store into port
> 80 makes me suspicious.)   That might mean that the freeze happens only
> when certain values are written, or when they are written closely in
> time to some other action - being used to communicate something to the

There's nothing easier than always writing 0 to the 0x80 to check if
it hangs in such case...?
								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 16:15                                                         ` Alan Cox
@ 2008-01-01 16:43                                                           ` Ingo Molnar
  2008-01-01 17:32                                                             ` Alan Cox
  2008-01-01 17:32                                                             ` Christer Weinigel
  2008-01-01 17:32                                                           ` David P. Reed
  2008-01-01 21:15                                                           ` H. Peter Anvin
  2 siblings, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2008-01-01 16:43 UTC (permalink / raw)
  To: Alan Cox
  Cc: David P. Reed, H. Peter Anvin, Rene Herman, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> Ingo - the fact that so many ISA bus devices need _p to mean "ISA bus 
> clocks" says to me we should keep the _p port 0x80 using variant for 
> old systems/device combinations (eg ISA ethernet cards) which won't 
> show up in any problem system (we know this from 15 odd years of 
> testing), but stop using it for PCI and embedded devices on modern 
> systems.

yes, ISA is fragile, and no way do we want to remove the delay, but are 
there strong counter-arguments against doing the clean thing and adding 
an udelay(2) (or udelay(1)) to replace those _p() uses in ISA drivers? 
That removes the global effect once and forever. Initially for 
standalone drivers without early bootup functionality, not platform 
drivers that might need to run before we have calibrated udelay.

if someone runs a fresh new kernel on an ancient device then timings 
_will_ change a bit, no matter what we do. Alignments change, the 
compiler output will change (old compilers get deprecated so a new 
compiler might have to be picked), cache effects change - and this is 
inevitable. The important thing is to not eliminate the delays - but we 
sure dont have to keep them cycle accurate (we couldnt even if we wanted 
to). The only way to get the _exact same_ behavior is to not change the 
kernel at all.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2008-01-01 15:59                                                       ` David P. Reed
@ 2008-01-01 16:15                                                         ` Alan Cox
  2008-01-01 16:43                                                           ` Ingo Molnar
                                                                             ` (2 more replies)
  2008-01-01 17:31                                                         ` Pavel Machek
  1 sibling, 3 replies; 186+ messages in thread
From: Alan Cox @ 2008-01-01 16:15 UTC (permalink / raw)
  To: David P. Reed
  Cc: H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> 80 makes me suspicious.)   That might mean that the freeze happens only
> when certain values are written, or when they are written closely in
> time to some other action - being used to communicate something to the
> SMM code).   If there is some race in when Linux's port 80 writes happen
> that happen to change the meaning of a request to the hardware or to
> SMM, then we could be rarely stepping on

That does imply some muppet 'extended' the debug interface for power
management on your laptop. Also pretty much proves that for such systems
we do have to move from port 0x80 to another delay approach.

Ingo - the fact that so many ISA bus devices need _p to mean "ISA bus
clocks" says to me we should keep the _p port 0x80 using variant for old
systems/device combinations (eg ISA ethernet cards) which won't show up
in any problem system (we know this from 15 odd years of testing), but
stop using it for PCI and embedded devices on modern systems.

Alan


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:25                                                     ` Alan Cox
  2008-01-01 15:57                                                       ` David P. Reed
@ 2008-01-01 15:59                                                       ` David P. Reed
  2008-01-01 16:15                                                         ` Alan Cox
  2008-01-01 17:31                                                         ` Pavel Machek
  1 sibling, 2 replies; 186+ messages in thread
From: David P. Reed @ 2008-01-01 15:59 UTC (permalink / raw)
  To: Alan Cox
  Cc: H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 3215 bytes --]

[attached the DSDT.dsl file fyi]

Alan Cox wrote:
>> responds to reads differently than "unused" ports.  In particular, an 
>> inb takes 1/2 the elapsed time compared to a read to "known" unused port 
>> 0xed - 792 tsc ticks for port 80 compared to about 1450 tsc ticks for 
>> port 0xed and other unused ports (tsc at 800 MHz).
>>     
>
> Well at least we know where the port is now - thats too fast for an LPC
> bus device, so it must be an SMI trap.
>
> Only easy way to find out is to use the debugging event counters and see
> how many instruction cycles are issued as part of the 0x80 port. If its
> suprisingly high then you've got a firmware bug and can go spank HP.
>
>   
Alan, thank you for the pointers.  I have been doing variations on this
testing theme for a while - I get intrigued by a good debugging
challenge, and after all it's my machine...

Two relevant new data points, and then some more suggestions:

1. It appears to be a real port.  SMI traps are not happening in the
normal outb to 80.  Hundreds of them execute perfectly with the expected
instruction counts.  If I can trace the particular event that creates
the hard freeze (getting really creative, here) and stop before the
freeze disables the entire computer, I will.  That may be an SMI, or
perhaps any other kind of interrupt or exception.  Maybe someone knows
how to safely trace through an impending SMI while doing printk's or
something?

2. It appears to be the standard POST diagnostic port.  On a whim, I
disassembled my DSDT code, and studied it more closely.   It turns out
that there are a bunch of "Store(..., DBUG)" instructions scattered
throughout, and when you look at what DBUG is defined as, it is defined
as an IO Port at IO address DBGP, which is a 1-byte value = 0x80.  So
the ACPI BIOS thinks it has something to do with debugging.   There's a
little strangeness here, however, because the value sent to the port
occasionally has something to do with arguments to the ACPI operations
relating to sleep and wakeup ...  could just be that those arguments are
distinctive.

In thinking about this, I recognize a couple of things.  ACPI is telling
us something when it declares a reference to port 80 in its code.  It's
not telling us the function of this port on this machine, but it is
telling us that it is being used by the BIOS.   This could be a reason
to put out a printk warning message...   'warning: port 80 is used by
ACPI BIOS - if you are experiencing problems, you might try an alternate
means of iodelay.'

Second, it seems likely that there are one of two possible reasons that
the port 80 writes cause hang/freezes:

1. buffer overflow in such a device.

2. there is some "meaning" to certain byte values being written (the
_PTS and _WAK use of arguments that come from callers to store into port
80 makes me suspicious.)   That might mean that the freeze happens only
when certain values are written, or when they are written closely in
time to some other action - being used to communicate something to the
SMM code).   If there is some race in when Linux's port 80 writes happen
that happen to change the meaning of a request to the hardware or to
SMM, then we could be rarely stepping on





[-- Attachment #2: DSDT.dsl --]
[-- Type: text/x-dsl, Size: 280554 bytes --]

/*
 * Intel ACPI Component Architecture
 * AML Disassembler version 20061109
 *
 * Disassembly of DSDT.dat, Wed Nov 21 17:02:51 2007
 *
 *
 * Original Table Header:
 *     Signature        "DSDT"
 *     Length           0x00008FB0 (36784)
 *     Revision         0x01
 *     OEM ID           "HP    "
 *     OEM Table ID     "MCP51M"
 *     OEM Revision     0x06040000 (100925440)
 *     Creator ID       "MSFT"
 *     Creator Revision 0x03000000 (50331648)
 */
DefinitionBlock ("DSDT.aml", "DSDT", 1, "HP    ", "MCP51M", 0x06040000)
{
    External (\_PR_.CPU0._PPC)

    Name (\_S0, Package (0x04)
    {
        0x00, 
        0x00, 
        0x00, 
        0x00
    })
    Name (\_S3, Package (0x04)
    {
        0x05, 
        0x05, 
        0x00, 
        0x00
    })
    Name (\_S4, Package (0x04)
    {
        0x06, 
        0x06, 
        0x00, 
        0x00
    })
    Name (\_S5, Package (0x04)
    {
        0x07, 
        0x07, 
        0x00, 
        0x00
    })
    Name (SX, 0x00)
    Method (\_PTS, 1, NotSerialized)
    {
        Store (Arg0, DBUG)
        If (LEqual (Arg0, 0x03))
        {
            Store (0x04, GP23)
            Store (0x04, GP24)
        }

        If (LEqual (Arg0, 0x04))
        {
            Store (0x04, GP23)
            Store (0x04, GP24)
            If (LEqual (OSYS, 0x07D6))
            {
                Or (PSMI, 0x01, PSMI)
            }
            Else
            {
                And (PSMI, 0xFE, PSMI)
            }
        }

        If (LEqual (Arg0, 0x05))
        {
            Acquire (\_SB.PCI0.PSMX, 0xFFFF)
            Store (0x8F, \_SB.PCI0.SMIC)
            Store (\_SB.PCI0.SMIS, Local0)
            Release (\_SB.PCI0.PSMX)
        }

        If (LGreater (Arg0, 0x01))
        {
            Store (Zero, LDTC)
            Store (0x04, Z000)
            Store (0x04, Z001)
            Store (0x04, Z002)
        }
    }

    Method (\_WAK, 1, NotSerialized)
    {
        Store (Arg0, DBUG)
        If (LEqual (Arg0, 0x03))
        {
            Acquire (\_SB.PCI0.PSMX, 0xFFFF)
            Store (0x84, \_SB.PCI0.SMIC)
            Store (\_SB.PCI0.SMIS, Local0)
            Release (\_SB.PCI0.PSMX)
            And (GP23, 0x0F, GP26)
            If (LEqual (GP26, 0x05))
            {
                Store (0x01, GP26)
            }
            Else
            {
                Store (0x00, GP26)
            }

            And (GP24, 0x0F, GP25)
            If (LEqual (GP25, 0x05))
            {
                Store (0x01, GP25)
            }
            Else
            {
                Store (0x00, GP25)
            }

            Notify (\_SB.PWRB, 0x02)
            Z003 ()
        }

        If (LEqual (Arg0, 0x04))
        {
            Acquire (\_SB.PCI0.PSMX, 0xFFFF)
            Store (0x85, \_SB.PCI0.SMIC)
            Store (\_SB.PCI0.SMIS, Local0)
            Release (\_SB.PCI0.PSMX)
            And (GP23, 0x0F, GP26)
            If (LEqual (GP26, 0x05))
            {
                Store (0x01, GP26)
            }
            Else
            {
                Store (0x00, GP26)
            }

            And (GP24, 0x0F, GP25)
            If (LEqual (GP25, 0x05))
            {
                Store (0x01, GP25)
            }
            Else
            {
                Store (0x00, GP25)
            }

            Store (Zero, S4FL)
            Store (Zero, S4RT)
            Notify (\_SB.PWRB, 0x02)
            Z003 ()
        }
    }

    Method (Z003, 0, NotSerialized)
    {
        If (LEqual (HOTB, 0x04))
        {
            Notify (\_SB.QBTN, 0x02)
        }

        If (LEqual (HOTB, 0x05))
        {
            Notify (\_SB.DBTN, 0x02)
        }

        If (LEqual (HOTB, 0x03))
        {
            Notify (\_SB.MUBN, 0x02)
        }

        If (LEqual (HOTB, 0x06))
        {
            Notify (\_SB.PIBN, 0x02)
        }

        If (LEqual (HOTB, 0x10))
        {
            Notify (\_SB.WEBN, 0x02)
        }

        If (LEqual (HOTB, 0x11))
        {
            Notify (\_SB.LVBN, 0x02)
        }

        If (LEqual (HOTB, 0x12))
        {
            Notify (\_SB.VOBN, 0x02)
        }

        Store (0x00, HOTB)
    }

    Scope (\_PR)
    {
        Processor (CPU0, 0x00, 0x00001010, 0x06) {}
        Processor (CPU1, 0x01, 0x00001010, 0x06) {}
    }

    Scope (\_SI)
    {
        Method (_SST, 1, NotSerialized)
        {
            Store ("==== SST Working ====", Debug)
        }

        Method (_MSG, 1, NotSerialized)
        {
        }
    }

    Scope (\_GPE)
    {
        Method (_L14, 0, NotSerialized)
        {
            If (PEWS)
            {
                Store (0x01, PEWS)
            }

            Notify (\_SB.PCI0.XVR1, 0x00)
            Notify (\_SB.PCI0.XVR2, 0x01)
        }

        Method (_L0B, 0, NotSerialized)
        {
            Store (0x0B, DBUG)
            Notify (\_SB.PCI0.MAC0, 0x02)
        }
    }

    Scope (\_SB)
    {
        Device (MCFG)
        {
            Name (_HID, EisaId ("PNP0C02"))
            Name (_CRS, ResourceTemplate ()
            {
                DWordMemory (ResourceConsumer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
                    0x00000000,         // Granularity
                    0xE0000000,         // Range Minimum
                    0xEFFFFFFF,         // Range Maximum
                    0x00000000,         // Translation Offset
                    0x10000000,         // Length
                    ,, , AddressRangeMemory, TypeStatic)
            })
        }

        Device (PWRB)
        {
            Name (_HID, EisaId ("PNP0C0C"))
            Method (_STA, 0, NotSerialized)
            {
                Return (0x0B)
            }
        }

        Device (SLPB)
        {
            Name (_HID, EisaId ("PNP0C0E"))
        }

        Device (ACAD)
        {
            Name (_HID, "ACPI0003")
            Name (_PCL, Package (0x01)
            {
                \_SB
            })
            Method (_PSR, 0, NotSerialized)
            {
                If (ECON)
                {
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    Store (\_SB.PCI0.EC0.ACIN, Local0)
                    Release (\_SB.PCI0.EC0.MUT0)
                    If (RBRF)
                    {
                        \_SB.PCI0.EC0.RSBR ()
                        Store (0x00, RBRF)
                    }

                    If (Local0)
                    {
                        Return (0x01)
                    }
                    Else
                    {
                        Return (0x00)
                    }
                }
                Else
                {
                    Return (0x01)
                }
            }
        }

        Method (VTOB, 1, NotSerialized)
        {
            Store (0x01, Local0)
            ShiftLeft (Local0, Arg0, Local0)
            Return (Local0)
        }

        Method (BTOV, 1, NotSerialized)
        {
            ShiftRight (Arg0, 0x01, Local0)
            Store (0x00, Local1)
            While (Local0)
            {
                Increment (Local1)
                ShiftRight (Local0, 0x01, Local0)
            }

            Return (Local1)
        }

        Method (MKWD, 2, NotSerialized)
        {
            If (And (Arg1, 0x80))
            {
                Store (0xFFFF0000, Local0)
            }
            Else
            {
                Store (Zero, Local0)
            }

            Or (Local0, Arg0, Local0)
            Or (Local0, ShiftLeft (Arg1, 0x08), Local0)
            Return (Local0)
        }

        Method (POSW, 1, NotSerialized)
        {
            If (And (Arg0, 0x8000))
            {
                If (LEqual (Arg0, 0xFFFF))
                {
                    Return (0xFFFFFFFF)
                }
                Else
                {
                    Not (Arg0, Local0)
                    Increment (Local0)
                    And (Local0, 0xFFFF, Local0)
                    Return (Local0)
                }
            }
            Else
            {
                Return (Arg0)
            }
        }

        Method (GBFE, 3, NotSerialized)
        {
            CreateByteField (Arg0, Arg1, TIDX)
            Store (TIDX, Arg2)
        }

        Method (PBFE, 3, NotSerialized)
        {
            CreateByteField (Arg0, Arg1, TIDX)
            Store (Arg2, TIDX)
        }

        Method (ITOS, 1, NotSerialized)
        {
            Store (Buffer (0x05)
                {
                    0x20, 0x20, 0x20, 0x20, 0x20
                }, Local0)
            Store (Buffer (0x11)
                {
                    "0123456789ABCDEF"
                }, Local7)
            Store (0x05, Local1)
            Store (0x00, Local2)
            Store (0x00, Local3)
            While (Local1)
            {
                Decrement (Local1)
                And (ShiftRight (Arg0, ShiftLeft (Local1, 0x02)), 0x0F, Local4)
                GBFE (Local7, Local4, RefOf (Local5))
                PBFE (Local0, Local2, Local5)
                Increment (Local2)
            }

            Return (Local0)
        }

        Device (BAT0)
        {
            Name (_HID, EisaId ("PNP0C0A"))
            Name (_PCL, Package (0x01)
            {
                \_SB
            })
            Name (PBIF, Package (0x0D)
            {
                0x01, 
                0xFFFFFFFF, 
                0xFFFFFFFF, 
                0x01, 
                0xFFFFFFFF, 
                0xFA, 
                0x96, 
                0x0A, 
                0x19, 
                "BAT1", 
                " ", 
                " ", 
                " "
            })
            Name (PBST, Package (0x04)
            {
                0x00, 
                0xFFFFFFFF, 
                0xFFFFFFFF, 
                0x2710
            })
            Name (BAST, 0x00)
            Name (B1ST, 0x0F)
            Name (B1WT, 0x00)
            Method (_STA, 0, NotSerialized)
            {
                If (ECON)
                {
                    If (\_SB.PCI0.EC0.MBTS)
                    {
                        Store (0x1F, B1ST)
                    }
                    Else
                    {
                        Store (0x0F, B1ST)
                    }
                }
                Else
                {
                    Store (0x0F, B1ST)
                }

                Return (B1ST)
            }

            Method (_BIF, 0, NotSerialized)
            {
                If (LEqual (B1ST, 0x1F))
                {
                    UPBI ()
                }
                Else
                {
                    IVBI ()
                }

                Return (PBIF)
            }

            Method (_BST, 0, NotSerialized)
            {
                If (LEqual (B1ST, 0x1F))
                {
                    UPBS ()
                }
                Else
                {
                    IVBS ()
                }

                Return (PBST)
            }

            Method (UPBI, 0, NotSerialized)
            {
                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                If (LNot (\_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x10, RefOf (Local5))))
                {
                    If (LAnd (Local5, LNot (And (Local5, 0x8000))))
                    {
                        ShiftRight (Local5, 0x05, Local5)
                        ShiftLeft (Local5, 0x05, Local5)
                        Store (Local5, Index (PBIF, 0x02))
                        Divide (Local5, 0x64, , Local2)
                        Add (Local2, 0x01, Local2)
                        Multiply (Local2, 0x05, Local4)
                        Add (Local4, 0x02, Index (PBIF, 0x05))
                        Multiply (Local2, 0x03, Local4)
                        Add (Local4, 0x02, Index (PBIF, 0x06))
                    }
                }

                Store (0x1770, Index (PBIF, 0x01))
                Store (0x39D0, Index (PBIF, 0x04))
                Store ("Primary", Index (PBIF, 0x09))
                Store ("LION", Index (PBIF, 0x0B))
                Store ("Hewlett-Packard", Index (PBIF, 0x0C))
                Store (0x01, Index (PBIF, 0x00))
                Release (\_SB.PCI0.EC0.MUT0)
            }

            Method (UPUM, 0, NotSerialized)
            {
                Store (Buffer (0x0B)
                    {
                        /* 0000 */    0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 
                        /* 0008 */    0x00, 0x00, 0x00
                    }, Local0)
                Store (Buffer (0x05)
                    {
                        0x36, 0x35, 0x35, 0x33, 0x35
                    }, Local6)
                Store (Buffer (0x05)
                    {
                        0x31, 0x32, 0x33, 0x32, 0x31
                    }, Local7)
                If (LNot (\_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x1B, RefOf (Local5))))
                {
                    Divide (Local5, 0x0200, , Local1)
                    Subtract (Local5, Multiply (Local1, 0x0200, Local2), Local5)
                    Multiply (Subtract (Local1, 0x0A, Local1), 0x03E8, Local1)
                    Divide (Local5, 0x20, , Local2)
                    Subtract (Local5, Multiply (Local2, 0x20, Local3), Local3)
                    Add (Multiply (Decrement (Local2), 0x1E, Local5), Local3, Local5)
                    Add (Local1, Local5, Local5)
                    Store (ITOS (ToBCD (Local5)), Local7)
                }

                If (LNot (\_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x1C, RefOf (Local5))))
                {
                    Store (ITOS (ToBCD (Local5)), Local6)
                }

                Store (0x05, Local1)
                Store (0x00, Local2)
                Store (0x00, Local3)
                While (Local1)
                {
                    Decrement (Local1)
                    GBFE (Local6, Local2, RefOf (Local5))
                    PBFE (Local0, Local3, Local5)
                    Increment (Local2)
                    Increment (Local3)
                }

                Increment (Local3)
                Store (0x00, Local2)
                Store (0x05, Local1)
                While (Local1)
                {
                    Decrement (Local1)
                    GBFE (Local7, Local2, RefOf (Local5))
                    PBFE (Local0, Local3, Local5)
                    Increment (Local2)
                    Increment (Local3)
                }

                Store (Local0, Index (PBIF, 0x0A))
                Store ("Hewlett-Packard", Index (PBIF, 0x0C))
            }

            Method (UPBS, 0, NotSerialized)
            {
                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                Store (\_SB.PCI0.EC0.MBRM, Local5)
                If (LNot (And (Local5, 0x8000)))
                {
                    ShiftRight (Local5, 0x05, Local5)
                    ShiftLeft (Local5, 0x05, Local5)
                    If (LNotEqual (Local5, DerefOf (Index (PBST, 0x02))))
                    {
                        Store (Local5, Index (PBST, 0x02))
                    }
                }

                Store (\_SB.PCI0.EC0.MBCV, Index (PBST, 0x03))
                Sleep (0xFA)
                Store (\_SB.PCI0.EC0.MBST, Local0)
                Release (\_SB.PCI0.EC0.MUT0)
                Store (Local0, Index (PBST, 0x00))
            }

            Method (IVBI, 0, NotSerialized)
            {
                Store (0xFFFFFFFF, Index (PBIF, 0x01))
                Store (0xFFFFFFFF, Index (PBIF, 0x02))
                Store (0xFFFFFFFF, Index (PBIF, 0x04))
                Store ("Bad", Index (PBIF, 0x09))
                Store ("      ", Index (PBIF, 0x0A))
                Store ("Bad", Index (PBIF, 0x0B))
                Store ("Bad", Index (PBIF, 0x0C))
            }

            Method (IVBS, 0, NotSerialized)
            {
                Store (0x00, Index (PBST, 0x00))
                Store (0xFFFFFFFF, Index (PBST, 0x01))
                Store (0xFFFFFFFF, Index (PBST, 0x02))
                Store (0x2710, Index (PBST, 0x03))
            }
        }

        Device (LID)
        {
            Name (_HID, EisaId ("PNP0C0D"))
            Method (_LID, 0, NotSerialized)
            {
                If (ECON)
                {
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    Store (\_SB.PCI0.EC0.LIDS, Local0)
                    Release (\_SB.PCI0.EC0.MUT0)
                    If (Local0)
                    {
                        Return (0x00)
                    }
                    Else
                    {
                        Return (0x01)
                    }
                }
                Else
                {
                    Return (0x01)
                }
            }
        }

        Device (MEM0)
        {
            Name (_HID, EisaId ("PNP0C01"))
            Method (_CRS, 0, Serialized)
            {
                Name (MEMR, ResourceTemplate ()
                {
                    Memory32Fixed (ReadOnly,
                        0xFFC00000,         // Address Base
                        0x00400000,         // Address Length
                        )
                    Memory32Fixed (ReadWrite,
                        0xFEC00000,         // Address Base
                        0x00001000,         // Address Length
                        )
                    Memory32Fixed (ReadWrite,
                        0xFEE00000,         // Address Base
                        0x00100000,         // Address Length
                        )
                    Memory32Fixed (ReadWrite,
                        0x00000000,         // Address Base
                        0x00000000,         // Address Length
                        _Y00)
                })
                CreateDWordField (MEMR, \_SB.MEM0._CRS._Y00._BAS, MBAS)
                CreateDWordField (MEMR, \_SB.MEM0._CRS._Y00._LEN, MBLE)
                If (\_SB.PCI0.LPC0.MTBA)
                {
                    Store (\_SB.PCI0.LPC0.MTBA, MBAS)
                    Store (0x1000, MBLE)
                }

                Return (MEMR)
            }
        }

        Device (QLBD)
        {
            Name (_HID, "HPQ0006")
            Method (_STA, 0, NotSerialized)
            {
                Return (0x0F)
            }
        }

        Device (WMID)
        {
            Name (Z004, Package (0x0E)
            {
                0x04, 
                0x04, 
                0x04, 
                0x00, 
                0x04, 
                0x04, 
                0x00, 
                0x00, 
                0x04, 
                0x04, 
                0x0C, 
                0x00, 
                0x00, 
                0x00
            })
            Method (Z005, 2, NotSerialized)
            {
                CreateDWordField (Arg1, 0x00, Z006)
                CreateDWordField (Arg1, 0x04, Z007)
                CreateDWordField (Arg1, 0x08, Z008)
                CreateDWordField (Arg1, 0x0C, Z009)
                If (LEqual (Arg0, 0x01))
                {
                    Store (0x00, Local0)
                }

                If (LEqual (Arg0, 0x02))
                {
                    Store (0x04, Local0)
                }

                If (LEqual (Arg0, 0x03))
                {
                    Store (0x80, Local0)
                }

                If (LEqual (Arg0, 0x04))
                {
                    Store (0x0400, Local0)
                }

                If (LEqual (Arg0, 0x05))
                {
                    Store (0x1000, Local0)
                }

                Store (Buffer (Add (0x08, Local0)) {}, Local1)
                CreateDWordField (Local1, 0x00, Z00A)
                CreateDWordField (Local1, 0x04, Z00B)
                Store (0x4C494146, Z00A)
                Store (0x02, Z00B)
                If (LEqual (Z006, 0x55434553))
                {
                    Store (0x03, Z00B)
                    If (LEqual (Z007, 0x01))
                    {
                        Store (0x04, Z00B)
                        If (LEqual (Z008, 0x05))
                        {
                            Store (^Z00C (), Local2)
                            Store (0x00, Z00B)
                        }

                        If (LEqual (Z008, 0x0E))
                        {
                            Store (^Z00D (), Local2)
                            Store (0x00, Z00B)
                        }

                        If (LEqual (Z008, 0x07))
                        {
                            If (Z009)
                            {
                                Store (DerefOf (Index (Arg1, 0x10)), Local3)
                                Store (^Z00E (Local3), Local2)
                                Store (0x00, Z00B)
                            }
                            Else
                            {
                                Store (0x05, Z00B)
                            }
                        }

                        If (LEqual (Z008, 0x01))
                        {
                            Store (^Z00F (), Local2)
                            Store (0x00, Z00B)
                        }

                        If (LEqual (Z008, 0x08))
                        {
                            Store (^Z00G (), Local2)
                            Store (0x00, Z00B)
                        }

                        If (LEqual (Z008, 0x09))
                        {
                            Store (^Z00H (), Local2)
                            Store (0x00, Z00B)
                        }

                        If (LEqual (Z008, 0x0A))
                        {
                            Store (^Z00I (), Local2)
                            Store (0x00, Z00B)
                        }

                        If (LEqual (Z008, 0x0C))
                        {
                            Store (^Z00J (), Local2)
                            Store (0x00, Z00B)
                        }
                    }

                    If (LEqual (Z007, 0x02))
                    {
                        Store (0x04, Z00B)
                        If (LAnd (LGreater (Z008, 0x00), LLessEqual (Z008, 0x0C)))
                        {
                            If (LLess (Z009, DerefOf (Index (Z004, Subtract (Z008, 0x01)
                                ))))
                            {
                                Store (0x05, Z00B)
                            }
                            Else
                            {
                                CreateDWordField (Arg1, 0x10, Z00K)
                                If (LEqual (Z008, 0x05))
                                {
                                    Store (^Z00L (Z00K), Local2)
                                    Store (0x00, Z00B)
                                }

                                If (LEqual (Z008, 0x01))
                                {
                                    Store (^Z00M (Z00K), Local2)
                                    Store (0x00, Z00B)
                                }

                                If (LEqual (Z008, 0x09))
                                {
                                    Store (^Z00N (Z00K), Local2)
                                    Store (0x00, Z00B)
                                }

                                If (LEqual (Z008, 0x0A))
                                {
                                    Store (^Z00O (Z00K), Local2)
                                    Store (0x00, Z00B)
                                }
                            }
                        }
                    }
                }

                If (LEqual (Z00B, 0x00))
                {
                    Store (DerefOf (Index (Local2, 0x00)), Z00B)
                    If (LEqual (Z00B, 0x00))
                    {
                        If (LLessEqual (DerefOf (Index (Local2, 0x01)), Local0))
                        {
                            Store (0x00, Local0)
                            While (LLess (Local0, DerefOf (Index (Local2, 0x01))))
                            {
                                Store (DerefOf (Index (DerefOf (Index (Local2, 0x02)), Local0)), 
                                    Index (Local1, Add (Local0, 0x08)))
                                Increment (Local0)
                            }

                            Store (0x53534150, Z00A)
                        }
                        Else
                        {
                            Store (0x05, Z00B)
                        }
                    }
                }

                Return (Local1)
            }

            Name (_HID, "PNP0C14")
            Name (_UID, 0x00)
            Name (Z00P, 0x00)
            Name (Z00Q, 0x00)
            Name (BUFF, Buffer (0x04)
            {
                0x00, 0x00, 0x00, 0x00
            })
            CreateByteField (BUFF, 0x00, OB0)
            CreateByteField (BUFF, 0x01, OB1)
            CreateByteField (BUFF, 0x02, OB2)
            CreateByteField (BUFF, 0x03, OB3)
            Name (_WDG, Buffer (0x50)
            {
                /* 0000 */    0x34, 0xF0, 0xB7, 0x5F, 0x63, 0x2C, 0xE9, 0x45, 
                /* 0008 */    0xBE, 0x91, 0x3D, 0x44, 0xE2, 0xC7, 0x07, 0xE4, 
                /* 0010 */    0x41, 0x44, 0x01, 0x02, 0x79, 0x42, 0xF2, 0x95, 
                /* 0018 */    0x7B, 0x4D, 0x34, 0x43, 0x93, 0x87, 0xAC, 0xCD, 
                /* 0020 */    0xC6, 0x7E, 0xF6, 0x1C, 0x80, 0x00, 0x01, 0x08, 
                /* 0028 */    0x21, 0x12, 0x90, 0x05, 0x66, 0xD5, 0xD1, 0x11, 
                /* 0030 */    0xB2, 0xF0, 0x00, 0xA0, 0xC9, 0x06, 0x29, 0x10, 
                /* 0038 */    0x41, 0x45, 0x01, 0x00, 0xD4, 0x2B, 0x99, 0xD0, 
                /* 0040 */    0x7C, 0xA4, 0xFE, 0x4E, 0xB0, 0x72, 0x32, 0x4A, 
                /* 0048 */    0xEC, 0x92, 0x29, 0x6C, 0x42, 0x43, 0x01, 0x00
            })
            Method (WQBC, 1, NotSerialized)
            {
                Store ("HP WMI WQBC)", Debug)
                Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                Store (0x88, \_SB.PCI0.SMIC)
                Store (\_SB.PCI0.SMIS, Local0)
                Release (\_SB.PCI0.PSMX)
                Store (Local0, CADL)
                If (ECON)
                {
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    If (LEqual (\_SB.PCI0.EC0.LIDS, 0x01))
                    {
                        And (Local0, 0xFE, Local0)
                    }

                    Release (\_SB.PCI0.EC0.MUT0)
                }

                Return (Local0)
            }

            Method (WSBC, 2, NotSerialized)
            {
                Store ("HP WMI WSBC)", Debug)
                CreateByteField (Arg1, 0x00, ADA0)
                Store (ADA0, Local0)
                If (LOr (LEqual (\_SB.PCI0.XVR0.VGA.SWIT, 0x00), LEqual (\_SB.PCI0.UVGA.SWIT, 0x00)))
                {
                    Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                    Store (0x87, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Local1)
                    Release (\_SB.PCI0.PSMX)
                    If (LEqual (Local0, Local1))
                    {
                        Return (0x02)
                    }
                    Else
                    {
                        Store (0x00, NSTE)
                        If (LEqual (Local0, 0x01))
                        {
                            Store ("LCD", Debug)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (Zero, \_SB.PCI0.UVGA.CRTA)
                            Store (One, \_SB.PCI0.UVGA.LCDA)
                            Store (Zero, \_SB.PCI0.UVGA.TVAF)
                            Store (Zero, \_SB.PCI0.UVGA.HDTV)
                        }

                        If (LEqual (Local0, 0x02))
                        {
                            Store ("CRT", Debug)
                            Store (One, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (One, \_SB.PCI0.UVGA.CRTA)
                            Store (Zero, \_SB.PCI0.UVGA.LCDA)
                            Store (Zero, \_SB.PCI0.UVGA.TVAF)
                            Store (Zero, \_SB.PCI0.UVGA.HDTV)
                        }

                        If (LEqual (Local0, 0x03))
                        {
                            Store ("Both", Debug)
                            Store (One, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (One, \_SB.PCI0.UVGA.CRTA)
                            Store (One, \_SB.PCI0.UVGA.LCDA)
                            Store (Zero, \_SB.PCI0.UVGA.TVAF)
                            Store (Zero, \_SB.PCI0.UVGA.HDTV)
                        }

                        If (LEqual (Local0, 0x04))
                        {
                            Store ("TV", Debug)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (One, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (Zero, \_SB.PCI0.UVGA.CRTA)
                            Store (Zero, \_SB.PCI0.UVGA.LCDA)
                            Store (One, \_SB.PCI0.UVGA.TVAF)
                            Store (Zero, \_SB.PCI0.UVGA.HDTV)
                        }

                        If (LEqual (Local0, 0x05))
                        {
                            Store ("TV+LCD", Debug)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (One, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (Zero, \_SB.PCI0.UVGA.CRTA)
                            Store (One, \_SB.PCI0.UVGA.LCDA)
                            Store (One, \_SB.PCI0.UVGA.TVAF)
                            Store (Zero, \_SB.PCI0.UVGA.HDTV)
                        }

                        If (LEqual (Local0, 0x06))
                        {
                            Store ("TV+CRT", Debug)
                        }

                        If (LEqual (Local0, 0x08))
                        {
                            Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (One, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (Zero, \_SB.PCI0.UVGA.CRTA)
                            Store (Zero, \_SB.PCI0.UVGA.LCDA)
                            Store (Zero, \_SB.PCI0.UVGA.TVAF)
                            Store (One, \_SB.PCI0.UVGA.HDTV)
                        }

                        If (LEqual (Local0, 0x09))
                        {
                            Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                            Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                            Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                            Store (One, \_SB.PCI0.XVR0.VGA.HDTV)
                            Store (Zero, \_SB.PCI0.UVGA.CRTA)
                            Store (One, \_SB.PCI0.UVGA.LCDA)
                            Store (Zero, \_SB.PCI0.UVGA.TVAF)
                            Store (One, \_SB.PCI0.UVGA.HDTV)
                        }

                        Store (CADL, PADL)
                        If (LGreaterEqual (OSYS, 0x07D1))
                        {
                            Notify (\_SB.PCI0, 0x00)
                        }
                        Else
                        {
                            If (VGAT)
                            {
                                Notify (\_SB.PCI0.XVR0.VGA, 0x00)
                            }
                            Else
                            {
                                Notify (\_SB.PCI0.UVGA, 0x00)
                            }
                        }

                        Sleep (0x02EE)
                        If (VGAT)
                        {
                            Notify (\_SB.PCI0.XVR0.VGA, 0x80)
                        }
                        Else
                        {
                            Notify (\_SB.PCI0.UVGA, 0x80)
                        }

                        Return (0x00)
                    }
                }
                Else
                {
                    Return (0x01)
                }
            }

            Method (WMAD, 3, NotSerialized)
            {
                Return (Z005 (Arg1, Arg2))
            }

            Method (Z00C, 0, NotSerialized)
            {
                Store ("HP WMI Command 0x5 (BIOS Read)", Debug)
                Store (0x01, WIRE)
                And (BTWL, 0x03, Local0)
                Or (Local0, 0x20, OB0)
                Store (WWLS, Local1)
                ShiftLeft (Local1, 0x01, Local1)
                Store (BWLS, Local2)
                ShiftLeft (Local2, 0x01, Local2)
                Store (BTLS, Local3)
                ShiftLeft (Local3, 0x03, Local3)
                Or (Local1, Local3, Local1)
                Or (Local2, Local3, Local2)
                And (GP24, 0x0F, GP25)
                If (LEqual (GP25, 0x05))
                {
                    Store (0x01, GP25)
                }
                Else
                {
                    Store (0x00, GP25)
                }

                And (GP23, 0x0F, GP26)
                If (LEqual (GP26, 0x05))
                {
                    Store (0x01, GP26)
                }
                Else
                {
                    Store (0x00, GP26)
                }

                If (GP26)
                {
                    If (LNot (WWLS))
                    {
                        Store (0x00, GP26)
                        Store (0x04, GP23)
                    }

                    If (LNot (BTLS))
                    {
                        Store (0x00, GP26)
                        Store (0x04, GP23)
                    }
                }

                If (GP25)
                {
                    If (LNot (BWLS))
                    {
                        Store (0x00, GP25)
                        Store (0x04, GP24)
                    }

                    If (LNot (BTLS))
                    {
                        Store (0x00, GP25)
                        Store (0x04, GP24)
                    }
                }

                Or (GP26, Local1, Local1)
                Or (GP25, Local2, Local2)
                Store (0x00, OB2)
                Store (0x00, OB1)
                If (WLSU)
                {
                    Or (Local1, 0x04, Local1)
                }

                If (BTSU)
                {
                    Or (Local2, 0x04, Local2)
                }

                If (GP26)
                {
                    Or (Local1, 0x10, Local1)
                }
                Else
                {
                    And (Local1, 0xEF, Local1)
                }

                If (And (BTWL, 0x01))
                {
                    Store (Local1, OB1)
                }

                If (And (BTWL, 0x02))
                {
                    Store (Local2, OB2)
                }

                Store (0x00, OB3)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x04, 
                        Buffer (0x04)
                        {
                            0x01, 0x02, 0x03, 0x04
                        }
                    }, Local0)
                Store (OB0, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                Store (OB1, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                Store (OB2, Index (DerefOf (Index (Local0, 0x02)), 0x02))
                Store (OB3, Index (DerefOf (Index (Local0, 0x02)), 0x03))
                Return (Local0)
            }

            Method (Z00L, 1, NotSerialized)
            {
                Store ("HP WMI Command 0x5 (BIOS Write)", Debug)
                And (GP24, 0x0F, GP25)
                If (LEqual (GP25, 0x05))
                {
                    Store (0x01, GP25)
                }
                Else
                {
                    Store (0x00, GP25)
                }

                And (GP23, 0x0F, GP26)
                If (LEqual (GP26, 0x05))
                {
                    Store (0x01, GP26)
                }
                Else
                {
                    Store (0x00, GP26)
                }

                If (And (BTWL, 0x03))
                {
                    If (And (Arg0, 0x0800))
                    {
                        If (And (Arg0, 0x08))
                        {
                            Store (0x01, WWLS)
                            Store (0x01, BWLS)
                            If (WLSU)
                            {
                                If (BTLS)
                                {
                                    Store (0x01, GP26)
                                    Store (0x05, GP23)
                                }
                            }
                            Else
                            {
                                Store (0x00, GP26)
                                Store (0x04, GP23)
                            }

                            If (BTSU)
                            {
                                If (BTLS)
                                {
                                    Store (0x01, GP25)
                                    Store (0x05, GP24)
                                }
                            }
                            Else
                            {
                                Store (0x00, GP25)
                                Store (0x04, GP24)
                            }
                        }
                        Else
                        {
                            Store (0x00, WWLS)
                            Store (0x00, GP26)
                            Store (0x04, GP23)
                            Store (0x00, BWLS)
                            Store (0x00, GP25)
                            Store (0x04, GP24)
                        }
                    }

                    If (And (Arg0, 0x0100))
                    {
                        If (And (Arg0, 0x01))
                        {
                            Store (0x01, WWLS)
                            If (WLSU)
                            {
                                If (BTLS)
                                {
                                    Store (0x01, GP26)
                                    Store (0x05, GP23)
                                }
                            }
                            Else
                            {
                                Store (0x00, GP26)
                                Store (0x04, GP23)
                            }
                        }
                        Else
                        {
                            Store (0x00, WWLS)
                            Store (0x00, GP26)
                            Store (0x04, GP23)
                        }
                    }

                    If (And (Arg0, 0x0200))
                    {
                        If (And (Arg0, 0x02))
                        {
                            Store (0x01, BWLS)
                            If (BTSU)
                            {
                                If (BTLS)
                                {
                                    Store (0x01, GP25)
                                    Store (0x05, GP24)
                                }
                            }
                            Else
                            {
                                Store (0x00, GP25)
                                Store (0x04, GP24)
                            }
                        }
                        Else
                        {
                            Store (0x00, BWLS)
                            Store (0x00, GP25)
                            Store (0x04, GP24)
                        }
                    }

                    Return (Package (0x02)
                    {
                        0x00, 
                        0x00
                    })
                }
                Else
                {
                    Return (Package (0x02)
                    {
                        0x0D, 
                        0x00
                    })
                }
            }

            Method (Z00D, 0, NotSerialized)
            {
                Store ("HP WMI Command 0xE (BIOS Read)", Debug)
                Store (0x00, Local0)
                Store (Buffer (0x0A)
                    {
                        /* 0000 */    0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                        /* 0008 */    0x00, 0x00
                    }, Local2)
                Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                Store (0x00, \_SB.PCI0.SMIS)
                Store (0x89, \_SB.PCI0.SMIC)
                Store (\_SB.PCI0.SMIS, WLID)
                Release (\_SB.PCI0.PSMX)
                If (LNotEqual (WLID, 0xFF))
                {
                    Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                    Store (0x02, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x02))
                    Store (0x03, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x03))
                    Store (0x04, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x04))
                    Store (0x05, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x05))
                    Store (0x06, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x06))
                    Store (0x07, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x07))
                    Store (0x08, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x08))
                    Store (0x09, \_SB.PCI0.SMIS)
                    Store (0x89, \_SB.PCI0.SMIC)
                    Store (\_SB.PCI0.SMIS, Index (Local2, 0x09))
                    Release (\_SB.PCI0.PSMX)
                    Store (Local2, Local1)
                    Add (Local0, 0x0A, Local0)
                }

                Store (Package (0x03) {}, Local2)
                Store (0x00, Index (Local2, 0x00))
                Store (Local0, Index (Local2, 0x01))
                Store (Local1, Index (Local2, 0x02))
                Return (Local2)
            }

            Method (Z00E, 1, NotSerialized)
            {
                Store ("HP WMI Command 0x7 (BIOS Read)", Debug)
                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                If (LNot (ECON))
                {
                    Store (Package (0x02)
                        {
                            0x0D, 
                            0x00
                        }, Local0)
                    Sleep (0x96)
                    Release (\_SB.PCI0.EC0.MUT0)
                    Return (Local0)
                }

                If (Arg0)
                {
                    Store (Package (0x02)
                        {
                            0x06, 
                            0x00
                        }, Local0)
                    Sleep (0x96)
                    Release (\_SB.PCI0.EC0.MUT0)
                    Return (Local0)
                }

                If (LNot (\_SB.PCI0.EC0.MBTS))
                {
                    Store (Package (0x02)
                        {
                            0x06, 
                            0x00
                        }, Local0)
                    Sleep (0x96)
                    Release (\_SB.PCI0.EC0.MUT0)
                    Return (Local0)
                }

                Release (\_SB.PCI0.EC0.MUT0)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x80, 
                        Buffer (0x80) {}
                    }, Local0)
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x18, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x01))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x10, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x03))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x02))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x0F, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x05))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x04))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x0C, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x07))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x06))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x17, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x09))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x08))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x08, RefOf (Local1))
                Subtract (Local1, 0x0AAA, Local1)
                Divide (Local1, 0x0A, Local2, Local1)
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x0B))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x0A))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x09, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x0D))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x0C))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x0A, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x0F))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x0E))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x19, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x11))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x10))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x16, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x13))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x12))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x3F, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x15))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x14))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x3E, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x17))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x16))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x3D, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x19))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x18))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x3C, RefOf (Local1))
                Divide (Local1, 0x0100, Local2, Index (DerefOf (Index (Local0, 0x02)), 
                    0x1B))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x1A))
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x1C, RefOf (Local1))
                Store (ITOS (ToBCD (Local1)), Local3)
                Store (0x1C, Local2)
                Store (0x00, Local4)
                Store (SizeOf (Local3), Local1)
                While (Local1)
                {
                    GBFE (Local3, Local4, RefOf (Local5))
                    PBFE (DerefOf (Index (Local0, 0x02)), Local2, Local5)
                    Decrement (Local1)
                    Increment (Local2)
                    Increment (Local4)
                }

                Store (0x20, Index (DerefOf (Index (Local0, 0x02)), Local2))
                Increment (Local2)
                \_SB.PCI0.EC0.SMRD (0x09, 0x16, 0x1B, RefOf (Local1))
                And (Local1, 0x1F, Local7)
                Store (ITOS (ToBCD (Local7)), Local6)
                And (Local1, 0x01E0, Local7)
                ShiftRight (Local7, 0x05, Local7)
                Store (ITOS (ToBCD (Local7)), Local5)
                ShiftRight (Local1, 0x09, Local7)
                Add (Local7, 0x07BC, Local7)
                Store (ITOS (ToBCD (Local7)), Local4)
                Store (0x02, Local1)
                Store (0x03, Local7)
                While (Local1)
                {
                    GBFE (Local5, Local7, RefOf (Local3))
                    PBFE (DerefOf (Index (Local0, 0x02)), Local2, Local3)
                    Decrement (Local1)
                    Increment (Local2)
                    Increment (Local7)
                }

                Store ("/", Index (DerefOf (Index (Local0, 0x02)), Local2))
                Increment (Local2)
                Store (0x02, Local1)
                Store (0x03, Local7)
                While (Local1)
                {
                    GBFE (Local6, Local7, RefOf (Local3))
                    PBFE (DerefOf (Index (Local0, 0x02)), Local2, Local3)
                    Decrement (Local1)
                    Increment (Local2)
                    Increment (Local7)
                }

                Store ("/", Index (DerefOf (Index (Local0, 0x02)), Local2))
                Increment (Local2)
                Store (0x04, Local1)
                Store (0x01, Local7)
                While (Local1)
                {
                    GBFE (Local4, Local7, RefOf (Local3))
                    PBFE (DerefOf (Index (Local0, 0x02)), Local2, Local3)
                    Decrement (Local1)
                    Increment (Local2)
                    Increment (Local7)
                }

                Store (0x00, Index (DerefOf (Index (Local0, 0x02)), Local2))
                \_SB.PCI0.EC0.SMRD (0x0B, 0x16, 0x20, RefOf (Local1))
                Store (SizeOf (Local1), Local3)
                Store (0x2C, Local2)
                Store (0x00, Local4)
                While (Local3)
                {
                    GBFE (Local1, Local4, RefOf (Local5))
                    PBFE (DerefOf (Index (Local0, 0x02)), Local2, Local5)
                    Decrement (Local3)
                    Increment (Local2)
                    Increment (Local4)
                }

                Store (0x00, Index (DerefOf (Index (Local0, 0x02)), Local2))
                Sleep (0x96)
                Return (Local0)
            }

            Method (Z00F, 0, NotSerialized)
            {
                Store ("HP WMI Command 0x1 (BIOS Read)", Debug)
                Store (WQBC (0x00), OB0)
                Or (OB0, 0x01, OB0)
                Store (0x00, OB1)
                Store (0x00, OB2)
                Store (0x00, OB3)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x04, 
                        Buffer (0x04)
                        {
                            0x01, 0x02, 0x03, 0x04
                        }
                    }, Local0)
                Store (OB0, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                Store (OB1, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                Store (OB2, Index (DerefOf (Index (Local0, 0x02)), 0x02))
                Store (OB3, Index (DerefOf (Index (Local0, 0x02)), 0x03))
                Return (Local0)
            }

            Method (Z00M, 1, NotSerialized)
            {
                Store ("HP WMI Command 0x1 (BIOS Write)", Debug)
                And (Arg0, 0x0F, Local0)
                If (VGAT)
                {
                    If (LEqual (\_SB.PCI0.XVR0.VGA.SWIT, 0x00))
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x87, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local1)
                        Release (\_SB.PCI0.PSMX)
                        If (LEqual (Local0, Local1))
                        {
                            Return (Package (0x02)
                            {
                                0x00, 
                                0x00
                            })
                        }
                        Else
                        {
                            Store (0x00, NSTE)
                            If (LEqual (Local0, 0x01))
                            {
                                Store ("LCD", Debug)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x02))
                            {
                                Store ("CRT", Debug)
                                Store (One, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x03))
                            {
                                Store ("Both", Debug)
                                Store (One, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x04))
                            {
                                Store ("TV", Debug)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (One, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x05))
                            {
                                Store ("TV+LCD", Debug)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (One, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x06))
                            {
                                Store ("TV+CRT", Debug)
                                Return (Package (0x02)
                                {
                                    0x06, 
                                    0x00
                                })
                            }

                            If (LEqual (Local0, 0x07))
                            {
                                Store ("TV+CRT+LCD", Debug)
                                Return (Package (0x02)
                                {
                                    0x06, 
                                    0x00
                                })
                            }

                            If (LEqual (Local0, 0x08))
                            {
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (One, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x09))
                            {
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (One, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LGreaterEqual (Local0, 0x0A))
                            {
                                Return (Package (0x02)
                                {
                                    0x06, 
                                    0x00
                                })
                            }

                            Store (CADL, PADL)
                            Notify (\_SB.PCI0.XVR0.VGA, 0x80)
                            Return (Package (0x02)
                            {
                                0x00, 
                                0x00
                            })
                        }
                    }
                    Else
                    {
                        Return (Package (0x02)
                        {
                            0x00, 
                            0x00
                        })
                    }
                }
                Else
                {
                    If (LEqual (\_SB.PCI0.UVGA.SWIT, 0x00))
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x87, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local1)
                        Release (\_SB.PCI0.PSMX)
                        If (LEqual (Local0, Local1))
                        {
                            Return (Package (0x02)
                            {
                                0x00, 
                                0x00
                            })
                        }
                        Else
                        {
                            Store (0x00, NSTE)
                            If (LEqual (Local0, 0x01))
                            {
                                Store ("LCD", Debug)
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x02))
                            {
                                Store ("CRT", Debug)
                                Store (One, \_SB.PCI0.UVGA.CRTA)
                                Store (Zero, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x03))
                            {
                                Store ("Both", Debug)
                                Store (One, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x04))
                            {
                                Store ("TV", Debug)
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (Zero, \_SB.PCI0.UVGA.LCDA)
                                Store (One, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x05))
                            {
                                Store ("TV+LCD", Debug)
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (One, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x06))
                            {
                                Store ("TV+CRT", Debug)
                                Return (Package (0x02)
                                {
                                    0x06, 
                                    0x00
                                })
                            }

                            If (LEqual (Local0, 0x07))
                            {
                                Store ("TV+CRT+LCD", Debug)
                                Return (Package (0x02)
                                {
                                    0x06, 
                                    0x00
                                })
                            }

                            If (LEqual (Local0, 0x08))
                            {
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (Zero, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (One, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x09))
                            {
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (One, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LGreaterEqual (Local0, 0x0A))
                            {
                                Return (Package (0x02)
                                {
                                    0x06, 
                                    0x00
                                })
                            }

                            Store (CADL, PADL)
                            Notify (\_SB.PCI0.UVGA, 0x80)
                            Return (Package (0x02)
                            {
                                0x00, 
                                0x00
                            })
                        }
                    }
                    Else
                    {
                        Return (Package (0x02)
                        {
                            0x00, 
                            0x00
                        })
                    }
                }
            }

            Method (Z00G, 0, NotSerialized)
            {
                Store ("HP WMI Command 0x8 (BIOS Read)", Debug)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x80, 
                        Buffer (0x80)
                        {
                            /* 0000 */    0x31, 0x01, 0x9B, 0x01, 0xFF, 0x01, 0x63, 0x02, 
                            /* 0008 */    0xAE, 0x01, 0x64, 0x02, 0x9D, 0x01, 0xB6, 0x01, 
                            /* 0010 */    0xB7, 0x01, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, 
                            /* 0018 */    0x68, 0x02, 0xFF, 0xFF, 0xE4, 0x20, 0xE6, 0x20, 
                            /* 0020 */    0x42, 0x21, 0x70, 0x21, 0x00, 0x00
                        }
                    }, Local0)
                Return (Local0)
            }

            Method (Z00H, 0, NotSerialized)
            {
                Store ("HP WMI Command 0x9 (BIOS Read)", Debug)
                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x04, 
                        Buffer (0x04) {}
                    }, Local0)
                Store (\_SB.PCI0.EC0.Z00R (), Index (DerefOf (Index (Local0, 0x02)), 0x00))
                Release (\_SB.PCI0.EC0.MUT0)
                Return (Local0)
            }

            Method (Z00N, 1, NotSerialized)
            {
                Store ("HP WMI Command 0x9 (BIOS Write)", Debug)
                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                \_SB.PCI0.EC0.Z00S (Arg0)
                Release (\_SB.PCI0.EC0.MUT0)
                Return (Package (0x02)
                {
                    0x00, 
                    0x00
                })
            }

            Method (Z00T, 0, NotSerialized)
            {
                Store (Package (0x03)
                    {
                        0x00, 
                        0x04, 
                        Buffer (0x04) {}
                    }, Local0)
                If (ECON)
                {
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    Store (\_SB.PCI0.EC0.QBHK, Local1)
                    Store (0x00, \_SB.PCI0.EC0.QBHK)
                    Release (\_SB.PCI0.EC0.MUT0)
                }

                If (LEqual (Local1, 0x0D))
                {
                    Store ("Fn+ESC Pressed", Debug)
                    Store (0x31, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x01, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x01))
                {
                    Store ("Fn+F1 Pressed", Debug)
                    Store (0x9B, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x01, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x04))
                {
                    \_SB.PCI0.EC0._Q0D ()
                    Store (0x00, Local3)
                    Store (0x00, Local4)
                    Store (0x00, Local5)
                    Store (0xAE, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x01, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                    ShiftLeft (And (NSTE, 0x01), 0x01, Local3)
                    ShiftLeft (And (NSTE, 0x02), 0x01, Local4)
                    ShiftRight (And (NSTE, 0x08), 0x03, Local5)
                    Or (Local3, Local4, Local3)
                    Or (Local3, Local5, Local3)
                    Store (CSTE, Local3)
                    Store (Local3, Index (DerefOf (Index (Local0, 0x02)), 0x02))
                    ShiftLeft (And (CADL, 0x01), 0x01, Local3)
                    ShiftLeft (And (CADL, 0x02), 0x01, Local4)
                    ShiftRight (And (CADL, 0x08), 0x03, Local5)
                    Or (Local3, Local4, Local3)
                    Or (Local3, Local5, Local3)
                    Store (PSTE, Local3)
                    Store (Local3, Index (DerefOf (Index (Local0, 0x02)), 0x03))
                }

                If (LEqual (Local1, 0x06))
                {
                    Store ("Fn+F6 Pressed", Debug)
                    Store (0x9D, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x01, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x07))
                {
                    If (LEqual (OSYS, 0x07D6))
                    {
                        If (LEqual (VGAT, 0x01))
                        {
                            Notify (\_SB.PCI0.XVR0.VGA.LCD, 0x87)
                        }
                        Else
                        {
                            Notify (\_SB.PCI0.UVGA.LCD, 0x87)
                        }
                    }
                    Else
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x8D, \_SB.PCI0.SMIC)
                        Release (\_SB.PCI0.PSMX)
                    }

                    Sleep (0x32)
                    Store (0xB6, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x01, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x08))
                {
                    If (LEqual (OSYS, 0x07D6))
                    {
                        If (LEqual (VGAT, 0x01))
                        {
                            Notify (\_SB.PCI0.XVR0.VGA.LCD, 0x86)
                        }
                        Else
                        {
                            Notify (\_SB.PCI0.UVGA.LCD, 0x86)
                        }
                    }
                    Else
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x8C, \_SB.PCI0.SMIC)
                        Release (\_SB.PCI0.PSMX)
                    }

                    Sleep (0x32)
                    Store (0xB7, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x01, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                Return (Local0)
            }

            Method (Z00I, 0, NotSerialized)
            {
                Store ("HP WMI Command 0xA (BIOS Read)", Debug)
                Return (Z00T ())
            }

            Method (Z00O, 1, NotSerialized)
            {
                Store ("HP WMI Command 0xA (BIOS Write)", Debug)
                And (Arg0, 0xFF, Local1)
                And (Arg0, 0xFF00, Local3)
                ShiftRight (Local3, 0x08, Local2)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x04, 
                        Buffer (0x04) {}
                    }, Local0)
                Store (Local1, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                Store (Local2, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                If (LEqual (Arg0, 0x01AE))
                {
                    \_SB.PCI0.EC0._Q0D ()
                    Store (CSTE, Index (DerefOf (Index (Local0, 0x02)), 0x02))
                    Store (PSTE, Index (DerefOf (Index (Local0, 0x02)), 0x03))
                }

                Return (Local0)
            }

            Method (Z00J, 0, NotSerialized)
            {
                Store ("HP WMI Command 0xC (BIOS Read)", Debug)
                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                Store (Package (0x03)
                    {
                        0x00, 
                        0x04, 
                        Buffer (0x04) {}
                    }, Local0)
                If (ECON)
                {
                    Store (\_SB.PCI0.EC0.QBBB, Local1)
                    Store (0x00, \_SB.PCI0.EC0.QBBB)
                }

                If (LEqual (Local1, 0x03))
                {
                    Store (0xE4, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x20, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x04))
                {
                    Store (0x42, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x21, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x05))
                {
                    Store (0xE6, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x20, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                If (LEqual (Local1, 0x10))
                {
                    Store (0x70, Index (DerefOf (Index (Local0, 0x02)), 0x00))
                    Store (0x21, Index (DerefOf (Index (Local0, 0x02)), 0x01))
                }

                Release (\_SB.PCI0.EC0.MUT0)
                Return (Local0)
            }

            Method (_WED, 1, NotSerialized)
            {
                Concatenate (Z00P, Z00Q, Local0)
                Return (Local0)
            }

            Name (WQAE, Buffer (0x08A9)
            {
                /* 0000 */    0x46, 0x4F, 0x4D, 0x42, 0x01, 0x00, 0x00, 0x00, 
                /* 0008 */    0x99, 0x08, 0x00, 0x00, 0x8A, 0x3A, 0x00, 0x00, 
                /* 0010 */    0x44, 0x53, 0x00, 0x01, 0x1A, 0x7D, 0xDA, 0x54, 
                /* 0018 */    0x98, 0x4B, 0x9C, 0x00, 0x01, 0x06, 0x18, 0x42, 
                /* 0020 */    0x10, 0x13, 0x10, 0x22, 0x21, 0x04, 0x12, 0x01, 
                /* 0028 */    0xA1, 0xC8, 0x2C, 0x0C, 0x86, 0x10, 0x38, 0x2E, 
                /* 0030 */    0x84, 0x1C, 0x40, 0x88, 0x59, 0x50, 0x08, 0x21, 
                /* 0038 */    0x10, 0xEA, 0x4F, 0x20, 0xBF, 0x02, 0x10, 0x3A, 
                /* 0040 */    0x14, 0x20, 0x53, 0x80, 0x41, 0x01, 0x4E, 0x11, 
                /* 0048 */    0x44, 0xD0, 0xAB, 0x00, 0x9B, 0x02, 0x4C, 0x0A, 
                /* 0050 */    0xB0, 0x28, 0x40, 0xBB, 0x00, 0xCB, 0x02, 0x74, 
                /* 0058 */    0x0B, 0x90, 0x0E, 0x4B, 0x44, 0x82, 0xA3, 0xC4, 
                /* 0060 */    0x80, 0xA3, 0x74, 0x62, 0x0B, 0x37, 0x6C, 0xF0, 
                /* 0068 */    0x42, 0x51, 0x34, 0x83, 0x28, 0x09, 0x2A, 0x17, 
                /* 0070 */    0xE0, 0x1B, 0x41, 0xE0, 0xE5, 0x0A, 0x90, 0x3C, 
                /* 0078 */    0x01, 0x69, 0x16, 0x60, 0x58, 0x80, 0x75, 0x01, 
                /* 0080 */    0xB2, 0x87, 0x40, 0xA5, 0x0E, 0x01, 0x25, 0x67, 
                /* 0088 */    0x08, 0xA8, 0x01, 0xB4, 0x3A, 0x01, 0xE1, 0x57, 
                /* 0090 */    0x3A, 0x25, 0x24, 0x41, 0x38, 0x63, 0x15, 0x8F, 
                /* 0098 */    0xAF, 0x59, 0x34, 0x3D, 0x27, 0x39, 0xC7, 0x90, 
                /* 00A0 */    0xE3, 0x71, 0xA1, 0x07, 0xC1, 0x05, 0x78, 0x18, 
                /* 00A8 */    0x06, 0x1D, 0xB2, 0x22, 0x6B, 0x80, 0xC1, 0x58, 
                /* 00B0 */    0x18, 0x0B, 0x75, 0x31, 0x6A, 0xD4, 0x48, 0xD9, 
                /* 00B8 */    0x80, 0x0C, 0x51, 0x12, 0x1C, 0x6A, 0xD4, 0x96, 
                /* 00C0 */    0x28, 0xC0, 0xFC, 0x38, 0x34, 0xBB, 0xB6, 0xC7, 
                /* 00C8 */    0x42, 0x20, 0x99, 0xB4, 0xA1, 0xA0, 0xA4, 0x40, 
                /* 00D0 */    0x68, 0x6C, 0x67, 0xEA, 0x19, 0x45, 0x3C, 0x52, 
                /* 00D8 */    0xC3, 0x24, 0xF0, 0x28, 0x22, 0x1B, 0x8D, 0x43, 
                /* 00E0 */    0x63, 0x87, 0xE1, 0x61, 0x06, 0x3B, 0x88, 0xC3, 
                /* 00E8 */    0x38, 0xE6, 0xC8, 0x09, 0x3C, 0xA1, 0x23, 0x3D, 
                /* 00F0 */    0xF2, 0xC2, 0xE6, 0x29, 0xD4, 0x18, 0xCD, 0x41, 
                /* 00F8 */    0x11, 0xB8, 0xD0, 0x18, 0x19, 0x10, 0xF2, 0x3C, 
                /* 0100 */    0x7E, 0x8D, 0xC4, 0x04, 0x76, 0x2F, 0xC0, 0x1A, 
                /* 0108 */    0xA6, 0x60, 0x1B, 0x9B, 0x98, 0xFE, 0xFF, 0x10, 
                /* 0110 */    0x47, 0x1E, 0xA3, 0xAD, 0xB9, 0x0B, 0x29, 0x4C, 
                /* 0118 */    0x8C, 0x28, 0xC1, 0xE2, 0x55, 0x3C, 0x0D, 0xA1, 
                /* 0120 */    0x3C, 0x29, 0x84, 0x8A, 0x54, 0x19, 0x8A, 0x86, 
                /* 0128 */    0x1E, 0xA5, 0x42, 0x01, 0xCE, 0xE6, 0x21, 0xDC, 
                /* 0130 */    0x1A, 0x41, 0x85, 0x10, 0x2B, 0x52, 0xAC, 0xF6, 
                /* 0138 */    0x07, 0x41, 0x42, 0x2E, 0x5B, 0xC7, 0x07, 0x47, 
                /* 0140 */    0x1A, 0x0D, 0xEA, 0x50, 0xE0, 0xB1, 0x7B, 0xDC, 
                /* 0148 */    0xCF, 0x02, 0x3E, 0x08, 0x9C, 0x5B, 0x90, 0xA3, 
                /* 0150 */    0x3B, 0x8B, 0x47, 0x85, 0x83, 0xF6, 0xF0, 0xD8, 
                /* 0158 */    0x6D, 0xC0, 0x67, 0x08, 0x9F, 0x02, 0xF0, 0xAE, 
                /* 0160 */    0x01, 0x35, 0xFD, 0x83, 0x67, 0x82, 0xE0, 0x50, 
                /* 0168 */    0x43, 0xF4, 0xA8, 0xC3, 0x9D, 0xC0, 0x21, 0x32, 
                /* 0170 */    0x40, 0x4F, 0xEA, 0xB8, 0xB1, 0x83, 0x3B, 0x99, 
                /* 0178 */    0x83, 0x7E, 0x6F, 0x68, 0xF6, 0xC6, 0x40, 0x08, 
                /* 0180 */    0x8E, 0xC7, 0x97, 0x05, 0x36, 0xE1, 0x04, 0x96, 
                /* 0188 */    0x3F, 0x08, 0xD4, 0xC8, 0x0C, 0xED, 0x51, 0x9E, 
                /* 0190 */    0x56, 0xCC, 0x90, 0xCF, 0x0C, 0x26, 0xB0, 0x58, 
                /* 0198 */    0x08, 0x29, 0x80, 0xD0, 0x78, 0xC0, 0x7F, 0x03, 
                /* 01A0 */    0x78, 0xC0, 0xF0, 0xCD, 0xC0, 0xF3, 0x35, 0xC1, 
                /* 01A8 */    0xB0, 0x10, 0x32, 0xB2, 0x0A, 0x8F, 0x87, 0x8E, 
                /* 01B0 */    0xC2, 0xD7, 0x83, 0xC3, 0x39, 0xAD, 0x78, 0x26, 
                /* 01B8 */    0x18, 0x0E, 0x42, 0x27, 0x09, 0x8B, 0x1A, 0x36, 
                /* 01C0 */    0x3D, 0x39, 0xF0, 0x43, 0x03, 0xBB, 0x19, 0x9C, 
                /* 01C8 */    0xC1, 0x23, 0x80, 0x47, 0x72, 0x42, 0xFE, 0x98, 
                /* 01D0 */    0x78, 0x60, 0xF0, 0x01, 0xF1, 0xDE, 0xA7, 0x4C, 
                /* 01D8 */    0x46, 0x70, 0xA6, 0x06, 0xF4, 0x71, 0xC0, 0xFF, 
                /* 01E0 */    0xFF, 0xA1, 0xF0, 0x21, 0x7A, 0x7C, 0xA7, 0x7C, 
                /* 01E8 */    0xBC, 0x96, 0x00, 0x21, 0x59, 0xE3, 0x84, 0x7E, 
                /* 01F0 */    0x87, 0xF0, 0xF1, 0xC3, 0x47, 0x16, 0x47, 0x84, 
                /* 01F8 */    0x90, 0x93, 0x53, 0x00, 0x1A, 0xF8, 0x74, 0xCF, 
                /* 0200 */    0x2E, 0xC2, 0xE9, 0x7A, 0x52, 0x0E, 0x34, 0x0C, 
                /* 0208 */    0x3A, 0x4E, 0x70, 0x9C, 0x07, 0xC0, 0x31, 0x4E, 
                /* 0210 */    0xF8, 0xE7, 0x02, 0xF8, 0x03, 0xE4, 0xA7, 0x8C, 
                /* 0218 */    0x57, 0x8C, 0x04, 0x8E, 0x39, 0x42, 0xF4, 0xB9, 
                /* 0220 */    0xC6, 0x23, 0xC4, 0xC2, 0x3F, 0x55, 0x14, 0x3E, 
                /* 0228 */    0x10, 0x32, 0x46, 0x70, 0x01, 0x7A, 0x8C, 0xC0, 
                /* 0230 */    0x37, 0xE0, 0x18, 0xD1, 0x47, 0x09, 0xAE, 0xFE, 
                /* 0238 */    0xA0, 0x41, 0x07, 0x88, 0xFB, 0xFF, 0x0F, 0x10, 
                /* 0240 */    0x3E, 0xA8, 0x07, 0x08, 0x7C, 0xA3, 0x1F, 0x3D, 
                /* 0248 */    0xD0, 0xE3, 0xB2, 0xE8, 0xF3, 0x80, 0x8C, 0x9F, 
                /* 0250 */    0x68, 0x34, 0x2F, 0x7E, 0x3A, 0xE0, 0x87, 0x0F, 
                /* 0258 */    0xF0, 0x80, 0x7A, 0x48, 0x38, 0x50, 0xCC, 0xB4, 
                /* 0260 */    0x39, 0xE8, 0xB3, 0xCB, 0xA1, 0x63, 0x87, 0x0B, 
                /* 0268 */    0xFE, 0x13, 0x08, 0xB8, 0xE4, 0x1D, 0xC2, 0x40, 
                /* 0270 */    0x31, 0x62, 0xFC, 0x39, 0xC8, 0xA7, 0x30, 0xF0, 
                /* 0278 */    0xFF, 0xFF, 0x4F, 0x61, 0xB8, 0x11, 0xF0, 0x20, 
                /* 0280 */    0xAF, 0x05, 0x9F, 0xB6, 0xA8, 0x74, 0x18, 0xD4, 
                /* 0288 */    0x81, 0x0B, 0x30, 0x09, 0x1A, 0xE1, 0x59, 0xA2, 
                /* 0290 */    0x36, 0x08, 0x01, 0xBF, 0x4D, 0xBC, 0x6D, 0xF9, 
                /* 0298 */    0x16, 0x10, 0xE7, 0xC8, 0x7B, 0x3B, 0x70, 0x11, 
                /* 02A0 */    0x8C, 0x08, 0xA7, 0x1D, 0xCA, 0x63, 0x88, 0x18, 
                /* 02A8 */    0x23, 0xCA, 0xE3, 0x96, 0x51, 0xDE, 0xB6, 0x5E, 
                /* 02B0 */    0x00, 0xE2, 0x9D, 0xE5, 0xF3, 0x96, 0x31, 0x82, 
                /* 02B8 */    0x47, 0x7E, 0xE0, 0x62, 0x62, 0xDF, 0x13, 0xFA, 
                /* 02C0 */    0xB9, 0xF9, 0xC0, 0x05, 0x38, 0xFB, 0xFF, 0x1F, 
                /* 02C8 */    0xB8, 0x00, 0x0E, 0x05, 0x3D, 0x0C, 0xA1, 0x87, 
                /* 02D0 */    0xE1, 0xA9, 0x9C, 0xCB, 0x13, 0xE5, 0xA9, 0x44, 
                /* 02D8 */    0x8C, 0x1A, 0x26, 0xEA, 0x33, 0x94, 0x2F, 0x1A, 
                /* 02E0 */    0x3E, 0x10, 0x81, 0xEF, 0xCC, 0x05, 0xFC, 0xFE, 
                /* 02E8 */    0xFF, 0x07, 0x22, 0x38, 0x02, 0xCF, 0x34, 0xA0, 
                /* 02F0 */    0xF4, 0x39, 0x03, 0x81, 0x9C, 0x8A, 0x0F, 0x35, 
                /* 02F8 */    0xC0, 0x48, 0xF4, 0xAB, 0xC1, 0x27, 0x1A, 0x2A, 
                /* 0300 */    0x13, 0x06, 0x75, 0xA8, 0x01, 0x4C, 0x5E, 0x61, 
                /* 0308 */    0x9E, 0x46, 0xCF, 0xF9, 0x59, 0xC6, 0xA7, 0x1A, 
                /* 0310 */    0x1F, 0x4A, 0x8D, 0x63, 0x88, 0x97, 0x99, 0x87, 
                /* 0318 */    0x1A, 0x1F, 0x0B, 0x5E, 0x49, 0x7D, 0xA8, 0x31, 
                /* 0320 */    0x54, 0x9C, 0x87, 0x1A, 0x9F, 0x48, 0x03, 0x45, 
                /* 0328 */    0x7D, 0xB3, 0x79, 0xB6, 0x31, 0x7A, 0x7C, 0xDF, 
                /* 0330 */    0x50, 0x0D, 0xF1, 0x50, 0xC3, 0x84, 0xBD, 0x23, 
                /* 0338 */    0xF4, 0xC1, 0xF5, 0xA1, 0x06, 0x1C, 0xFF, 0xFF, 
                /* 0340 */    0x43, 0x0D, 0xC0, 0xFF, 0xFF, 0xFF, 0xA1, 0x06, 
                /* 0348 */    0x70, 0x74, 0x34, 0x80, 0x73, 0x64, 0xC4, 0x1D, 
                /* 0350 */    0x0D, 0xC0, 0x75, 0x28, 0x05, 0x0E, 0x47, 0x03, 
                /* 0358 */    0xE0, 0x71, 0x14, 0x02, 0xF3, 0x85, 0xC6, 0x47, 
                /* 0360 */    0x21, 0x60, 0xF1, 0xFF, 0x3F, 0x0A, 0xE1, 0x64, 
                /* 0368 */    0x9F, 0x83, 0x50, 0x42, 0x8F, 0x42, 0x80, 0x54, 
                /* 0370 */    0xC8, 0xA7, 0x88, 0x67, 0x1F, 0x5F, 0x7E, 0x1E, 
                /* 0378 */    0x08, 0x22, 0xBC, 0xE6, 0xFB, 0x14, 0xE4, 0x43, 
                /* 0380 */    0xBE, 0x8F, 0x42, 0x0C, 0xC6, 0x50, 0xBE, 0x06, 
                /* 0388 */    0xF9, 0x28, 0xC4, 0xA0, 0x5E, 0x83, 0x7C, 0xDF, 
                /* 0390 */    0x37, 0xC8, 0x91, 0x18, 0xFB, 0x99, 0xC0, 0x47, 
                /* 0398 */    0x21, 0x26, 0xED, 0x28, 0x04, 0x28, 0xFC, 0xFF, 
                /* 03A0 */    0x1F, 0x85, 0x00, 0xFE, 0xFF, 0xFF, 0x8F, 0x42, 
                /* 03A8 */    0x80, 0xB3, 0x00, 0x47, 0x03, 0xD0, 0x4D, 0xEB, 
                /* 03B0 */    0x51, 0x08, 0xBC, 0x77, 0x96, 0xD3, 0x3E, 0x01, 
                /* 03B8 */    0x9F, 0x85, 0x00, 0xB3, 0xFF, 0xFF, 0xB3, 0x10, 
                /* 03C0 */    0x30, 0x3B, 0x0A, 0x45, 0x3D, 0xE8, 0x57, 0xA1, 
                /* 03C8 */    0x27, 0x80, 0x17, 0x80, 0x18, 0x61, 0xDE, 0x81, 
                /* 03D0 */    0x5E, 0x32, 0xD9, 0x5D, 0xDC, 0x38, 0x4F, 0x2E, 
                /* 03D8 */    0xA7, 0x6D, 0x94, 0x97, 0x20, 0x1F, 0x28, 0x9E, 
                /* 03E0 */    0x85, 0x0C, 0xF5, 0x2E, 0x14, 0xF4, 0x8D, 0xDC, 
                /* 03E8 */    0xA3, 0x8C, 0x19, 0x3F, 0xC4, 0xF3, 0x90, 0x21, 
                /* 03F0 */    0x9E, 0x85, 0x00, 0x76, 0xFD, 0xFF, 0xCF, 0x42, 
                /* 03F8 */    0x00, 0xFF, 0xFF, 0xFF, 0x47, 0x03, 0xF8, 0x2F, 
                /* 0400 */    0x00, 0x9F, 0x85, 0x80, 0xE7, 0x09, 0xE0, 0x41, 
                /* 0408 */    0xDB, 0x67, 0x21, 0x80, 0x33, 0x87, 0xCB, 0xF3, 
                /* 0410 */    0x0F, 0x7A, 0x60, 0xEF, 0x11, 0x9E, 0xF5, 0x71, 
                /* 0418 */    0xBF, 0x5E, 0x7A, 0xE0, 0x0F, 0x05, 0xCF, 0x42, 
                /* 0420 */    0x0C, 0xEB, 0x98, 0x7C, 0x16, 0x62, 0x10, 0x2F, 
                /* 0428 */    0x9A, 0x86, 0x78, 0xE1, 0xF4, 0x61, 0xC0, 0xFF, 
                /* 0430 */    0x7F, 0xBC, 0xC0, 0xAF, 0x9C, 0x06, 0x0A, 0x12, 
                /* 0438 */    0xE8, 0x59, 0x08, 0x60, 0xFC, 0xFF, 0xFF, 0x2C, 
                /* 0440 */    0x04, 0x90, 0x71, 0x8D, 0x3A, 0x0B, 0x01, 0xCB, 
                /* 0448 */    0x63, 0x0C, 0x3B, 0xAD, 0x24, 0xF8, 0xFF, 0x3F, 
                /* 0450 */    0x0B, 0x01, 0x9F, 0x5C, 0x46, 0x0E, 0x42, 0x98, 
                /* 0458 */    0x88, 0x6F, 0x05, 0x1F, 0x33, 0x01, 0xA5, 0xE7, 
                /* 0460 */    0xA0, 0x17, 0x77, 0x63, 0x04, 0x7E, 0x91, 0x78, 
                /* 0468 */    0xCC, 0x64, 0x47, 0x4D, 0xC3, 0x3C, 0x0B, 0x19, 
                /* 0470 */    0xEF, 0x30, 0xCE, 0xE0, 0x09, 0xDE, 0x93, 0x7F, 
                /* 0478 */    0x16, 0x62, 0x60, 0xC7, 0x18, 0xEC, 0x51, 0xC8, 
                /* 0480 */    0xA0, 0x06, 0x8F, 0x1D, 0x22, 0x4C, 0xA0, 0x67, 
                /* 0488 */    0x21, 0x16, 0x6A, 0xDC, 0x3A, 0x7F, 0xF8, 0x2C, 
                /* 0490 */    0x04, 0xBC, 0xFF, 0xFF, 0x67, 0x21, 0xC0, 0xD3, 
                /* 0498 */    0x61, 0xC3, 0x67, 0x0D, 0xF0, 0x0C, 0xDF, 0xA3, 
                /* 04A0 */    0x3A, 0x87, 0xC7, 0x63, 0xE0, 0x92, 0x55, 0xC7, 
                /* 04A8 */    0x09, 0x83, 0xE5, 0x5E, 0xA7, 0x6C, 0x9C, 0x61, 
                /* 04B0 */    0xE8, 0x20, 0xAC, 0x0E, 0x48, 0xC3, 0xC1, 0xDC, 
                /* 04B8 */    0x43, 0x0E, 0xE2, 0x7C, 0xD8, 0x40, 0xAD, 0x08, 
                /* 04C0 */    0x4E, 0xC7, 0x24, 0x0F, 0xDA, 0x5A, 0x28, 0xA4, 
                /* 04C8 */    0x80, 0x46, 0x03, 0x32, 0xBC, 0x33, 0x9F, 0x96, 
                /* 04D0 */    0x28, 0x88, 0x01, 0x7D, 0x02, 0xB2, 0x8D, 0x73, 
                /* 04D8 */    0x00, 0x6A, 0x2F, 0x9A, 0x02, 0x39, 0xDA, 0x60, 
                /* 04E0 */    0xF4, 0x5F, 0x16, 0xE8, 0x6C, 0x7C, 0x0D, 0xE0, 
                /* 04E8 */    0x1A, 0x20, 0x74, 0x30, 0x30, 0xB4, 0xD5, 0xDC, 
                /* 04F0 */    0x62, 0x50, 0x60, 0xC6, 0x7F, 0x70, 0x31, 0x81, 
                /* 04F8 */    0x8F, 0x2E, 0xF8, 0xB3, 0x00, 0xEE, 0xFF, 0x3F, 
                /* 0500 */    0x5C, 0x8F, 0xF6, 0x5D, 0xA0, 0xEA, 0xC9, 0xEA, 
                /* 0508 */    0x8A, 0x60, 0x75, 0x97, 0x17, 0x08, 0x33, 0x32, 
                /* 0510 */    0x41, 0x7D, 0x07, 0x02, 0x50, 0x00, 0xF9, 0x0E, 
                /* 0518 */    0xE0, 0xA3, 0xD3, 0x73, 0x00, 0x9B, 0x48, 0x88, 
                /* 0520 */    0x30, 0xD1, 0x8C, 0x8E, 0x98, 0x30, 0x2A, 0xFA, 
                /* 0528 */    0x84, 0x29, 0x88, 0x27, 0xEC, 0x58, 0x13, 0x46, 
                /* 0530 */    0xCF, 0xC4, 0x77, 0x1B, 0x36, 0x62, 0x4C, 0x88, 
                /* 0538 */    0xDB, 0x06, 0xB4, 0x09, 0x06, 0xF5, 0x3D, 0x08, 
                /* 0540 */    0xD6, 0x90, 0xF9, 0x58, 0x7C, 0x67, 0xC0, 0x4D, 
                /* 0548 */    0x19, 0x8C, 0x73, 0x62, 0xD7, 0x04, 0x0B, 0x9C, 
                /* 0550 */    0x33, 0xC8, 0xE1, 0x31, 0xD7, 0x2F, 0x7E, 0x5B, 
                /* 0558 */    0xF2, 0xE8, 0xF8, 0x41, 0xC1, 0x37, 0x1C, 0x86, 
                /* 0560 */    0xFD, 0x30, 0xE6, 0x19, 0xBD, 0x8A, 0xF9, 0xE6, 
                /* 0568 */    0x86, 0x81, 0xF5, 0x78, 0x39, 0xAC, 0xD1, 0xC2, 
                /* 0570 */    0x1E, 0xDA, 0xAB, 0x87, 0xCF, 0x2D, 0x3E, 0x4F, 
                /* 0578 */    0x18, 0x23, 0xAC, 0x2F, 0x2C, 0xE0, 0x00, 0xFC, 
                /* 0580 */    0xFF, 0xBF, 0x5A, 0xC1, 0xBE, 0x6B, 0x80, 0xE7, 
                /* 0588 */    0x26, 0xE4, 0xBB, 0x06, 0xC0, 0xDA, 0xFF, 0xFF, 
                /* 0590 */    0x5D, 0x03, 0xFE, 0x35, 0xC1, 0x77, 0x0D, 0xE0, 
                /* 0598 */    0x3D, 0x74, 0xDF, 0x35, 0x80, 0x6B, 0xF6, 0xBB, 
                /* 05A0 */    0x06, 0xEA, 0x18, 0x60, 0x85, 0x77, 0x0D, 0x68, 
                /* 05A8 */    0xB7, 0xB4, 0x57, 0xB4, 0x87, 0x2A, 0x6B, 0xBA, 
                /* 05B0 */    0x6C, 0xA0, 0xD4, 0x5C, 0x36, 0x00, 0x6D, 0xFF, 
                /* 05B8 */    0xFF, 0xCB, 0x06, 0xB0, 0x91, 0x32, 0x61, 0x54, 
                /* 05C0 */    0xF8, 0x09, 0x53, 0x10, 0x4F, 0xD8, 0xC1, 0x2E, 
                /* 05C8 */    0x1B, 0xA0, 0x88, 0x71, 0xD9, 0x00, 0xFD, 0xD8, 
                /* 05D0 */    0x5E, 0x36, 0x80, 0xC1, 0x3D, 0x81, 0xDF, 0x36, 
                /* 05D8 */    0x80, 0x37, 0xA4, 0x6F, 0x1B, 0xC0, 0xF4, 0xFF, 
                /* 05E0 */    0x0F, 0x31, 0xFF, 0x6D, 0x03, 0xC5, 0x61, 0x95, 
                /* 05E8 */    0xB7, 0x0D, 0x88, 0x87, 0x77, 0x46, 0x60, 0x55, 
                /* 05F0 */    0xD7, 0x0D, 0x94, 0x9E, 0xEB, 0x06, 0x40, 0x02, 
                /* 05F8 */    0x31, 0x13, 0x46, 0xC5, 0x9F, 0x30, 0x05, 0xF1, 
                /* 0600 */    0x84, 0x1D, 0xED, 0xBA, 0x01, 0x8A, 0x20, 0xD7, 
                /* 0608 */    0x0D, 0xD0, 0xCF, 0xEB, 0x94, 0xC1, 0xFA, 0xFF, 
                /* 0610 */    0xBF, 0x6E, 0x60, 0x2F, 0x0A, 0x98, 0xFB, 0x06, 
                /* 0618 */    0xF0, 0x86, 0xE5, 0xF7, 0x0D, 0xC0, 0xC7, 0xE5, 
                /* 0620 */    0x1B, 0x73, 0xDF, 0x00, 0x6C, 0xFE, 0xFF, 0xEF, 
                /* 0628 */    0x1B, 0x00, 0x13, 0x2E, 0x0A, 0xB8, 0xFB, 0x06, 
                /* 0630 */    0xF0, 0xBE, 0x48, 0xFB, 0xBE, 0x01, 0x5C, 0x83, 
                /* 0638 */    0x49, 0xF8, 0xFF, 0xDF, 0xF5, 0xE8, 0x0B, 0x40, 
                /* 0640 */    0x51, 0x60, 0x50, 0x43, 0xF2, 0x99, 0x00, 0x3F, 
                /* 0648 */    0xBA, 0x83, 0x3B, 0xA6, 0xE0, 0x4C, 0x12, 0x1C, 
                /* 0650 */    0x6A, 0xE0, 0xBE, 0x02, 0x3C, 0xCD, 0x9F, 0xD6, 
                /* 0658 */    0x7B, 0xBD, 0xE7, 0xF1, 0x24, 0x10, 0x92, 0x1D, 
                /* 0660 */    0x61, 0x7C, 0x6C, 0x43, 0x9C, 0x0C, 0xC8, 0x41, 
                /* 0668 */    0xDC, 0x47, 0xF7, 0x88, 0xEF, 0xE1, 0x86, 0x49, 
                /* 0670 */    0xE0, 0x21, 0x33, 0x34, 0x0E, 0x8D, 0x1D, 0x86, 
                /* 0678 */    0xEF, 0x02, 0xC1, 0x0E, 0xE2, 0x30, 0xCE, 0xD7, 
                /* 0680 */    0x04, 0x9E, 0xD0, 0x83, 0xC0, 0x7B, 0xF9, 0xA3, 
                /* 0688 */    0x41, 0xF1, 0x77, 0x03, 0x4A, 0x60, 0xB8, 0xD0, 
                /* 0690 */    0x98, 0x91, 0xFA, 0x6C, 0xFF, 0x8E, 0x70, 0x24, 
                /* 0698 */    0x26, 0xB0, 0x7B, 0x48, 0x59, 0x13, 0xA0, 0xF1, 
                /* 06A0 */    0x96, 0x43, 0x20, 0x7A, 0xC3, 0x91, 0x2D, 0x14, 
                /* 06A8 */    0xCD, 0x2D, 0xCA, 0xFB, 0x42, 0x14, 0x3B, 0x43, 
                /* 06B0 */    0x10, 0x46, 0x94, 0x60, 0x41, 0x9E, 0xD6, 0x62, 
                /* 06B8 */    0x45, 0x79, 0x66, 0x37, 0x42, 0xC4, 0x10, 0xAF, 
                /* 06C0 */    0x0C, 0x81, 0x5E, 0x12, 0xC2, 0x07, 0x79, 0xEC, 
                /* 06C8 */    0x89, 0xD3, 0xFE, 0x20, 0x88, 0xF8, 0x17, 0x82, 
                /* 06D0 */    0x3C, 0x80, 0x28, 0xD2, 0x68, 0x50, 0xE7, 0x06, 
                /* 06D8 */    0x8F, 0xDD, 0x87, 0x10, 0x5F, 0xFE, 0x7D, 0xB8, 
                /* 06E0 */    0xF7, 0xE8, 0x0E, 0xEE, 0x45, 0xFE, 0xA0, 0x3D, 
                /* 06E8 */    0x3C, 0x76, 0xC2, 0xF0, 0x41, 0x03, 0x8E, 0x6B, 
                /* 06F0 */    0x40, 0x4D, 0xFF, 0x19, 0x01, 0x2C, 0x97, 0x7F, 
                /* 06F8 */    0xF8, 0xE3, 0xF1, 0x3D, 0xC1, 0xF3, 0x39, 0xE1, 
                /* 0700 */    0x04, 0x96, 0x3F, 0x08, 0xD4, 0x71, 0x84, 0xCF, 
                /* 0708 */    0xF3, 0x85, 0xC3, 0x90, 0xCF, 0x02, 0x87, 0xC5, 
                /* 0710 */    0xC4, 0x0A, 0xF8, 0xFF, 0x9F, 0x4C, 0xD8, 0x78, 
                /* 0718 */    0xC0, 0x7F, 0x0F, 0x79, 0xFD, 0xF7, 0xCD, 0xC0, 
                /* 0720 */    0xF3, 0x35, 0xC1, 0x88, 0x10, 0x72, 0x32, 0x1E, 
                /* 0728 */    0x34, 0xE8, 0xD9, 0xF8, 0x80, 0xE1, 0xEB, 0x09, 
                /* 0730 */    0x3B, 0x77, 0x70, 0x51, 0xE7, 0x0E, 0xD4, 0xD1, 
                /* 0738 */    0xC1, 0xA7, 0x06, 0x76, 0xB3, 0xC1, 0x1C, 0xB7, 
                /* 0740 */    0xF9, 0x59, 0x03, 0xFC, 0x23, 0x84, 0x7F, 0x7B, 
                /* 0748 */    0xF0, 0xBC, 0x7C, 0x65, 0x78, 0x75, 0x48, 0xE0, 
                /* 0750 */    0x90, 0x23, 0x44, 0x8F, 0xCB, 0x23, 0xC4, 0x9C, 
                /* 0758 */    0x6F, 0x30, 0x43, 0x04, 0xD7, 0x59, 0x00, 0x1C, 
                /* 0760 */    0x43, 0x04, 0x3E, 0x67, 0x4C, 0x9F, 0x71, 0x60, 
                /* 0768 */    0xFE, 0xFF, 0xCF, 0x38, 0xEC, 0xD2, 0xC3, 0x07, 
                /* 0770 */    0x6A, 0x78, 0x13, 0xF8, 0xFE, 0x8C, 0x3B, 0xD2, 
                /* 0778 */    0x18, 0x9C, 0x1F, 0x33, 0x1E, 0x76, 0x18, 0xF8, 
                /* 0780 */    0xFB, 0x8E, 0x67, 0x70, 0x34, 0x3E, 0xA0, 0x18, 
                /* 0788 */    0x21, 0xF8, 0x73, 0xC9, 0x73, 0x8A, 0x35, 0x0F, 
                /* 0790 */    0x52, 0x33, 0x7A, 0x67, 0x38, 0x04, 0x76, 0xB3, 
                /* 0798 */    0xC2, 0x1D, 0x38, 0x3C, 0x04, 0x3E, 0x80, 0x56, 
                /* 07A0 */    0x27, 0x47, 0x4E, 0x3F, 0xA7, 0x84, 0x1B, 0x3E, 
                /* 07A8 */    0xBF, 0x0A, 0x60, 0x0E, 0x41, 0x38, 0x85, 0x36, 
                /* 07B0 */    0x7D, 0x6A, 0x34, 0x6A, 0xD5, 0xA0, 0x4C, 0x8D, 
                /* 07B8 */    0x32, 0x0D, 0x6A, 0xF5, 0xA9, 0xD4, 0x98, 0xB1, 
                /* 07C0 */    0x0B, 0x8B, 0x03, 0xBE, 0x02, 0x74, 0x1C, 0xB0, 
                /* 07C8 */    0x3C, 0x0A, 0x1D, 0xC1, 0xC8, 0x9B, 0x40, 0x20, 
                /* 07D0 */    0x0E, 0x0B, 0x42, 0x23, 0xBD, 0x71, 0x04, 0x62, 
                /* 07D8 */    0xC9, 0xEF, 0x2F, 0x81, 0x58, 0xEE, 0x03, 0x45, 
                /* 07E0 */    0x20, 0x0E, 0x68, 0x02, 0x9C, 0xAA, 0x00, 0xA7, 
                /* 07E8 */    0xAF, 0x01, 0x81, 0x38, 0x32, 0x08, 0x15, 0xFA, 
                /* 07F0 */    0x35, 0x13, 0x88, 0x63, 0x82, 0xD0, 0x50, 0x3E, 
                /* 07F8 */    0x40, 0x98, 0xF4, 0x17, 0x80, 0x00, 0x89, 0x11, 
                /* 0800 */    0x10, 0x16, 0xEE, 0xE5, 0x20, 0x10, 0x4B, 0x7B, 
                /* 0808 */    0x2D, 0x08, 0xC4, 0x42, 0xAC, 0x80, 0xB0, 0xB8, 
                /* 0810 */    0x20, 0x34, 0x9C, 0x16, 0x10, 0x26, 0xC9, 0x0C, 
                /* 0818 */    0x08, 0x0B, 0x04, 0x42, 0xE5, 0x3F, 0xD3, 0x04, 
                /* 0820 */    0x62, 0x91, 0x6E, 0x00, 0xE9, 0xBA, 0x05, 0xE2, 
                /* 0828 */    0x20, 0x7A, 0x40, 0x98, 0x0C, 0x3F, 0x20, 0x2C, 
                /* 0830 */    0x34, 0x08, 0x8D, 0xF6, 0x6C, 0x10, 0x20, 0x31, 
                /* 0838 */    0x04, 0xC2, 0xE2, 0x3B, 0x02, 0x61, 0xE2, 0xDF, 
                /* 0840 */    0x44, 0x02, 0x71, 0x4A, 0x4B, 0x10, 0x37, 0xA5, 
                /* 0848 */    0x01, 0x06, 0x11, 0x90, 0x93, 0x6A, 0x02, 0x62, 
                /* 0850 */    0xB9, 0x41, 0x34, 0x24, 0xF2, 0xB0, 0x10, 0x90, 
                /* 0858 */    0x93, 0x82, 0x68, 0xC0, 0xC4, 0x14, 0x90, 0xFF, 
                /* 0860 */    0xFF, 0x43, 0x13, 0x88, 0x80, 0x9C, 0xCA, 0x15, 
                /* 0868 */    0x10, 0x8B, 0x08, 0x22, 0x20, 0x27, 0x7B, 0x52, 
                /* 0870 */    0x09, 0xC8, 0x39, 0x41, 0x74, 0x04, 0x20, 0xBA, 
                /* 0878 */    0x80, 0x58, 0x3E, 0x10, 0x01, 0x39, 0x96, 0x2F, 
                /* 0880 */    0x20, 0x16, 0x12, 0x44, 0x40, 0x4E, 0xF4, 0xF3, 
                /* 0888 */    0x09, 0x44, 0xE2, 0x81, 0x68, 0x10, 0xE4, 0x3F, 
                /* 0890 */    0x21, 0x20, 0x67, 0x04, 0x11, 0x10, 0x79, 0x12, 
                /* 0898 */    0x05, 0x21, 0x9A, 0x3E, 0x62, 0x02, 0x71, 0x6A, 
                /* 08A0 */    0x10, 0x9A, 0xEC, 0x27, 0x14, 0x84, 0xFC, 0xFF, 
                /* 08A8 */    0x01
            })
        }

        Device (PCI0)
        {
            Name (_ADR, 0x00)
            Name (_HID, EisaId ("PNP0A03"))
            Name (_UID, 0x01)
            Method (_INI, 0, NotSerialized)
            {
                Store (0x07D0, OSYS)
                If (CondRefOf (_OSI, Local0))
                {
                    If (\_OSI ("Linux"))
                    {
                        Store (0x03E8, OSYS)
                    }

                    If (\_OSI ("Windows 2001"))
                    {
                        Store (0x07D1, OSYS)
                    }

                    If (\_OSI ("Windows 2001 SP1"))
                    {
                        Store (0x07D1, OSYS)
                    }

                    If (\_OSI ("Windows 2001 SP2"))
                    {
                        Store (0x07D2, OSYS)
                    }

                    If (\_OSI ("Windows 2006"))
                    {
                        Store (0x07D6, OSYS)
                    }
                }
            }

            Method (_STA, 0, NotSerialized)
            {
                Return (0x0F)
            }

            Scope (\_SB)
            {
                OperationRegion (ASLD, SystemMemory, 0x7FF15DBC, 0x00000100)
                Field (ASLD, AnyAcc, NoLock, Preserve)
                {
                    TOM,    32, 
                    R_ST,   1, 
                        ,   3, 
                    R_P0,   4, 
                    R_S0,   4, 
                    R_S1,   4, 
                    RSS0,   4, 
                    RSS1,   4, 
                    PSTN,   8, 
                    DUAL,   8, 
                    IVIM,   8, 
                    ACBR,   8, 
                    DCBR,   8, 
                    WC01,   8, 
                    SID0,   8, 
                    SID1,   8, 
                    SID2,   8, 
                    SID3,   8, 
                    SID4,   8, 
                    EAX0,   32, 
                    EBX0,   32, 
                    CCBR,   8, 
                    ACST,   8
                }
            }

            Method (_CRS, 0, NotSerialized)
            {
                Name (CBUF, ResourceTemplate ()
                {
                    WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
                        0x0000,             // Granularity
                        0x0000,             // Range Minimum
                        0x00FF,             // Range Maximum
                        0x0000,             // Translation Offset
                        0x0100,             // Length
                        ,, )
                    IO (Decode16,
                        0x0CF8,             // Range Minimum
                        0x0CF8,             // Range Maximum
                        0x01,               // Alignment
                        0x08,               // Length
                        )
                    WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
                        0x0000,             // Granularity
                        0x0000,             // Range Minimum
                        0x0CF7,             // Range Maximum
                        0x0000,             // Translation Offset
                        0x0CF8,             // Length
                        ,, , TypeStatic)
                    WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
                        0x0000,             // Granularity
                        0x0D00,             // Range Minimum
                        0xFFFF,             // Range Maximum
                        0x0000,             // Translation Offset
                        0xF300,             // Length
                        ,, , TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000A0000,         // Range Minimum
                        0x000BFFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00020000,         // Length
                        ,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000C0000,         // Range Minimum
                        0x000C3FFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000C4000,         // Range Minimum
                        0x000C7FFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000C8000,         // Range Minimum
                        0x000CBFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000CC000,         // Range Minimum
                        0x000CFFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000D0000,         // Range Minimum
                        0x000D3FFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000D4000,         // Range Minimum
                        0x000D7FFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000D8000,         // Range Minimum
                        0x000DBFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000DC000,         // Range Minimum
                        0x000DFFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000E0000,         // Range Minimum
                        0x000E3FFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000E4000,         // Range Minimum
                        0x000E7FFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000E8000,         // Range Minimum
                        0x000EBFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000EC000,         // Range Minimum
                        0x000EFFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00004000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x000F0000,         // Range Minimum
                        0x000FFFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0x00010000,         // Length
                        0x00,, , AddressRangeMemory, TypeStatic)
                    DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
                        0x00000000,         // Granularity
                        0x00100000,         // Range Minimum
                        0xFEBFFFFF,         // Range Maximum
                        0x00000000,         // Translation Offset
                        0xFFF00000,         // Length
                        ,, _Y01, AddressRangeMemory, TypeStatic)
                })
                CreateDWordField (CBUF, \_SB.PCI0._CRS._Y01._MIN, PMMN)
                CreateDWordField (CBUF, \_SB.PCI0._CRS._Y01._LEN, PMLN)
                Multiply (\_SB.TOM, 0x00100000, PMMN)
                Subtract (0xFEC00000, PMMN, PMLN)
                Return (CBUF)
            }

            Name (_PRT, Package (0x0D)
            {
                Package (0x04)
                {
                    0x000AFFFF, 
                    0x00, 
                    \_SB.PCI0.LSMB, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x000AFFFF, 
                    0x01, 
                    \_SB.PCI0.LPMU, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x000BFFFF, 
                    0x00, 
                    \_SB.PCI0.LUS0, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x000BFFFF, 
                    0x01, 
                    \_SB.PCI0.LUS2, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x0014FFFF, 
                    0x00, 
                    \_SB.PCI0.LMAC, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x0010FFFF, 
                    0x01, 
                    \_SB.PCI0.LAZA, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x000DFFFF, 
                    0x00, 
                    \_SB.PCI0.LPID, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x000EFFFF, 
                    0x00, 
                    \_SB.PCI0.LTID, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x000FFFFF, 
                    0x00, 
                    \_SB.PCI0.LSI1, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x0005FFFF, 
                    0x00, 
                    \_SB.PCI0.LK3E, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x0005FFFF, 
                    0x01, 
                    \_SB.PCI0.LK4E, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x0005FFFF, 
                    0x02, 
                    \_SB.PCI0.LK1E, 
                    0x00
                }, 

                Package (0x04)
                {
                    0x0005FFFF, 
                    0x03, 
                    \_SB.PCI0.LK2E, 
                    0x00
                }
            })
            Device (LPC0)
            {
                Name (_ADR, 0x000A0000)
                OperationRegion (P44, PCI_Config, 0x44, 0x04)
                Field (P44, AnyAcc, NoLock, Preserve)
                {
                    MTBA,   32
                }

                OperationRegion (P74, PCI_Config, 0x74, 0x04)
                Field (P74, AnyAcc, NoLock, Preserve)
                {
                    HPTF,   16
                }

                Device (MBRD)
                {
                    Name (_HID, EisaId ("PNP0C02"))
                    Name (_UID, 0x1F)
                    Name (RSRC, ResourceTemplate ()
                    {
                        Memory32Fixed (ReadWrite,
                            0xE0000000,         // Address Base
                            0x10000000,         // Address Length
                            )
                    })
                    Method (_CRS, 0, NotSerialized)
                    {
                        Return (RSRC)
                    }
                }

                Device (PMIO)
                {
                    Name (_HID, EisaId ("PNP0C02"))
                    Name (_UID, 0x03)
                    Method (_CRS, 0, NotSerialized)
                    {
                        Name (IODM, ResourceTemplate ()
                        {
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x00,               // Alignment
                                0x00,               // Length
                                )
                        })
                        Name (IORT, ResourceTemplate ()
                        {
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x80,               // Length
                                _Y02)
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x80,               // Length
                                _Y03)
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x80,               // Length
                                _Y04)
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x80,               // Length
                                _Y05)
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x80,               // Length
                                _Y06)
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x80,               // Length
                                _Y07)
                            IO (Decode16,
                                0x0000,             // Range Minimum
                                0x0000,             // Range Maximum
                                0x01,               // Alignment
                                0x40,               // Length
                                _Y08)
                        })
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y02._MIN, I1MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y02._MAX, I1MX)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y03._MIN, I2MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y03._MAX, I2MX)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y04._MIN, I3MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y04._MAX, I3MX)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y05._MIN, I4MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y05._MAX, I4MX)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y06._MIN, I5MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y06._MAX, I5MX)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y07._MIN, I6MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y07._MAX, I6MX)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y08._MIN, I9MN)
                        CreateWordField (IORT, \_SB.PCI0.LPC0.PMIO._CRS._Y08._MAX, I9MX)
                        And (\_SB.PCI0.SMB0.PMBR, 0xFFFC, I1MN)
                        Store (I1MN, I1MX)
                        Add (I1MN, 0x80, Local0)
                        Store (Local0, I2MN)
                        Store (Local0, I2MX)
                        And (\_SB.PCI0.SMB0.NVSB, 0xFFFC, I3MN)
                        Store (I3MN, I3MX)
                        Add (I3MN, 0x80, Local0)
                        Store (Local0, I4MN)
                        Store (Local0, I4MX)
                        And (\_SB.PCI0.SMB0.ANLG, 0xFFFC, I5MN)
                        Store (I5MN, I5MX)
                        Add (I5MN, 0x80, Local0)
                        Store (Local0, I6MN)
                        Store (Local0, I6MX)
                        And (\_SB.PCI0.SMB0.SB7C, 0xFFFC, I9MN)
                        Store (I9MN, I9MX)
                        If (I1MN)
                        {
                            Store (IORT, Local0)
                        }
                        Else
                        {
                            Store (IODM, Local0)
                        }

                        Return (Local0)
                    }
                }
            }

            OperationRegion (SSMI, SystemIO, 0x142E, 0x02)
            Field (SSMI, ByteAcc, NoLock, Preserve)
            {
                SMIC,   8, 
                SMIS,   8
            }

            Mutex (PSMX, 0x00)
            Method (PHSR, 2, NotSerialized)
            {
                Acquire (PSMX, 0xFFFF)
                Store (Arg1, SMIS)
                Store (Arg0, SMIC)
                Store (SMIS, Local0)
                Release (PSMX)
                Return (Local0)
            }

            Device (SYS0)
            {
                Name (_HID, EisaId ("PNP0C02"))
                Name (_UID, 0x01)
                Name (_CRS, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0010,             // Range Minimum
                        0x0010,             // Range Maximum
                        0x01,               // Alignment
                        0x10,               // Length
                        )
                    IO (Decode16,
                        0x0022,             // Range Minimum
                        0x0022,             // Range Maximum
                        0x01,               // Alignment
                        0x1E,               // Length
                        )
                    IO (Decode16,
                        0x0044,             // Range Minimum
                        0x0044,             // Range Maximum
                        0x01,               // Alignment
                        0x1C,               // Length
                        )
                    IO (Decode16,
                        0x0068,             // Range Minimum
                        0x0068,             // Range Maximum
                        0x01,               // Alignment
                        0x08,               // Length
                        )
                    IO (Decode16,
                        0x0080,             // Range Minimum
                        0x0080,             // Range Maximum
                        0x00,               // Alignment
                        0x01,               // Length
                        )
                    IO (Decode16,
                        0x0091,             // Range Minimum
                        0x0091,             // Range Maximum
                        0x01,               // Alignment
                        0x03,               // Length
                        )
                    IO (Decode16,
                        0x0097,             // Range Minimum
                        0x0097,             // Range Maximum
                        0x01,               // Alignment
                        0x09,               // Length
                        )
                    IO (Decode16,
                        0x00A2,             // Range Minimum
                        0x00A2,             // Range Maximum
                        0x01,               // Alignment
                        0x1E,               // Length
                        )
                    IO (Decode16,
                        0x00E0,             // Range Minimum
                        0x00E0,             // Range Maximum
                        0x01,               // Alignment
                        0x10,               // Length
                        )
                    IO (Decode16,
                        0x0360,             // Range Minimum
                        0x0360,             // Range Maximum
                        0x01,               // Alignment
                        0x02,               // Length
                        )
                    IO (Decode16,
                        0x0380,             // Range Minimum
                        0x0380,             // Range Maximum
                        0x01,               // Alignment
                        0x04,               // Length
                        )
                    IO (Decode16,
                        0x04D0,             // Range Minimum
                        0x04D0,             // Range Maximum
                        0x01,               // Alignment
                        0x02,               // Length
                        )
                })
            }

            Device (PIC0)
            {
                Name (_HID, EisaId ("PNP0000"))
                Name (_CRS, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0020,             // Range Minimum
                        0x0020,             // Range Maximum
                        0x04,               // Alignment
                        0x02,               // Length
                        )
                    IO (Decode16,
                        0x00A0,             // Range Minimum
                        0x00A0,             // Range Maximum
                        0x04,               // Alignment
                        0x02,               // Length
                        )
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {2}
                })
            }

            Device (DMA0)
            {
                Name (_HID, EisaId ("PNP0200"))
                Name (_CRS, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0000,             // Range Minimum
                        0x0000,             // Range Maximum
                        0x01,               // Alignment
                        0x09,               // Length
                        )
                    IO (Decode16,
                        0x000A,             // Range Minimum
                        0x000A,             // Range Maximum
                        0x01,               // Alignment
                        0x06,               // Length
                        )
                    IO (Decode16,
                        0x0081,             // Range Minimum
                        0x0081,             // Range Maximum
                        0x01,               // Alignment
                        0x03,               // Length
                        )
                    IO (Decode16,
                        0x0087,             // Range Minimum
                        0x0087,             // Range Maximum
                        0x01,               // Alignment
                        0x01,               // Length
                        )
                    IO (Decode16,
                        0x0089,             // Range Minimum
                        0x0089,             // Range Maximum
                        0x01,               // Alignment
                        0x03,               // Length
                        )
                    IO (Decode16,
                        0x008F,             // Range Minimum
                        0x008F,             // Range Maximum
                        0x01,               // Alignment
                        0x01,               // Length
                        )
                    IO (Decode16,
                        0x00C0,             // Range Minimum
                        0x00C0,             // Range Maximum
                        0x01,               // Alignment
                        0x12,               // Length
                        )
                    IO (Decode16,
                        0x00D4,             // Range Minimum
                        0x00D4,             // Range Maximum
                        0x01,               // Alignment
                        0x0C,               // Length
                        )
                    DMA (Compatibility, BusMaster, Transfer8, )
                        {4}
                })
            }

            Device (SPK0)
            {
                Name (_HID, EisaId ("PNP0800"))
                Name (_CRS, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0061,             // Range Minimum
                        0x0061,             // Range Maximum
                        0x01,               // Alignment
                        0x01,               // Length
                        )
                })
            }

            Device (MTH0)
            {
                Name (_HID, EisaId ("PNP0C04"))
                Name (_CRS, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x00F0,             // Range Minimum
                        0x00F0,             // Range Maximum
                        0x01,               // Alignment
                        0x02,               // Length
                        )
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {13}
                })
            }

            Device (PIT0)
            {
                Name (_HID, EisaId ("PNP0100"))
                Name (BUF0, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0040,             // Range Minimum
                        0x0040,             // Range Maximum
                        0x00,               // Alignment
                        0x04,               // Length
                        )
                })
                Name (BUF1, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0040,             // Range Minimum
                        0x0040,             // Range Maximum
                        0x00,               // Alignment
                        0x04,               // Length
                        )
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {0}
                })
                Method (_CRS, 0, NotSerialized)
                {
                    If (And (\_SB.PCI0.LPC0.HPTF, 0x04))
                    {
                        Return (BUF0)
                    }
                    Else
                    {
                        Return (BUF1)
                    }
                }
            }

            Device (RTC0)
            {
                Name (_HID, EisaId ("PNP0B00"))
                Name (BUF2, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0070,             // Range Minimum
                        0x0070,             // Range Maximum
                        0x00,               // Alignment
                        0x02,               // Length
                        )
                })
                Name (BUF3, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0070,             // Range Minimum
                        0x0070,             // Range Maximum
                        0x00,               // Alignment
                        0x02,               // Length
                        )
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {8}
                })
                Method (_CRS, 0, NotSerialized)
                {
                    If (And (\_SB.PCI0.LPC0.HPTF, 0x04))
                    {
                        Return (BUF2)
                    }
                    Else
                    {
                        Return (BUF3)
                    }
                }
            }

            Device (MMTM)
            {
                Name (_HID, EisaId ("PNP0103"))
                Name (BUF4, ResourceTemplate ()
                {
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {0}
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {8}
                    Memory32Fixed (ReadOnly,
                        0x00000000,         // Address Base
                        0x00000400,         // Address Length
                        _Y09)
                })
                Name (BUF5, ResourceTemplate ()
                {
                })
                Method (_STA, 0, NotSerialized)
                {
                    If (And (\_SB.PCI0.LPC0.HPTF, 0x04))
                    {
                        Return (0x0F)
                    }

                    Return (0x00)
                }

                CreateDWordField (BUF4, \_SB.PCI0.MMTM._Y09._BAS, MMBB)
                Method (_CRS, 0, NotSerialized)
                {
                    If (And (\_SB.PCI0.LPC0.HPTF, 0x04))
                    {
                        Store (\_SB.PCI0.LPC0.MTBA, MMBB)
                        Return (BUF4)
                    }
                    Else
                    {
                        Return (BUF5)
                    }
                }
            }

            Device (KBC0)
            {
                Name (_HID, EisaId ("PNP0303"))
                Name (_CRS, ResourceTemplate ()
                {
                    IO (Decode16,
                        0x0060,             // Range Minimum
                        0x0060,             // Range Maximum
                        0x01,               // Alignment
                        0x01,               // Length
                        )
                    IO (Decode16,
                        0x0064,             // Range Minimum
                        0x0064,             // Range Maximum
                        0x01,               // Alignment
                        0x01,               // Length
                        )
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {1}
                })
            }

            Device (MSE0)
            {
                Method (_HID, 0, NotSerialized)
                {
                    If (LEqual (HPBD, 0x01))
                    {
                        Return ("*SYN012A")
                    }
                    Else
                    {
                        Return ("*SYN0129")
                    }
                }

                Name (_CID, Package (0x03)
                {
                    0x00012E4F, 
                    0x02002E4F, 
                    0x130FD041
                })
                Name (_CRS, ResourceTemplate ()
                {
                    IRQ (Edge, ActiveHigh, Exclusive, )
                        {12}
                })
            }

            Device (EC0)
            {
                Name (_HID, EisaId ("PNP0C09"))
                Name (_UID, 0x01)
                Name (_GPE, 0x10)
                Method (_CRS, 0, NotSerialized)
                {
                    Name (BFFR, ResourceTemplate ()
                    {
                        IO (Decode16,
                            0x0062,             // Range Minimum
                            0x0062,             // Range Maximum
                            0x00,               // Alignment
                            0x01,               // Length
                            )
                        IO (Decode16,
                            0x0066,             // Range Minimum
                            0x0066,             // Range Maximum
                            0x00,               // Alignment
                            0x01,               // Length
                            )
                    })
                    Return (BFFR)
                }

                OperationRegion (ERAM, EmbeddedControl, 0x00, 0xFF)
                Field (ERAM, ByteAcc, Lock, Preserve)
                {
                    SMPR,   8, 
                    SMST,   8, 
                    SMAD,   8, 
                    SMCM,   8, 
                    SMD0,   256, 
                    BCNT,   8, 
                    SMAA,   8, 
                    BATD,   16, 
                            Offset (0x40), 
                    ACIN,   1, 
                            Offset (0x41), 
                        ,   4, 
                    FANC,   1, 
                    BLED,   1, 
                    AADA,   1, 
                            Offset (0x42), 
                        ,   7, 
                    Q8EO,   1, 
                        ,   4, 
                    BANK,   4, 
                            Offset (0x45), 
                    VFAN,   1, 
                    ISEN,   1, 
                    KBEP,   1, 
                    ASCN,   1, 
                    ALIN,   1, 
                            Offset (0x4E), 
                    LIDP,   1, 
                    DT1P,   1, 
                    ODDW,   1, 
                    PRPP,   1, 
                        ,   1, 
                        ,   1, 
                        ,   1, 
                            Offset (0x4F), 
                            Offset (0x52), 
                    LIDS,   1, 
                    DT1I,   1, 
                        ,   1, 
                    PREP,   1, 
                    RBAT,   1, 
                    CRTS,   1, 
                    ABTN,   1, 
                    DBAY,   1, 
                            Offset (0x58), 
                    RTMP,   8, 
                    ECT1,   8, 
                    ECT2,   8, 
                    RG5B,   8, 
                    FSPD,   16, 
                            Offset (0x61), 
                    QPDD,   8, 
                            Offset (0x72), 
                    BFCC,   16, 
                            Offset (0x82), 
                    MBST,   8, 
                    MCUR,   16, 
                    MBRM,   16, 
                    MBCV,   16, 
                            Offset (0xA0), 
                    QBHK,   8, 
                            Offset (0xA2), 
                    QBBB,   8, 
                            Offset (0xA4), 
                    MBTS,   1, 
                    MBTF,   1, 
                    BDES,   1, 
                    BTRK,   1, 
                    BARM,   1, 
                    BLOW,   1, 
                    BDIS,   1, 
                    BDED,   1, 
                        ,   3, 
                    NIMH,   1, 
                            Offset (0xAF), 
                    BATT,   8, 
                            Offset (0xB3), 
                    BACU,   8, 
                            Offset (0xC0), 
                    BRID,   8, 
                            Offset (0xE0), 
                    DTMC,   8, 
                            Offset (0xE2), 
                    BRIC,   8, 
                            Offset (0xE6), 
                    SFHK,   8, 
                    GQKS,   7
                }

                Field (ERAM, ByteAcc, NoLock, Preserve)
                {
                            Offset (0x04), 
                    SMW0,   16
                }

                Field (ERAM, ByteAcc, NoLock, Preserve)
                {
                            Offset (0x04), 
                    SMB0,   8
                }

                Field (ERAM, ByteAcc, NoLock, Preserve)
                {
                            Offset (0x04), 
                    FLD0,   64
                }

                Field (ERAM, ByteAcc, NoLock, Preserve)
                {
                            Offset (0x04), 
                    FLD1,   128
                }

                Field (ERAM, ByteAcc, NoLock, Preserve)
                {
                            Offset (0x04), 
                    FLD2,   192
                }

                Field (ERAM, ByteAcc, NoLock, Preserve)
                {
                            Offset (0x04), 
                    FLD3,   256
                }

                Name (BATO, 0x00)
                Name (BATN, 0x00)
                Name (BATF, 0xC0)
                Mutex (MUT0, 0x00)
                Mutex (MUT1, 0x00)
                Method (_REG, 2, NotSerialized)
                {
                    If (LAnd (LEqual (Arg0, 0x03), LEqual (Arg1, 0x01)))
                    {
                        Store (0x01, ECON)
                    }
                }

                Method (_Q20, 0, NotSerialized)
                {
                    Store (0x20, \DBUG)
                    If (LEqual (OSYS, 0x07D6))
                    {
                        Notify (\_SB.BAT0, 0x81)
                    }

                    Notify (\_SB.ACAD, 0x80)
                    Notify (\_SB.BAT0, 0x80)
                }

                Method (_Q21, 0, NotSerialized)
                {
                    Store (0x21, \DBUG)
                    Notify (\_SB.ACAD, 0x80)
                    Notify (\_SB.BAT0, 0x80)
                    RSBR ()
                }

                Method (_Q09, 0, NotSerialized)
                {
                    If (LEqual (DTCN, 0x02))
                    {
                        Store (0x00, DTCN)
                    }
                    Else
                    {
                        Add (DTCN, 0x01, DTCN)
                        Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                        Store (0x96, \_SB.PCI0.EC0.DTMC)
                        Release (\_SB.PCI0.EC0.MUT0)
                    }

                    Store (0x09, \DBUG)
                    Store (0x05, \_SB.WMID.Z00P)
                    Store (0x00, \_SB.WMID.Z00Q)
                    Notify (\_SB.WMID, 0x80)
                }

                Method (_Q0D, 0, NotSerialized)
                {
                    Store (0x0D, \DBUG)
                    If (VGAT)
                    {
                        VSWT ()
                    }
                    Else
                    {
                        VSWU ()
                    }
                }

                Method (_Q10, 0, NotSerialized)
                {
                    Store (0x10, \DBUG)
                    If (LEqual (OSYS, 0x07D6))
                    {
                        If (LEqual (VGAT, 0x01))
                        {
                            Notify (\_SB.PCI0.XVR0.VGA.LCD, 0x87)
                        }
                        Else
                        {
                            Notify (\_SB.PCI0.UVGA.LCD, 0x87)
                        }
                    }
                    Else
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x8D, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local0)
                        Release (\_SB.PCI0.PSMX)
                    }
                }

                Method (_Q11, 0, NotSerialized)
                {
                    If (LEqual (OSYS, 0x07D6))
                    {
                        If (LEqual (VGAT, 0x01))
                        {
                            Notify (\_SB.PCI0.XVR0.VGA.LCD, 0x86)
                        }
                        Else
                        {
                            Notify (\_SB.PCI0.UVGA.LCD, 0x86)
                        }
                    }
                    Else
                    {
                        Store (0x11, \DBUG)
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x8C, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local0)
                        Release (\_SB.PCI0.PSMX)
                    }
                }

                Method (_Q15, 0, NotSerialized)
                {
                    Store (0x15, \DBUG)
                    Store ("!!! Wireless Button pressed !!!", Debug)
                    Acquire (M723, 0xFFFF)
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    If (\_SB.PCI0.EC0.DT1I)
                    {
                        Store (0x00, BTLS)
                    }
                    Else
                    {
                        Store (0x01, BTLS)
                    }

                    Release (\_SB.PCI0.EC0.MUT0)
                    If (LOr (BTSU, WLSU))
                    {
                        If (BTLS)
                        {
                            Store (0x00, BTLS)
                            Store (0x00, GP25)
                            Store (0x04, GP24)
                            Store (0x00, GP26)
                            Store (0x04, GP23)
                        }
                        Else
                        {
                            Store (0x01, BTLS)
                            If (WLSU)
                            {
                                If (WIRE)
                                {
                                    If (WWLS)
                                    {
                                        Store (0x01, GP26)
                                        Store (0x05, GP23)
                                    }
                                }
                                Else
                                {
                                    Store (0x01, GP26)
                                    Store (0x05, GP23)
                                }
                            }

                            If (BTSU)
                            {
                                If (WIRE)
                                {
                                    If (BWLS)
                                    {
                                        Store (0x01, GP25)
                                        Store (0x05, GP24)
                                    }
                                }
                                Else
                                {
                                    Store (0x01, GP25)
                                    Store (0x05, GP24)
                                }
                            }
                        }
                    }
                    Else
                    {
                        Store (0x00, BTLS)
                        Store (0x00, GP25)
                        Store (0x04, GP24)
                        Store (0x00, GP26)
                        Store (0x04, GP23)
                    }

                    Release (M723)
                    Store (0x05, \_SB.WMID.Z00P)
                    Store (0x00, \_SB.WMID.Z00Q)
                    Notify (\_SB.WMID, 0x80)
                }

                Method (_Q16, 0, NotSerialized)
                {
                    Store (QBBB, Local0)
                    If (LEqual (Local0, 0x00))
                    {
                        Store (QPDD, Local0)
                        ShiftRight (Local0, 0x02, Local0)
                        Add (Local0, 0x02, Local0)
                        If (LEqual (Local0, 0x01))
                        {
                            Notify (\_SB.QBTN, 0x80)
                        }

                        If (LEqual (Local0, 0x02))
                        {
                            Notify (\_SB.DBTN, 0x80)
                        }
                    }
                    Else
                    {
                        If (LEqual (OSYS, 0x07D6))
                        {
                            If (LEqual (Local0, 0x04))
                            {
                                Store (0x04, \_SB.WMID.Z00P)
                                Store (0x00, \_SB.WMID.Z00Q)
                                Notify (\_SB.WMID, 0x80)
                                Return (0x00)
                            }

                            If (LEqual (Local0, 0x05))
                            {
                                Store (0x04, \_SB.WMID.Z00P)
                                Store (0x00, \_SB.WMID.Z00Q)
                                Notify (\_SB.WMID, 0x80)
                                Return (0x00)
                            }

                            If (LEqual (Local0, 0x07))
                            {
                                Store (0x04, \_SB.WMID.Z00P)
                                Store (0x00, \_SB.WMID.Z00Q)
                                Notify (\_SB.WMID, 0x80)
                                Return (0x00)
                            }

                            If (LEqual (Local0, 0x08))
                            {
                                Store (0x04, \_SB.WMID.Z00P)
                                Store (0x00, \_SB.WMID.Z00Q)
                                Notify (\_SB.WMID, 0x80)
                                Return (0x00)
                            }

                            If (LEqual (Local0, 0x10))
                            {
                                Store (0x04, \_SB.WMID.Z00P)
                                Store (0x00, \_SB.WMID.Z00Q)
                                Notify (\_SB.WMID, 0x80)
                                Return (0x00)
                            }

                            If (LEqual (Local0, 0x03))
                            {
                                Store (0x04, \_SB.WMID.Z00P)
                                Store (0x00, \_SB.WMID.Z00Q)
                                Notify (\_SB.WMID, 0x80)
                                Return (0x00)
                            }
                        }

                        Store (0x04, \_SB.WMID.Z00P)
                        Store (0x00, \_SB.WMID.Z00Q)
                        Notify (\_SB.WMID, 0x80)
                    }
                }

                Method (_Q80, 0, NotSerialized)
                {
                    Store ("_Q80 : Temperature Up", Debug)
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    Store (\_SB.PCI0.EC0.RTMP, Local0)
                    Release (\_SB.PCI0.EC0.MUT0)
                    If (LGreater (Local0, 0x57))
                    {
                        Store (\_SB.PSTN, DBUG)
                        Store (\_SB.PSTN, \_PR.CPU0._PPC)
                        Notify (\_PR.CPU0, 0x80)
                    }
                    Else
                    {
                        If (LLess (Local0, 0x4B))
                        {
                            If (LEqual (Q8EO, 0x00))
                            {
                                Store (0x00, \_PR.CPU0._PPC)
                                Notify (\_PR.CPU0, 0x80)
                            }
                        }
                    }
                }

                Method (_Q81, 0, NotSerialized)
                {
                    Store ("_Q81 : Temperature Down", Debug)
                }

                Name (ARG9, 0x00)
                Name (ARG8, 0x00)
                Method (_Q8E, 0, NotSerialized)
                {
                    If (LLess (\_PR.CPU0._PPC, \_SB.PSTN))
                    {
                        Add (\_PR.CPU0._PPC, 0x01, \_PR.CPU0._PPC)
                        If (LGreater (\_PR.CPU0._PPC, \_SB.PSTN))
                        {
                            Store (\_SB.PSTN, \_PR.CPU0._PPC)
                            Notify (\_PR.CPU0, 0x80)
                        }
                        Else
                        {
                            If (LEqual (BACU, 0x01))
                            {
                                If (LGreaterEqual (BATT, 0x3A))
                                {
                                    Subtract (BATT, 0x3A, ARG9)
                                    Divide (ARG9, 0x02, ARG8, ARG9)
                                    Add (ARG9, 0x01, ARG9)
                                    If (LLessEqual (ARG9, \_SB.PSTN))
                                    {
                                        Store (ARG9, \_PR.CPU0._PPC)
                                    }
                                    Else
                                    {
                                        Store (\_SB.PSTN, \_PR.CPU0._PPC)
                                    }
                                }
                            }

                            Notify (\_PR.CPU0, 0x80)
                        }
                    }
                }

                Method (_Q8F, 0, NotSerialized)
                {
                    If (LGreater (\_PR.CPU0._PPC, 0x00))
                    {
                        Subtract (\_PR.CPU0._PPC, 0x01, \_PR.CPU0._PPC)
                        Notify (\_PR.CPU0, 0x80)
                        If (LEqual (\_PR.CPU0._PPC, 0x00))
                        {
                            Store (0x00, Q8EO)
                        }
                        Else
                        {
                            Store (0x01, Q8EO)
                        }
                    }
                    Else
                    {
                        Store (0x00, Q8EO)
                    }
                }

                Method (_Q8A, 0, NotSerialized)
                {
                    If (LIDP)
                    {
                        Store ("_Q8A : Lid Event", Debug)
                        Store (0x00, LIDP)
                    }

                    Notify (\_SB.LID, 0x80)
                }

                Method (VSWT, 0, NotSerialized)
                {
                    Store ("Hot-Keys: ----- _Q0C", Debug)
                    If (LEqual (\_SB.PCI0.XVR0.VGA.SWIT, 0x00))
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x88, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local0)
                        Release (\_SB.PCI0.PSMX)
                        Store (Local0, CADL)
                        If (LEqual (Local0, 0x10)) {}
                        Else
                        {
                            Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                            Store (0x87, \_SB.PCI0.SMIC)
                            Store (\_SB.PCI0.SMIS, Local1)
                            Release (\_SB.PCI0.PSMX)
                            Store (Local1, PSTE)
                            If (LEqual (Local1, 0x09))
                            {
                                Store (Zero, Local1)
                            }

                            If (LEqual (Local1, 0x05))
                            {
                                Store (0x08, Local1)
                            }

                            Store (Local1, \_SB.PCI0.XVR0.VGA.TOGF)
                            Increment (\_SB.PCI0.XVR0.VGA.TOGF)
                            While (LNotEqual (And (Local0, \_SB.PCI0.XVR0.VGA.TOGF), \_SB.PCI0.XVR0.VGA.TOGF))
                            {
                                Increment (\_SB.PCI0.XVR0.VGA.TOGF)
                                If (LGreater (\_SB.PCI0.XVR0.VGA.TOGF, 0x09))
                                {
                                    Store (One, \_SB.PCI0.XVR0.VGA.TOGF)
                                }
                            }

                            If (LEqual (CADL, 0x0F))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x08, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x08, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x04, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x04, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x03, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x09, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x05, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x01, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x0D))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x08, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x04, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x04, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x09, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x05, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x01, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x08, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x0B))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x08, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x08, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x03, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x09, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x09))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x08, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x07))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x02, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x04, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x04, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x03, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x05, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x01, \_SB.PCI0.XVR0.VGA.TOGF)
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x03))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x05))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x04, NSTE)
                                }
                            }

                            Sleep (0x03E8)
                            Store (\_SB.PCI0.XVR0.VGA.TOGF, Local0)
                            Store (Local0, CSTE)
                            If (LEqual (Local0, 0x01))
                            {
                                Store ("LCD", Debug)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x02))
                            {
                                Store ("CRT", Debug)
                                Store (One, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x03))
                            {
                                Store ("Both", Debug)
                                Store (One, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x04))
                            {
                                Store ("TV", Debug)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (One, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x05))
                            {
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (One, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x08))
                            {
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (One, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            If (LEqual (Local0, 0x09))
                            {
                                Store (Zero, \_SB.PCI0.XVR0.VGA.CRTA)
                                Store (One, \_SB.PCI0.XVR0.VGA.LCDA)
                                Store (Zero, \_SB.PCI0.XVR0.VGA.TVAF)
                                Store (One, \_SB.PCI0.XVR0.VGA.HDTV)
                            }

                            Notify (\_SB.PCI0.XVR0.VGA, 0x80)
                        }
                    }
                    Else
                    {
                    }
                }

                Method (VSWU, 0, NotSerialized)
                {
                    Store ("Hot-Keys: ----- _Q0C", Debug)
                    If (LEqual (\_SB.PCI0.UVGA.SWIT, 0x00))
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (0x88, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local0)
                        Release (\_SB.PCI0.PSMX)
                        Store (Local0, CADL)
                        If (LEqual (Local0, 0x10)) {}
                        Else
                        {
                            Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                            Store (0x87, \_SB.PCI0.SMIC)
                            Store (\_SB.PCI0.SMIS, Local1)
                            Release (\_SB.PCI0.PSMX)
                            Store (Local1, PSTE)
                            If (LEqual (Local1, 0x09))
                            {
                                Store (Zero, Local1)
                            }

                            If (LEqual (Local1, 0x05))
                            {
                                Store (0x08, Local1)
                            }

                            Store (Local1, \_SB.PCI0.UVGA.TOGF)
                            Increment (\_SB.PCI0.UVGA.TOGF)
                            While (LNotEqual (And (Local0, \_SB.PCI0.UVGA.TOGF), \_SB.PCI0.UVGA.TOGF))
                            {
                                Increment (\_SB.PCI0.UVGA.TOGF)
                                If (LGreater (\_SB.PCI0.UVGA.TOGF, 0x09))
                                {
                                    Store (One, \_SB.PCI0.UVGA.TOGF)
                                }
                            }

                            If (LEqual (CADL, 0x0F))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x08, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x08, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x04, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x04, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x03, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x09, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x05, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x01, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x0D))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x08, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x04, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x04, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x09, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x05, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x01, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x08, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x0B))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x08, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x08, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x03, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x09, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x09))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x09, NSTE)
                                }

                                If (LEqual (CSTE, 0x08))
                                {
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x09))
                                {
                                    Store (0x08, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x07))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x02, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x04, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x04, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x03, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x05, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x01, \_SB.PCI0.UVGA.TOGF)
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x03))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x03, NSTE)
                                }

                                If (LEqual (CSTE, 0x02))
                                {
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x03))
                                {
                                    Store (0x02, NSTE)
                                }
                            }

                            If (LEqual (CADL, 0x05))
                            {
                                If (LEqual (CSTE, 0x01))
                                {
                                    Store (0x05, NSTE)
                                }

                                If (LEqual (CSTE, 0x04))
                                {
                                    Store (0x01, NSTE)
                                }

                                If (LEqual (CSTE, 0x05))
                                {
                                    Store (0x04, NSTE)
                                }
                            }

                            Sleep (0x03E8)
                            Store (\_SB.PCI0.UVGA.TOGF, Local0)
                            Store (Local0, CSTE)
                            If (LEqual (Local0, 0x01))
                            {
                                Store ("LCD", Debug)
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x02))
                            {
                                Store ("CRT", Debug)
                                Store (One, \_SB.PCI0.UVGA.CRTA)
                                Store (Zero, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x03))
                            {
                                Store ("Both", Debug)
                                Store (One, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x04))
                            {
                                Store ("TV", Debug)
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (Zero, \_SB.PCI0.UVGA.LCDA)
                                Store (One, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x05))
                            {
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (One, \_SB.PCI0.UVGA.TVAF)
                                Store (Zero, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x08))
                            {
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (Zero, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (One, \_SB.PCI0.UVGA.HDTV)
                            }

                            If (LEqual (Local0, 0x09))
                            {
                                Store (Zero, \_SB.PCI0.UVGA.CRTA)
                                Store (One, \_SB.PCI0.UVGA.LCDA)
                                Store (Zero, \_SB.PCI0.UVGA.TVAF)
                                Store (One, \_SB.PCI0.UVGA.HDTV)
                            }

                            Notify (\_SB.PCI0.UVGA, 0x80)
                        }
                    }
                    Else
                    {
                    }
                }

                Method (RSBR, 0, NotSerialized)
                {
                    If (LEqual (OSYS, 0x07D6))
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (Zero, \_SB.PCI0.SMIS)
                        Store (0x8B, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local0)
                        Release (\_SB.PCI0.PSMX)
                    }
                    Else
                    {
                        Acquire (\_SB.PCI0.PSMX, 0xFFFF)
                        Store (One, \_SB.PCI0.SMIS)
                        Store (0x8B, \_SB.PCI0.SMIC)
                        Store (\_SB.PCI0.SMIS, Local0)
                        Release (\_SB.PCI0.PSMX)
                    }
                }

                Method (PRTH, 0, NotSerialized)
                {
                    Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                    If (\_SB.PCI0.EC0.ACIN)
                    {
                        Acquire (M723, 0xFFFF)
                        Store (ACBN, BRNS)
                        Release (M723)
                    }
                    Else
                    {
                        Acquire (M723, 0xFFFF)
                        Store (BABN, BRNS)
                        Release (M723)
                    }

                    Release (\_SB.PCI0.EC0.MUT0)
                }

                Method (SMRD, 4, NotSerialized)
                {
                    If (LNot (ECON))
                    {
                        Return (0xFF)
                    }

                    If (LNotEqual (Arg0, 0x07))
                    {
                        If (LNotEqual (Arg0, 0x09))
                        {
                            If (LNotEqual (Arg0, 0x0B))
                            {
                                Return (0x19)
                            }
                        }
                    }

                    Acquire (MUT0, 0xFFFF)
                    Store (0x04, Local0)
                    While (LGreater (Local0, 0x01))
                    {
                        And (SMST, 0x40, SMST)
                        Store (Arg2, SMCM)
                        Store (Arg1, SMAD)
                        Store (Arg0, SMPR)
                        Store (0x00, Local3)
                        While (LNot (And (SMST, 0xBF, Local1)))
                        {
                            Sleep (0x02)
                            Increment (Local3)
                            If (LEqual (Local3, 0x32))
                            {
                                And (SMST, 0x40, SMST)
                                Store (Arg2, SMCM)
                                Store (Arg1, SMAD)
                                Store (Arg0, SMPR)
                                Store (0x00, Local3)
                            }
                        }

                        If (LEqual (Local1, 0x80))
                        {
                            Store (0x00, Local0)
                        }
                        Else
                        {
                            Decrement (Local0)
                        }
                    }

                    If (Local0)
                    {
                        Store (And (Local1, 0x1F), Local0)
                    }
                    Else
                    {
                        If (LEqual (Arg0, 0x07))
                        {
                            Store (SMB0, Arg3)
                        }

                        If (LEqual (Arg0, 0x09))
                        {
                            Store (SMW0, Arg3)
                        }

                        If (LEqual (Arg0, 0x0B))
                        {
                            Store (BCNT, Local3)
                            ShiftRight (0x0100, 0x03, Local2)
                            If (LGreater (Local3, Local2))
                            {
                                Store (Local2, Local3)
                            }

                            If (LLess (Local3, 0x09))
                            {
                                Store (FLD0, Local2)
                            }
                            Else
                            {
                                If (LLess (Local3, 0x11))
                                {
                                    Store (FLD1, Local2)
                                }
                                Else
                                {
                                    If (LLess (Local3, 0x19))
                                    {
                                        Store (FLD2, Local2)
                                    }
                                    Else
                                    {
                                        Store (FLD3, Local2)
                                    }
                                }
                            }

                            Increment (Local3)
                            Store (Buffer (Local3) {}, Local4)
                            Decrement (Local3)
                            Store (Zero, Local5)
                            While (LGreater (Local3, Local5))
                            {
                                GBFE (Local2, Local5, RefOf (Local6))
                                PBFE (Local4, Local5, Local6)
                                Increment (Local5)
                            }

                            PBFE (Local4, Local5, 0x00)
                            Store (Local4, Arg3)
                        }
                    }

                    Release (MUT0)
                    Return (Local0)
                }

                Method (Z00R, 0, Serialized)
                {
                    If (ECON)
                    {
                        Store (SFHK, Local0)
                    }

                    Return (Local0)
                }

                Method (Z00S, 1, Serialized)
                {
                    If (ECON)
                    {
                        Store (Arg0, SFHK)
                    }
                }
            }

            Device (SMB0)
            {
                Name (_ADR, 0x000A0001)
                OperationRegion (SMCF, PCI_Config, 0x48, 0x04)
                Field (SMCF, AnyAcc, NoLock, Preserve)
                {
                    SB48,   4
                }

                OperationRegion (SBA0, PCI_Config, 0x20, 0x04)
                Field (SBA0, AnyAcc, NoLock, Preserve)
                {
                    SB20,   16
                }

                OperationRegion (SBA1, PCI_Config, 0x24, 0x04)
                Field (SBA1, AnyAcc, NoLock, Preserve)
                {
                    SB24,   16
                }

                OperationRegion (SBA2, PCI_Config, 0x7C, 0x04)
                Field (SBA2, AnyAcc, NoLock, Preserve)
                {
                    SB7C,   16
                }

                OperationRegion (P60, PCI_Config, 0x60, 0x02)
                Field (P60, AnyAcc, NoLock, Preserve)
                {
                    PMBR,   16
                }

                OperationRegion (P64, PCI_Config, 0x64, 0x02)
                Field (P64, AnyAcc, NoLock, Preserve)
                {
                    NVSB,   16
                }

                OperationRegion (P68, PCI_Config, 0x68, 0x02)
                Field (P68, AnyAcc, NoLock, Preserve)
                {
                    ANLG,   16
                }
            }

            Device (USB0)
            {
                Name (_ADR, 0x000B0000)
                Method (_S1D, 0, NotSerialized)
                {
                    Return (0x01)
                }

                Method (_S3D, 0, NotSerialized)
                {
                    Return (0x02)
                }

                Device (RH00)
                {
                    Name (_ADR, 0x00)
                    Device (PRT0)
                    {
                        Name (_ADR, 0x00)
                    }

                    Device (PRT1)
                    {
                        Name (_ADR, 0x01)
                    }

                    Device (PRT2)
                    {
                        Name (_ADR, 0x02)
                    }

                    Device (PRT3)
                    {
                        Name (_ADR, 0x03)
                    }

                    Device (PRT4)
                    {
                        Name (_ADR, 0x04)
                    }

                    Device (PRT5)
                    {
                        Name (_ADR, 0x05)
                        Name (_EJD, "_SB.PCI0.XVR2.X2S0")
                    }

                    Device (PRT6)
                    {
                        Name (_ADR, 0x06)
                    }

                    Device (PRT7)
                    {
                        Name (_ADR, 0x07)
                    }
                }
            }

            Device (USB2)
            {
                Name (_ADR, 0x000B0001)
            }

            Device (MAC0)
            {
                Name (_ADR, 0x00140000)
                Name (_PRW, Package (0x02)
                {
                    0x0B, 
                    0x05
                })
            }

            Device (AZA0)
            {
                Name (_ADR, 0x00100001)
            }

            Device (P2P0)
            {
                Name (_ADR, 0x00100000)
                Name (_UID, 0x02)
                OperationRegion (A080, PCI_Config, 0x19, 0x01)
                Field (A080, ByteAcc, NoLock, Preserve)
                {
                    SECB,   8
                }

                Method (_BBN, 0, NotSerialized)
                {
                    Return (SECB)
                }

                Method (_STA, 0, NotSerialized)
                {
                    Return (0x0F)
                }

                Name (_PRT, Package (0x02)
                {
                    Package (0x04)
                    {
                        0x0005FFFF, 
                        0x00, 
                        \_SB.PCI0.LNK1, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0x0005FFFF, 
                        0x01, 
                        \_SB.PCI0.LNK2, 
                        0x00
                    }
                })
            }

            Name (NATA, Package (0x01)
            {
                0x000D0000
            })
            Scope (\_SB.PCI0)
            {
                Device (NVRB)
                {
                    Name (_HID, "NVRAIDBUS")
                    Name (FNVR, 0xFF)
                    Method (_DIS, 0, NotSerialized)
                    {
                        Store (0x00, FNVR)
                    }

                    Method (_STA, 0, NotSerialized)
                    {
                        If (LEqual (\_SB.R_ST, 0x01))
                        {
                            If (LEqual (FNVR, 0xFF))
                            {
                                Return (0x0F)
                            }
                            Else
                            {
                                Return (0x0D)
                            }
                        }
                        Else
                        {
                            Return (0x00)
                        }
                    }

                    Name (_CRS, ResourceTemplate ()
                    {
                        IO (Decode16,
                            0x04D2,             // Range Minimum
                            0x04D2,             // Range Maximum
                            0x01,               // Alignment
                            0x01,               // Length
                            )
                    })
                }
            }

            Device (IDE0)
            {
                Name (SID4, 0x00)
                Name (SID5, 0x00)
                Name (SFLG, 0x00)
                Name (SID0, 0x00)
                Name (SID1, 0x00)
                Name (SID2, 0x00)
                Name (SID3, 0x00)
                Name (_ADR, 0x000D0000)
                OperationRegion (A090, PCI_Config, 0x50, 0x18)
                Field (A090, DWordAcc, NoLock, Preserve)
                {
                    ID20,   16, 
                            Offset (0x08), 
                    IDTS,   16, 
                    IDTP,   16, 
                    ID22,   32, 
                    UMSS,   16, 
                    UMSP,   16
                }

                Name (IDEP, Buffer (0x14) {})
                Name (IDES, Buffer (0x14) {})
                Method (GTM, 1, NotSerialized)
                {
                    If (LEqual (Arg0, 0x00))
                    {
                        Store (IDTP, Local0)
                        Store (UMSP, Local1)
                        Store (IDEP, Local2)
                    }
                    Else
                    {
                        Store (IDTS, Local0)
                        Store (UMSS, Local1)
                        Store (IDES, Local2)
                    }

                    CreateDWordField (Local2, 0x00, PIO0)
                    CreateDWordField (Local2, 0x04, DMA0)
                    CreateDWordField (Local2, 0x08, PIO1)
                    CreateDWordField (Local2, 0x0C, DMA1)
                    CreateDWordField (Local2, 0x10, FLAG)
                    Store (0x10, FLAG)
                    And (Local0, 0x0F00, Local3)
                    And (Local0, 0xF000, Local4)
                    ShiftRight (Local3, 0x08, Local3)
                    ShiftRight (Local4, 0x0C, Local4)
                    Add (Local3, Local4, Local3)
                    Multiply (Add (Local3, 0x02), 0x1E, PIO0)
                    If (LLessEqual (PIO0, 0xB4))
                    {
                        Or (FLAG, 0x02, FLAG)
                    }

                    If (And (Local1, 0x4000))
                    {
                        Or (FLAG, 0x01, FLAG)
                        And (Local1, 0x0700, Local3)
                        ShiftRight (Local3, 0x08, Local3)
                        Store (U2T (Local3), DMA0)
                    }
                    Else
                    {
                        Store (PIO0, DMA0)
                    }

                    And (Local0, 0x0F, Local3)
                    And (Local0, 0xF0, Local4)
                    ShiftRight (Local4, 0x04, Local4)
                    Add (Local3, Local4, Local3)
                    Multiply (Add (Local3, 0x02), 0x1E, PIO1)
                    If (LLessEqual (PIO1, 0xB4))
                    {
                        Or (FLAG, 0x08, FLAG)
                    }

                    If (And (Local1, 0x40))
                    {
                        Or (FLAG, 0x04, FLAG)
                        And (Local1, 0x07, Local3)
                        Store (U2T (Local3), DMA1)
                    }
                    Else
                    {
                        Store (PIO1, DMA1)
                    }

                    If (LEqual (Arg0, 0x00))
                    {
                        Store (Local2, IDEP)
                        Return (IDEP)
                    }
                    Else
                    {
                        Store (Local2, IDES)
                        Return (IDES)
                    }
                }

                Method (U2T, 1, NotSerialized)
                {
                    If (LEqual (Arg0, 0x00))
                    {
                        Return (0x3C)
                    }

                    If (LEqual (Arg0, 0x01))
                    {
                        Return (0x5A)
                    }

                    If (LEqual (Arg0, 0x02))
                    {
                        Return (0x78)
                    }

                    If (LEqual (Arg0, 0x03))
                    {
                        Return (0x96)
                    }

                    If (LEqual (Arg0, 0x04))
                    {
                        Return (0x2D)
                    }

                    If (LEqual (Arg0, 0x05))
                    {
                        Return (0x1E)
                    }

                    If (LEqual (Arg0, 0x06))
                    {
                        Return (0x14)
                    }

                    Return (0x0F)
                }

                Method (T2U, 1, NotSerialized)
                {
                    If (LGreater (Arg0, 0x78))
                    {
                        Return (0x03)
                    }

                    If (LGreater (Arg0, 0x5A))
                    {
                        Return (0x02)
                    }

                    If (LGreater (Arg0, 0x3C))
                    {
                        Return (0x01)
                    }

                    If (LGreater (Arg0, 0x2D))
                    {
                        Return (0x00)
                    }

                    If (LGreater (Arg0, 0x1E))
                    {
                        Return (0x04)
                    }

                    If (LGreater (Arg0, 0x14))
                    {
                        Return (0x05)
                    }

                    If (LGreater (Arg0, 0x0F))
                    {
                        Return (0x06)
                    }

                    Return (0x07)
                }

                Method (T2D, 1, NotSerialized)
                {
                    If (LGreater (Arg0, 0x01E0))
                    {
                        Return (0xA8)
                    }

                    If (LGreater (Arg0, 0x0186))
                    {
                        Return (0x77)
                    }

                    If (LGreater (Arg0, 0xF0))
                    {
                        Return (0x47)
                    }

                    If (LGreater (Arg0, 0xB4))
                    {
                        Return (0x33)
                    }

                    If (LGreater (Arg0, 0x96))
                    {
                        Return (0x22)
                    }

                    If (LGreater (Arg0, 0x78))
                    {
                        Return (0x21)
                    }

                    Return (0x20)
                }

                Method (STM, 4, NotSerialized)
                {
                    If (SX)
                    {
                        Store (SID0, ID20)
                        Store (SID1, IDTS)
                        Store (SID2, IDTP)
                        Store (SID3, ID22)
                        Store (SID4, UMSS)
                        Store (SID5, UMSP)
                    }
                    Else
                    {
                        Store (ID20, SID0)
                        Store (IDTS, SID1)
                        Store (IDTP, SID2)
                        Store (ID22, SID3)
                        Store (UMSS, SID4)
                        Store (UMSP, SID5)
                    }

                    Store (0x00, SX)
                    CreateDWordField (Arg0, 0x00, PIO0)
                    CreateDWordField (Arg0, 0x04, DMA0)
                    CreateDWordField (Arg0, 0x08, PIO1)
                    CreateDWordField (Arg0, 0x0C, DMA1)
                    CreateDWordField (Arg0, 0x10, FLAG)
                    If (LEqual (Arg3, 0x00))
                    {
                        Store (SID2, Local0)
                        Store (SID5, Local1)
                    }
                    Else
                    {
                        Store (SID1, Local0)
                        Store (SID4, Local1)
                    }

                    If (LNotEqual (PIO0, 0xFFFFFFFF))
                    {
                        And (Local0, 0xFF, Local0)
                        ShiftLeft (T2D (PIO0), 0x08, Local2)
                        Or (Local0, Local2, Local0)
                    }

                    If (LNotEqual (PIO1, 0xFFFFFFFF))
                    {
                        And (Local0, 0xFF00, Local0)
                        Or (Local0, T2D (PIO1), Local0)
                    }

                    If (And (FLAG, 0x01))
                    {
                        And (Local1, 0xFF, Local1)
                        ShiftLeft (T2U (DMA0), 0x08, Local2)
                        Or (0xC000, Local2, Local2)
                        Or (Local2, Local1, Local1)
                    }
                    Else
                    {
                        If (LNotEqual (DMA0, 0xFFFFFFFF))
                        {
                            And (Local0, 0xFF, Local0)
                            ShiftLeft (T2D (DMA0), 0x08, Local2)
                            Or (Local0, Local2, Local0)
                        }
                    }

                    If (And (FLAG, 0x04))
                    {
                        And (Local1, 0xFF00, Local1)
                        Or (0xC0, T2U (DMA1), Local2)
                        Or (Local2, Local1, Local1)
                    }
                    Else
                    {
                        If (LNotEqual (DMA1, 0xFFFFFFFF))
                        {
                            And (Local0, 0xFF00, Local0)
                            Or (Local0, T2D (DMA1), Local0)
                        }
                    }

                    If (LEqual (Arg3, 0x00))
                    {
                        Store (Local0, IDTP)
                        Store (Local1, UMSP)
                    }
                    Else
                    {
                        Store (Local0, IDTS)
                        Store (Local1, UMSS)
                    }
                }

                Method (GTF, 2, NotSerialized)
                {
                    Store (Buffer (0x07)
                        {
                            0x03, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xEF
                        }, Local0)
                    CreateByteField (Local0, 0x01, MODE)
                    CreateByteField (Local0, 0x05, DRIV)
                    Store (Arg1, DRIV)
                    If (LEqual (Arg0, 0x00))
                    {
                        Store (IDEP, Local1)
                    }
                    Else
                    {
                        Store (IDES, Local1)
                    }

                    CreateDWordField (Local1, 0x00, PIO0)
                    CreateDWordField (Local1, 0x04, DMA0)
                    CreateDWordField (Local1, 0x08, PIO1)
                    CreateDWordField (Local1, 0x0C, DMA1)
                    CreateDWordField (Local1, 0x10, FLGX)
                    If (LEqual (Arg1, 0xA0))
                    {
                        Store (PIO0, Local2)
                        Store (DMA0, Local3)
                        And (FLGX, 0x01, FLGX)
                    }
                    Else
                    {
                        Store (PIO1, Local2)
                        Store (DMA1, Local3)
                        And (FLGX, 0x04, FLGX)
                    }

                    Store (FLGX, Local1)
                    If (LGreater (Local2, 0x0186))
                    {
                        Store (0x00, Local2)
                    }
                    Else
                    {
                        If (LGreater (Local2, 0xF0))
                        {
                            Store (0x01, Local2)
                        }
                        Else
                        {
                            If (LGreater (Local2, 0xB4))
                            {
                                Store (0x02, Local2)
                            }
                            Else
                            {
                                If (LGreater (Local2, 0x78))
                                {
                                    Store (0x03, Local2)
                                }
                                Else
                                {
                                    Store (0x04, Local2)
                                }
                            }
                        }
                    }

                    Or (0x08, Local2, MODE)
                    Store (Local0, Local2)
                    If (FLGX)
                    {
                        If (LGreater (Local3, 0x5A))
                        {
                            Store (0x00, Local3)
                        }
                        Else
                        {
                            If (LGreater (Local3, 0x3C))
                            {
                                Store (0x01, Local3)
                            }
                            Else
                            {
                                If (LGreater (Local3, 0x2D))
                                {
                                    Store (0x02, Local3)
                                }
                                Else
                                {
                                    If (LGreater (Local3, 0x1E))
                                    {
                                        Store (0x03, Local3)
                                    }
                                    Else
                                    {
                                        If (LGreater (Local3, 0x14))
                                        {
                                            Store (0x04, Local3)
                                        }
                                        Else
                                        {
                                            If (LGreater (Local3, 0x0F))
                                            {
                                                Store (0x05, Local3)
                                            }
                                            Else
                                            {
                                                Store (0x06, Local3)
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        Or (0x40, Local3, MODE)
                    }
                    Else
                    {
                        If (LEqual (Local3, 0xFFFFFFFF))
                        {
                            Return (Local0)
                        }
                        Else
                        {
                            If (LGreater (Local3, 0x96))
                            {
                                Store (0x00, Local3)
                            }
                            Else
                            {
                                If (LGreater (Local3, 0x78))
                                {
                                    Store (0x01, Local3)
                                }
                                Else
                                {
                                    Store (0x02, Local3)
                                }
                            }

                            Or (0x20, Local3, MODE)
                        }
                    }

                    Concatenate (Local0, Local2, Local1)
                    Return (Local1)
                }

                Device (PRI0)
                {
                    Name (_ADR, 0x00)
                    Method (_GTM, 0, NotSerialized)
                    {
                        Return (GTM (0x00))
                    }

                    Method (_STM, 3, NotSerialized)
                    {
                        STM (Arg0, Arg1, Arg2, 0x00)
                    }

                    Device (MAST)
                    {
                        Name (_ADR, 0x00)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Return (GTF (0x00, 0xA0))
                        }
                    }

                    Device (SLAV)
                    {
                        Name (_ADR, 0x01)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Return (GTF (0x00, 0xB0))
                        }
                    }
                }

                Device (SEC0)
                {
                    Name (_ADR, 0x01)
                    Method (_GTM, 0, NotSerialized)
                    {
                        Return (GTM (0x01))
                    }

                    Method (_STM, 3, NotSerialized)
                    {
                        STM (Arg0, Arg1, Arg2, 0x01)
                    }

                    Device (MAST)
                    {
                        Name (_ADR, 0x00)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Return (GTF (0x01, 0xA0))
                        }
                    }

                    Device (SLAV)
                    {
                        Name (_ADR, 0x01)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Return (GTF (0x01, 0xB0))
                        }
                    }
                }

                Method (DRMP, 0, NotSerialized)
                {
                    Return (\_SB.R_P0)
                }
            }

            Device (SAT1)
            {
                Name (_ADR, 0x000F0000)
                Device (PRI0)
                {
                    Name (_ADR, 0x00)
                    Name (SPTM, Buffer (0x14)
                    {
                        /* 0000 */    0x78, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 
                        /* 0008 */    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                        /* 0010 */    0x13, 0x00, 0x00, 0x00
                    })
                    Method (_GTM, 0, NotSerialized)
                    {
                        Return (SPTM)
                    }

                    Method (_STM, 3, NotSerialized)
                    {
                        Store (Arg0, SPTM)
                    }

                    Device (MAST)
                    {
                        Name (_ADR, 0x00)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Store (Buffer (0x07)
                                {
                                    0x03, 0x46, 0x00, 0x00, 0x00, 0xA0, 0xEF
                                }, Local0)
                            Return (Local0)
                        }
                    }
                }

                Device (SEC0)
                {
                    Name (_ADR, 0x01)
                    Name (SSTM, Buffer (0x14)
                    {
                        /* 0000 */    0x78, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 
                        /* 0008 */    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                        /* 0010 */    0x13, 0x00, 0x00, 0x00
                    })
                    Method (_GTM, 0, NotSerialized)
                    {
                        Return (SSTM)
                    }

                    Method (_STM, 3, NotSerialized)
                    {
                        Store (Arg0, SSTM)
                    }

                    Device (MAST)
                    {
                        Name (_ADR, 0x00)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Store (Buffer (0x07)
                                {
                                    0x03, 0x46, 0x00, 0x00, 0x00, 0xA0, 0xEF
                                }, Local0)
                            Return (Local0)
                        }
                    }
                }

                Method (DRMP, 0, NotSerialized)
                {
                    Return (\_SB.R_S0)
                }
            }

            Device (SAT0)
            {
                Name (_ADR, 0x000E0000)
                Device (PRI0)
                {
                    Name (_ADR, 0x00)
                    Name (SPTM, Buffer (0x14)
                    {
                        /* 0000 */    0x78, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 
                        /* 0008 */    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                        /* 0010 */    0x13, 0x00, 0x00, 0x00
                    })
                    Method (_GTM, 0, NotSerialized)
                    {
                        Return (SPTM)
                    }

                    Method (_STM, 3, NotSerialized)
                    {
                        Store (Arg0, SPTM)
                    }

                    Device (MAST)
                    {
                        Name (_ADR, 0x00)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Store (Buffer (0x07)
                                {
                                    0x03, 0x46, 0x00, 0x00, 0x00, 0xA0, 0xEF
                                }, Local0)
                            Return (Local0)
                        }
                    }
                }

                Device (SEC0)
                {
                    Name (_ADR, 0x01)
                    Name (SSTM, Buffer (0x14)
                    {
                        /* 0000 */    0x78, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 
                        /* 0008 */    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
                        /* 0010 */    0x13, 0x00, 0x00, 0x00
                    })
                    Method (_GTM, 0, NotSerialized)
                    {
                        Return (SSTM)
                    }

                    Method (_STM, 3, NotSerialized)
                    {
                        Store (Arg0, SSTM)
                    }

                    Device (MAST)
                    {
                        Name (_ADR, 0x00)
                        Method (_GTF, 0, NotSerialized)
                        {
                            Store (Buffer (0x07)
                                {
                                    0x03, 0x46, 0x00, 0x00, 0x00, 0xA0, 0xEF
                                }, Local0)
                            Return (Local0)
                        }
                    }
                }

                Method (DRMP, 0, NotSerialized)
                {
                    Return (\_SB.R_S1)
                }
            }

            Device (UVGA)
            {
                Name (_ADR, 0x00050000)
                Name (SWIT, 0x01)
                Name (CRTA, 0x01)
                Name (LCDA, 0x01)
                Name (TVAF, 0x00)
                Name (HDTV, 0x00)
                Name (TOGF, 0x00)
                Name (BRIP, Package (0x0D)
                {
                    0x5C, 
                    0x2A, 
                    0x14, 
                    0x18, 
                    0x1C, 
                    0x21, 
                    0x26, 
                    0x2A, 
                    0x30, 
                    0x38, 
                    0x42, 
                    0x4E, 
                    0x5C
                })
                Name (Z00U, Package (0x0D)
                {
                    0x64, 
                    0x2A, 
                    0x14, 
                    0x18, 
                    0x1C, 
                    0x21, 
                    0x26, 
                    0x2A, 
                    0x34, 
                    0x3D, 
                    0x48, 
                    0x55, 
                    0x64
                })
                Method (_DOS, 1, NotSerialized)
                {
                    Store ("VGA --_DOS Arg0", Debug)
                    Store (Arg0, SWIT)
                }

                Method (_DOD, 0, NotSerialized)
                {
                    Store ("VGA --_DOD", Debug)
                    Return (Package (0x04)
                    {
                        0x00010100, 
                        0x00010118, 
                        0x00010200, 
                        0x00010121
                    })
                }

                Method (_PS0, 0, NotSerialized)
                {
                    Store ("VGA_PS0", Debug)
                }

                Method (_PS2, 0, NotSerialized)
                {
                    Store ("VGA_PS2", Debug)
                }

                Method (_PS3, 0, NotSerialized)
                {
                    Store ("VGA_PS3", Debug)
                }

                Device (CRT)
                {
                    Name (_ADR, 0x0100)
                    Method (_DCS, 0, NotSerialized)
                    {
                        Store ("CRT --_DCS", Debug)
                        If (CRTA)
                        {
                            Return (0x1F)
                        }
                        Else
                        {
                            Return (0x1D)
                        }
                    }

                    Method (_DGS, 0, NotSerialized)
                    {
                        Store ("CRT --_DGS", Debug)
                        Store (CRTA, Local0)
                        If (CRTA)
                        {
                            Return (0x01)
                        }
                        Else
                        {
                            Return (0x00)
                        }
                    }

                    Method (_DSS, 1, NotSerialized)
                    {
                        Store ("CRT --_DSS", Debug)
                        Store (Arg0, Debug)
                    }
                }

                Device (LCD)
                {
                    Name (_ADR, 0x0118)
                    Method (_DCS, 0, NotSerialized)
                    {
                        Store ("LCD --_DCS", Debug)
                        If (LCDA)
                        {
                            Return (0x1F)
                        }
                        Else
                        {
                            Return (0x1D)
                        }
                    }

                    Method (_DGS, 0, NotSerialized)
                    {
                        Store ("LCD --_DGS", Debug)
                        Store (LCDA, Local0)
                        If (LCDA)
                        {
                            Return (0x01)
                        }
                        Else
                        {
                            Return (0x00)
                        }
                    }

                    Method (_DSS, 1, NotSerialized)
                    {
                        Store ("LCD --_DSS", Debug)
                        Store (Arg0, Debug)
                    }

                    Method (_BCL, 0, NotSerialized)
                    {
                        If (LEqual (PTPE, 0x02))
                        {
                            Return (Z00U)
                        }
                        Else
                        {
                            Return (BRIP)
                        }
                    }

                    Method (_BCM, 1, NotSerialized)
                    {
                        Store (Arg0, Local0)
                        Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                        Store (Local0, \_SB.PCI0.EC0.BRIC)
                        Store (\_SB.PCI0.EC0.ACIN, Local1)
                        Release (\_SB.PCI0.EC0.MUT0)
                        Store (_BCL (), Local2)
                        Store (0x02, Local3)
                        While (LLess (Local3, 0x0D))
                        {
                            If (LEqual (Local0, DerefOf (Index (Local2, Local3))))
                            {
                                If (Local1)
                                {
                                    Subtract (Local3, 0x02, ACBR)
                                }
                                Else
                                {
                                    Subtract (Local3, 0x02, DCBR)
                                }

                                Subtract (Local3, 0x02, CCBR)
                                Store (0x0F, Local3)
                            }

                            Increment (Local3)
                        }
                    }

                    Method (_BQC, 0, NotSerialized)
                    {
                        If (ECON)
                        {
                            Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                            Store (\_SB.PCI0.EC0.BRIC, Local0)
                            Release (\_SB.PCI0.EC0.MUT0)
                            Return (Local0)
                        }
                        Else
                        {
                            Store (_BCL (), Local1)
                            Return (DerefOf (Index (Local1, CCBR)))
                        }
                    }
                }

                Device (TV)
                {
                    Name (_ADR, 0x0200)
                    Method (_DCS, 0, NotSerialized)
                    {
                        Store ("TV --_DCS", Debug)
                        If (TVAF)
                        {
                            Return (0x1F)
                        }
                        Else
                        {
                            Return (0x1D)
                        }
                    }

                    Method (_DGS, 0, NotSerialized)
                    {
                        Store ("TV --_DGS", Debug)
                        Store (TVAF, Local0)
                        If (TVAF)
                        {
                            Return (0x01)
                        }
                        Else
                        {
                            Return (0x00)
                        }
                    }

                    Method (_DSS, 1, NotSerialized)
                    {
                        Store ("TV --_DSS", Debug)
                        Store (Arg0, Debug)
                    }
                }

                Device (HDMI)
                {
                    Name (_ADR, 0x0121)
                    Method (_DCS, 0, NotSerialized)
                    {
                        Store ("HDMI TV --_DCS", Debug)
                        If (HDTV)
                        {
                            Return (0x1F)
                        }
                        Else
                        {
                            Return (0x1D)
                        }
                    }

                    Method (_DGS, 0, NotSerialized)
                    {
                        Store ("HDMI TV --_DGS", Debug)
                        Store (HDTV, Local0)
                        If (HDTV)
                        {
                            Return (0x01)
                        }
                        Else
                        {
                            Return (0x00)
                        }
                    }

                    Method (_DSS, 1, NotSerialized)
                    {
                        Store ("HDMI TV --_DSS", Debug)
                        Store (Arg0, Debug)
                    }
                }
            }

            Device (XVR0)
            {
                Name (_ADR, 0x00040000)
                Name (_UID, 0x03)
                OperationRegion (A1E0, PCI_Config, 0x19, 0x01)
                Field (A1E0, ByteAcc, NoLock, Preserve)
                {
                    SECB,   8
                }

                Method (_BBN, 0, NotSerialized)
                {
                    Return (SECB)
                }

                Method (_STA, 0, NotSerialized)
                {
                    Return (0x0F)
                }

                Name (_PRT, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        0x00, 
                        \_SB.PCI0.LK1E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x01, 
                        \_SB.PCI0.LK2E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        \_SB.PCI0.LK3E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        \_SB.PCI0.LK4E, 
                        0x00
                    }
                })
                Device (VGA)
                {
                    Name (_ADR, 0x00)
                    Name (SWIT, 0x01)
                    Name (CRTA, 0x01)
                    Name (LCDA, 0x01)
                    Name (TVAF, 0x00)
                    Name (HDTV, 0x00)
                    Name (TOGF, 0x00)
                    Name (BRIP, Package (0x0D)
                    {
                        0x5C, 
                        0x2A, 
                        0x14, 
                        0x18, 
                        0x1C, 
                        0x21, 
                        0x26, 
                        0x2A, 
                        0x30, 
                        0x38, 
                        0x42, 
                        0x4E, 
                        0x5C
                    })
                    Name (Z00U, Package (0x0D)
                    {
                        0x64, 
                        0x2A, 
                        0x14, 
                        0x18, 
                        0x1C, 
                        0x21, 
                        0x26, 
                        0x2A, 
                        0x34, 
                        0x3D, 
                        0x48, 
                        0x55, 
                        0x64
                    })
                    Method (_DOS, 1, NotSerialized)
                    {
                        Store ("VGA --_DOS Arg0", Debug)
                        Store (Arg0, SWIT)
                    }

                    Method (_DOD, 0, NotSerialized)
                    {
                        Store ("VGA --_DOD", Debug)
                        Return (Package (0x04)
                        {
                            0x00010100, 
                            0x00010118, 
                            0x00010200, 
                            0x00010121
                        })
                    }

                    Method (_PS0, 0, NotSerialized)
                    {
                        Store ("VGA_PS0", Debug)
                    }

                    Method (_PS2, 0, NotSerialized)
                    {
                        Store ("VGA_PS2", Debug)
                    }

                    Method (_PS3, 0, NotSerialized)
                    {
                        Store ("VGA_PS3", Debug)
                    }

                    Device (CRT)
                    {
                        Name (_ADR, 0x0100)
                        Method (_DCS, 0, NotSerialized)
                        {
                            Store ("CRT --_DCS", Debug)
                            If (CRTA)
                            {
                                Return (0x1F)
                            }
                            Else
                            {
                                Return (0x1D)
                            }
                        }

                        Method (_DGS, 0, NotSerialized)
                        {
                            Store ("CRT --_DGS", Debug)
                            Store (CRTA, Local0)
                            If (CRTA)
                            {
                                Return (0x01)
                            }
                            Else
                            {
                                Return (0x00)
                            }
                        }

                        Method (_DSS, 1, NotSerialized)
                        {
                            Store ("CRT --_DSS", Debug)
                            Store (Arg0, Debug)
                        }
                    }

                    Device (LCD)
                    {
                        Name (_ADR, 0x0118)
                        Method (_DCS, 0, NotSerialized)
                        {
                            Store ("LCD --_DCS", Debug)
                            If (LCDA)
                            {
                                Return (0x1F)
                            }
                            Else
                            {
                                Return (0x1D)
                            }
                        }

                        Method (_DGS, 0, NotSerialized)
                        {
                            Store ("LCD --_DGS", Debug)
                            Store (LCDA, Local0)
                            If (LCDA)
                            {
                                Return (0x01)
                            }
                            Else
                            {
                                Return (0x00)
                            }
                        }

                        Method (_DSS, 1, NotSerialized)
                        {
                            Store ("LCD --_DSS", Debug)
                            Store (Arg0, Debug)
                        }

                        Method (_BCL, 0, NotSerialized)
                        {
                            If (LEqual (PTPE, 0x02))
                            {
                                Return (Z00U)
                            }
                            Else
                            {
                                Return (BRIP)
                            }
                        }

                        Method (_BCM, 1, NotSerialized)
                        {
                            Store (Arg0, Local0)
                            Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                            Store (Local0, \_SB.PCI0.EC0.BRIC)
                            Store (\_SB.PCI0.EC0.ACIN, Local1)
                            Release (\_SB.PCI0.EC0.MUT0)
                            Store (_BCL (), Local2)
                            Store (0x02, Local3)
                            While (LLess (Local3, 0x0D))
                            {
                                If (LEqual (Local0, DerefOf (Index (Local2, Local3))))
                                {
                                    If (Local1)
                                    {
                                        Subtract (Local3, 0x02, ACBR)
                                    }
                                    Else
                                    {
                                        Subtract (Local3, 0x02, DCBR)
                                    }

                                    Subtract (Local3, 0x02, CCBR)
                                    Store (0x0F, Local3)
                                }

                                Increment (Local3)
                            }
                        }

                        Method (_BQC, 0, NotSerialized)
                        {
                            If (ECON)
                            {
                                Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                                Store (\_SB.PCI0.EC0.BRIC, Local0)
                                Release (\_SB.PCI0.EC0.MUT0)
                                Return (Local0)
                            }
                            Else
                            {
                                Store (_BCL (), Local1)
                                Return (DerefOf (Index (Local1, CCBR)))
                            }
                        }
                    }

                    Device (TV)
                    {
                        Name (_ADR, 0x0200)
                        Method (_DCS, 0, NotSerialized)
                        {
                            Store ("TV --_DCS", Debug)
                            If (TVAF)
                            {
                                Return (0x1F)
                            }
                            Else
                            {
                                Return (0x1D)
                            }
                        }

                        Method (_DGS, 0, NotSerialized)
                        {
                            Store ("TV --_DGS", Debug)
                            Store (TVAF, Local0)
                            If (TVAF)
                            {
                                Return (0x01)
                            }
                            Else
                            {
                                Return (0x00)
                            }
                        }

                        Method (_DSS, 1, NotSerialized)
                        {
                            Store ("TV --_DSS", Debug)
                            Store (Arg0, Debug)
                        }
                    }

                    Device (HDMI)
                    {
                        Name (_ADR, 0x0121)
                        Method (_DCS, 0, NotSerialized)
                        {
                            Store ("HDMI TV --_DCS", Debug)
                            If (HDTV)
                            {
                                Return (0x1F)
                            }
                            Else
                            {
                                Return (0x1D)
                            }
                        }

                        Method (_DGS, 0, NotSerialized)
                        {
                            Store ("HDMI TV --_DGS", Debug)
                            Store (HDTV, Local0)
                            If (HDTV)
                            {
                                Return (0x01)
                            }
                            Else
                            {
                                Return (0x00)
                            }
                        }

                        Method (_DSS, 1, NotSerialized)
                        {
                            Store ("HDMI TV --_DSS", Debug)
                            Store (Arg0, Debug)
                        }
                    }
                }
            }

            Device (XVR1)
            {
                Name (_ADR, 0x00030000)
                Name (_UID, 0x04)
                OperationRegion (A1E1, PCI_Config, 0x19, 0x01)
                Field (A1E1, ByteAcc, NoLock, Preserve)
                {
                    SECB,   8
                }

                Method (_BBN, 0, NotSerialized)
                {
                    Return (SECB)
                }

                Method (_STA, 0, NotSerialized)
                {
                    Return (0x0F)
                }

                Name (_PRT, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        0x00, 
                        \_SB.PCI0.LK4E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x01, 
                        \_SB.PCI0.LK1E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        \_SB.PCI0.LK2E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        \_SB.PCI0.LK3E, 
                        0x00
                    }
                })
                Device (X1S0)
                {
                    Name (_ADR, 0x00)
                }
            }

            Device (XVR2)
            {
                Name (_ADR, 0x00020000)
                Name (_HPP, Package (0x04)
                {
                    0x10, 
                    0x40, 
                    0x01, 
                    0x00
                })
                Name (_UID, 0x05)
                OperationRegion (A1E2, PCI_Config, 0x19, 0x01)
                Field (A1E2, ByteAcc, NoLock, Preserve)
                {
                    SECB,   8
                }

                Method (_BBN, 0, NotSerialized)
                {
                    Return (SECB)
                }

                Method (_STA, 0, NotSerialized)
                {
                    Return (0x0F)
                }

                Name (_PRT, Package (0x04)
                {
                    Package (0x04)
                    {
                        0xFFFF, 
                        0x00, 
                        \_SB.PCI0.LK2E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x01, 
                        \_SB.PCI0.LK3E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x02, 
                        \_SB.PCI0.LK4E, 
                        0x00
                    }, 

                    Package (0x04)
                    {
                        0xFFFF, 
                        0x03, 
                        \_SB.PCI0.LK1E, 
                        0x00
                    }
                })
                OperationRegion (PCE1, PCI_Config, 0x90, 0x70)
                Field (PCE1, DWordAcc, Lock, Preserve)
                {
                            Offset (0x08), 
                        ,   3, 
                    BS03,   1, 
                        ,   1, 
                    BS05,   1, 
                        ,   13, 
                    BS19,   1, 
                        ,   2, 
                    EPDS,   1
                }

                Device (X2S0)
                {
                    Name (_ADR, 0x00)
                    Method (_STA, 0, NotSerialized)
                    {
                        If (\_SB.PCI0.XVR2.EPDS)
                        {
                            Return (0x0F)
                        }
                        Else
                        {
                            Return (0x00)
                        }
                    }

                    Method (_RMV, 0, NotSerialized)
                    {
                        Return (0x01)
                    }

                    Name (_EJD, "_SB.PCI0.USB0.RH00.Prt5")
                }
            }
        }

        Device (QBTN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x01)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x04))
                {
                    Notify (QBTN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x01
                })
            }
        }

        Device (DBTN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x02)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x05))
                {
                    Notify (DBTN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x02
                })
            }
        }

        Device (MUBN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x03)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x03))
                {
                    Notify (MUBN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x03
                })
            }
        }

        Device (PIBN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x06)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x06))
                {
                    Notify (PIBN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x06
                })
            }
        }

        Device (WEBN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x04)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x10))
                {
                    Notify (WEBN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x04
                })
            }
        }

        Device (LVBN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x08)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x11))
                {
                    Notify (LVBN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x08
                })
            }
        }

        Device (VOBN)
        {
            Name (_HID, EisaId ("PNP0C32"))
            Name (_UID, 0x07)
            Method (_STA, 0, NotSerialized)
            {
                If (LEqual (OSYS, 0x07D6))
                {
                    Return (0x0F)
                }
                Else
                {
                    Return (0x00)
                }
            }

            Method (GHID, 0, NotSerialized)
            {
                If (LEqual (HOTB, 0x12))
                {
                    Notify (VOBN, 0x02)
                    Store (0x00, HOTB)
                }

                Return (Buffer (0x01)
                {
                    0x07
                })
            }
        }

        Scope (\)
        {
            Name (PICF, 0x00)
            Method (_PIC, 1, NotSerialized)
            {
                Store (Arg0, PICF)
            }

            OperationRegion (\_SB.PCI0.LPC0.PIRQ, PCI_Config, 0x7C, 0x0C)
            Field (\_SB.PCI0.LPC0.PIRQ, AnyAcc, NoLock, Preserve)
            {
                INTW,   4, 
                INTX,   4, 
                INTY,   4, 
                INTZ,   4, 
                INTA,   4, 
                INTB,   4, 
                INTC,   4, 
                INTD,   4, 
                ISCI,   4, 
                ITCO,   4, 
                ISMB,   4, 
                IUS2,   4, 
                INTU,   4, 
                INTS,   4, 
                PSI1,   4, 
                PSI0,   4, 
                IUS0,   4, 
                IUS1,   4, 
                IMAC,   4, 
                IAZA,   4, 
                IACI,   4, 
                IMCI,   4, 
                IPID,   4, 
                ISID,   4
            }
        }

        Scope (\_SB.PCI0)
        {
            Name (BUFA, ResourceTemplate ()
            {
                IRQ (Level, ActiveLow, Shared, )
                    {5,7,9,10,11,14,15}
            })
            Name (BUFB, ResourceTemplate ()
            {
                IRQ (Level, ActiveLow, Shared, _Y0A)
                    {}
            })
            CreateWordField (BUFB, \_SB.PCI0._Y0A._INT, IRQV)
            Method (CRS, 1, Serialized)
            {
                If (Arg0)
                {
                    ShiftLeft (0x01, Arg0, IRQV)
                }
                Else
                {
                    Store (Zero, IRQV)
                }

                Return (BUFB)
            }

            Method (SRS, 1, Serialized)
            {
                CreateWordField (Arg0, 0x01, IRQ0)
                FindSetRightBit (IRQ0, Local0)
                Decrement (Local0)
                Return (Local0)
            }

            Name (BUFM, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000014,
                }
            })
            Name (BUFI, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000015,
                }
            })
            Name (BUFU, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000016,
                }
            })
            Name (BUFS, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000017,
                }
            })
            Name (BUF1, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000010,
                }
            })
            Name (BUF2, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000011,
                }
            })
            Name (BUF3, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000012,
                }
            })
            Name (BUF4, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000013,
                }
            })
            Name (BUFF, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000005,
                    0x00000007,
                    0x0000000A,
                    0x0000000B,
                    0x0000000E,
                    0x0000000F,
                }
            })
            Name (BUP1, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000005,
                }
            })
            Name (BUP2, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x00000007,
                }
            })
            Name (BUFQ, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x0000000A,
                }
            })
            Name (BUFR, ResourceTemplate ()
            {
                Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
                {
                    0x0000000B,
                }
            })
            Method (CRSI, 1, Serialized)
            {
                Name (IRZ5, ResourceTemplate ()
                {
                    Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, _Y0B)
                    {
                        0x00000007,
                    }
                })
                CreateWordField (IRZ5, \_SB.PCI0.CRSI._Y0B._INT, INZ5)
                Store (Arg0, Local0)
                If (LEqual (Arg0, 0x03))
                {
                    Store (0x10, Local0)
                }

                If (LEqual (Arg0, 0x04))
                {
                    Store (0x11, Local0)
                }

                If (LEqual (Arg0, 0x06))
                {
                    Store (0x12, Local0)
                }

                If (LEqual (Arg0, 0x0C))
                {
                    Store (0x13, Local0)
                }

                If (LEqual (Arg0, 0x08))
                {
                    Store (0x14, Local0)
                }

                If (LEqual (Arg0, 0x0D))
                {
                    Store (0x15, Local0)
                }

                If (LEqual (Arg0, 0x02))
                {
                    Store (0x16, Local0)
                }

                If (LEqual (Arg0, 0x01))
                {
                    Store (0x17, Local0)
                }

                Store (Local0, INZ5)
                Return (IRZ5)
            }

            Method (SRSI, 1, Serialized)
            {
                CreateWordField (Arg0, 0x05, IRZ6)
                Store (IRZ6, Local0)
                If (LEqual (IRZ6, 0x10))
                {
                    Store (0x03, Local0)
                }

                If (LEqual (IRZ6, 0x11))
                {
                    Store (0x04, Local0)
                }

                If (LEqual (IRZ6, 0x12))
                {
                    Store (0x06, Local0)
                }

                If (LEqual (IRZ6, 0x13))
                {
                    Store (0x0C, Local0)
                }

                If (LEqual (IRZ6, 0x14))
                {
                    Store (0x08, Local0)
                }

                If (LEqual (IRZ6, 0x15))
                {
                    Store (0x0D, Local0)
                }

                If (LEqual (IRZ6, 0x16))
                {
                    Store (0x02, Local0)
                }

                If (LEqual (IRZ6, 0x17))
                {
                    Store (0x01, Local0)
                }

                Return (Local0)
            }

            Device (LNK1)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x01)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTW)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTW)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUP1)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTW))
                    }
                    Else
                    {
                        Return (CRSI (INTW))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTW)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTW)
                    }
                }
            }

            Device (LNK2)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x02)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTX)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTX)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUP2)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTX))
                    }
                    Else
                    {
                        Return (CRSI (INTX))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTX)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTX)
                    }
                }
            }

            Device (LNK3)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x03)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTY)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTY)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFQ)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTY))
                    }
                    Else
                    {
                        Return (CRSI (INTY))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTY)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTY)
                    }
                }
            }

            Device (LNK4)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x04)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTZ)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTZ)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFR)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTZ))
                    }
                    Else
                    {
                        Return (CRSI (INTZ))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTZ)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTZ)
                    }
                }
            }

            Device (LK1E)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x05)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTA)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTA)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUF1)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTA))
                    }
                    Else
                    {
                        Return (CRSI (INTA))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTA)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTA)
                    }
                }
            }

            Device (LK2E)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x06)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTB)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTB)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUF2)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTB))
                    }
                    Else
                    {
                        Return (CRSI (INTB))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTB)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTB)
                    }
                }
            }

            Device (LK3E)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x07)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTC)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTC)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUF3)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTC))
                    }
                    Else
                    {
                        Return (CRSI (INTC))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTC)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTC)
                    }
                }
            }

            Device (LK4E)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x08)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTD)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTD)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUF4)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTD))
                    }
                    Else
                    {
                        Return (CRSI (INTD))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTD)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTD)
                    }
                }
            }

            Device (LSMB)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x09)
                Method (_STA, 0, NotSerialized)
                {
                    If (ISMB)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, ISMB)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFQ)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (ISMB))
                    }
                    Else
                    {
                        Return (CRSI (ISMB))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), ISMB)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), ISMB)
                    }
                }
            }

            Device (LPMU)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x14)
                Method (_STA, 0, NotSerialized)
                {
                    If (INTS)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, INTS)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFR)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (INTS))
                    }
                    Else
                    {
                        Return (CRSI (INTS))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), INTS)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), INTS)
                    }
                }
            }

            Device (LUS0)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x0A)
                Method (_STA, 0, NotSerialized)
                {
                    If (IUS0)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IUS0)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFU)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IUS0))
                    }
                    Else
                    {
                        Return (CRSI (IUS0))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IUS0)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IUS0)
                    }
                }
            }

            Device (LUS2)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x0C)
                Method (_STA, 0, NotSerialized)
                {
                    If (IUS2)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IUS2)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFU)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IUS2))
                    }
                    Else
                    {
                        Return (CRSI (IUS2))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IUS2)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IUS2)
                    }
                }
            }

            Device (LMAC)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x0D)
                Method (_STA, 0, NotSerialized)
                {
                    If (IMAC)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IMAC)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFM)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IMAC))
                    }
                    Else
                    {
                        Return (CRSI (IMAC))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IMAC)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IMAC)
                    }
                }
            }

            Device (LAZA)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x0E)
                Method (_STA, 0, NotSerialized)
                {
                    If (IAZA)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IAZA)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFI)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IAZA))
                    }
                    Else
                    {
                        Return (CRSI (IAZA))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IAZA)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IAZA)
                    }
                }
            }

            Device (LACI)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x0F)
                Method (_STA, 0, NotSerialized)
                {
                    If (IACI)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IACI)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFI)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IACI))
                    }
                    Else
                    {
                        Return (CRSI (IACI))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IACI)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IACI)
                    }
                }
            }

            Device (LMCI)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x10)
                Method (_STA, 0, NotSerialized)
                {
                    If (IMCI)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IMCI)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFI)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IMCI))
                    }
                    Else
                    {
                        Return (CRSI (IMCI))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IMCI)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IMCI)
                    }
                }
            }

            Device (LPID)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x11)
                Method (_STA, 0, NotSerialized)
                {
                    If (IPID)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, IPID)
                    Store (0x00, ISID)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFI)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (IPID))
                    }
                    Else
                    {
                        Return (CRSI (IPID))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), IPID)
                        Store (SRS (Arg0), ISID)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), IPID)
                        Store (SRSI (Arg0), ISID)
                    }
                }
            }

            Device (LTID)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x12)
                Method (_STA, 0, NotSerialized)
                {
                    If (PSI0)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, PSI0)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFS)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (PSI0))
                    }
                    Else
                    {
                        Return (CRSI (PSI0))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), PSI0)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), PSI0)
                    }
                }
            }

            Device (LSI1)
            {
                Name (_HID, EisaId ("PNP0C0F"))
                Name (_UID, 0x13)
                Method (_STA, 0, NotSerialized)
                {
                    If (PSI0)
                    {
                        Return (0x0B)
                    }
                    Else
                    {
                        Return (0x09)
                    }
                }

                Method (_DIS, 0, NotSerialized)
                {
                    Store (0x00, PSI1)
                }

                Method (_PRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (BUFA)
                    }
                    Else
                    {
                        Return (BUFM)
                    }
                }

                Method (_CRS, 0, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Return (CRS (PSI1))
                    }
                    Else
                    {
                        Return (CRSI (PSI1))
                    }
                }

                Method (_SRS, 1, NotSerialized)
                {
                    If (LNot (PICF))
                    {
                        Store (SRS (Arg0), PSI1)
                    }
                    Else
                    {
                        Store (SRSI (Arg0), PSI1)
                    }
                }
            }
        }

        Scope (\_TZ)
        {
            Name (TPAS, 0x58)
            Name (TPC, 0x5F)
            Name (TPTM, 0x4B)
            ThermalZone (THRM)
            {
                Method (_CRT, 0, Serialized)
                {
                    Return (Add (0x0AAC, Multiply (TPC, 0x0A)))
                }

                Method (_SCP, 1, Serialized)
                {
                    Store (0x00, CTYP)
                }

                Method (_TMP, 0, Serialized)
                {
                    If (ECON)
                    {
                        Acquire (\_SB.PCI0.EC0.MUT0, 0xFFFF)
                        Store (\_SB.PCI0.EC0.RTMP, Local0)
                        Release (\_SB.PCI0.EC0.MUT0)
                        Store ("Current temp is: ", Debug)
                        Return (Add (0x0AAC, Multiply (Local0, 0x0A)))
                    }
                    Else
                    {
                        Return (Add (0x0AAC, Multiply (TPTM, 0x0A)))
                    }
                }

                Method (_PSL, 0, Serialized)
                {
                    Return (Package (0x01)
                    {
                        \_PR.CPU0
                    })
                }

                Method (_PSV, 0, Serialized)
                {
                    Return (Add (0x0AAC, Multiply (TPAS, 0x0A)))
                }

                Method (_TC1, 0, Serialized)
                {
                    Return (0x02)
                }

                Method (_TC2, 0, Serialized)
                {
                    Return (0x03)
                }

                Method (_TSP, 0, Serialized)
                {
                    Return (0x64)
                }
            }
        }
    }

    Scope (\_SB.PCI0.LPC0)
    {
        OperationRegion (RGA0, PCI_Config, 0xA0, 0x04)
        Field (RGA0, AnyAcc, NoLock, Preserve)
        {
            COMP,   8, 
            ADIO,   4, 
            MIDS,   4, 
            MSSS,   4, 
            FDCP,   2, 
            ADLB,   1, 
                    Offset (0x03), 
            LPTP,   3, 
                ,   1, 
            DVR0,   1, 
            DVR1,   1, 
            DVR2,   1, 
            DVR3,   1
        }

        OperationRegion (RGA1, PCI_Config, 0xA4, 0x04)
        Field (RGA1, AnyAcc, NoLock, Preserve)
        {
            GMPS,   16, 
                    Offset (0x04)
        }
    }

    OperationRegion (CS72, SystemIO, 0x72, 0x02)
    Field (CS72, ByteAcc, NoLock, Preserve)
    {
        CI72,   8, 
        CO73,   8
    }

    IndexField (CI72, CO73, ByteAcc, NoLock, Preserve)
    {
                Offset (0x22), 
            ,   3, 
        HPBD,   3, 
                Offset (0x9A), 
        BRNS,   4, 
        ACBN,   4, 
        BABN,   4, 
        WLSU,   1, 
        BTSU,   1, 
        IVIK,   2, 
        BTWL,   2, 
        BTLS,   1, 
        BWLS,   1, 
        WWLS,   1, 
                Offset (0x9D), 
        S4FL,   1, 
        SETF,   1, 
        VGAT,   1, 
        LSHK,   1, 
        S4RT,   2, 
        PTPE,   2, 
        BTNS,   1, 
        BTS3,   1, 
                Offset (0xA2), 
        HOTB,   8
    }

    Mutex (M723, 0x00)
    OperationRegion (DBGP, SystemIO, 0x80, 0x01)
    Field (DBGP, ByteAcc, NoLock, Preserve)
    {
        DBUG,   8
    }

    OperationRegion (ENEP, SystemIO, 0x0380, 0x04)
    Field (ENEP, ByteAcc, NoLock, Preserve)
    {
        P380,   8, 
        P381,   8, 
        P382,   8, 
        P383,   8
    }

    Mutex (M380, 0x00)
    OperationRegion (PM1A, SystemIO, 0x1000, 0x04)
    Field (PM1A, ByteAcc, NoLock, Preserve)
    {
            ,   14, 
        PEWS,   1, 
                Offset (0x02)
    }

    OperationRegion (LDTR, SystemIO, 0x10A6, 0x01)
    Field (LDTR, ByteAcc, NoLock, Preserve)
    {
        LDTC,   1
    }

    OperationRegion (Z00V, SystemIO, 0x1407, 0x01)
    Field (Z00V, ByteAcc, NoLock, Preserve)
    {
        PSMI,   1, 
                Offset (0x01)
    }

    OperationRegion (NVGP, SystemIO, 0x14C4, 0x08)
    Field (NVGP, ByteAcc, NoLock, Preserve)
    {
        Z00W,   8, 
        Z00X,   8, 
        Z00Y,   8, 
        Z000,   8, 
        Z001,   8, 
        Z002,   8, 
        Z00Z,   8, 
        Z010,   8
    }

    OperationRegion (NVG1, SystemIO, 0x14D0, 0x08)
    Field (NVG1, ByteAcc, NoLock, Preserve)
    {
                Offset (0x06), 
        GP23,   8, 
        GP24,   8
    }

    Name (RBRF, 0x01)
    Name (L10F, 0x00)
    Name (SCIC, 0x00)
    Name (SCID, 0x00)
    Name (CADL, 0x01)
    Name (PADL, 0x01)
    Name (PSTE, 0x01)
    Name (CSTE, 0x01)
    Name (NSTE, 0x01)
    Name (SSTE, 0x01)
    Name (WMSF, 0x00)
    Name (JMPF, 0x00)
    Name (WIRE, 0x00)
    Name (WLID, 0xFF)
    Name (GP25, 0x01)
    Name (GP26, 0x01)
    Name (WLSS, 0x01)
    Name (WLS2, 0x00)
    Name (S34F, 0x00)
    Name (S34C, 0x00)
    Name (OSYS, 0x07D6)
    Name (CTYP, 0x00)
    Name (DTCN, 0x00)
    Name (\ECON, 0x00)
    Name (FWSO, "FWSO")
}


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:25                                                     ` Alan Cox
@ 2008-01-01 15:57                                                       ` David P. Reed
  2008-01-01 21:16                                                         ` H. Peter Anvin
  2008-01-01 15:59                                                       ` David P. Reed
  1 sibling, 1 reply; 186+ messages in thread
From: David P. Reed @ 2008-01-01 15:57 UTC (permalink / raw)
  To: Alan Cox
  Cc: H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Alan Cox wrote:
>> responds to reads differently than "unused" ports.  In particular, an 
>> inb takes 1/2 the elapsed time compared to a read to "known" unused port 
>> 0xed - 792 tsc ticks for port 80 compared to about 1450 tsc ticks for 
>> port 0xed and other unused ports (tsc at 800 MHz).
>>     
>
> Well at least we know where the port is now - thats too fast for an LPC
> bus device, so it must be an SMI trap.
>
> Only easy way to find out is to use the debugging event counters and see
> how many instruction cycles are issued as part of the 0x80 port. If its
> suprisingly high then you've got a firmware bug and can go spank HP.
>
>   
Alan, thank you for the pointers.  I have been doing variations on this 
testing theme for a while - I get intrigued by a good debugging 
challenge, and after all it's my machine...

Two relevant new data points, and then some more suggestions:

1. It appears to be a real port.  SMI traps are not happening in the 
normal outb to 80.  Hundreds of them execute perfectly with the expected 
instruction counts.  If I can trace the particular event that creates 
the hard freeze (getting really creative, here) and stop before the 
freeze disables the entire computer, I will.  That may be an SMI, or 
perhaps any other kind of interrupt or exception.  Maybe someone knows 
how to safely trace through an impending SMI while doing printk's or 
something?

2. It appears to be the standard POST diagnostic port.  On a whim, I 
disassembled my DSDT code, and studied it more closely.   It turns out 
that there are a bunch of "Store(..., DBUG)" instructions scattered 
throughout, and when you look at what DBUG is defined as, it is defined 
as an IO Port at IO address DBGP, which is a 1-byte value = 0x80.  So 
the ACPI BIOS thinks it has something to do with debugging.   There's a 
little strangeness here, however, because the value sent to the port 
occasionally has something to do with arguments to the ACPI operations 
relating to sleep and wakeup ...  could just be that those arguments are 
distinctive.

In thinking about this, I recognize a couple of things.  ACPI is telling 
us something when it declares a reference to port 80 in its code.  It's 
not telling us the function of this port on this machine, but it is 
telling us that it is being used by the BIOS.   This could be a reason 
to put out a printk warning message...   'warning: port 80 is used by 
ACPI BIOS - if you are experiencing problems, you might try an alternate 
means of iodelay.'

Second, it seems likely that there are one of two possible reasons that 
the port 80 writes cause hang/freezes:

1. buffer overflow in such a device.

2. there is some "meaning" to certain byte values being written (the 
_PTS and _WAK use of arguments that come from callers to store into port 
80 makes me suspicious.)   That might mean that the freeze happens only 
when certain values are written, or when they are written closely in 
time to some other action - being used to communicate something to the 
SMM code).   If there is some race in when Linux's port 80 writes happen 
that happen to change the meaning of a request to the hardware or to 
SMM, then we could be rarely stepping on




^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
       [not found]             ` <fa.KbCnGLPlUEYe/Ibajd+hTY7A7Qw@ifi.uio.no>
@ 2007-12-31 18:21               ` Robert Hancock
  0 siblings, 0 replies; 186+ messages in thread
From: Robert Hancock @ 2007-12-31 18:21 UTC (permalink / raw)
  To: Alan Cox
  Cc: Pavel Machek, Linus Torvalds, Rene Herman, Ingo Molnar, dpreed,
	Islam Amer, hpa, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

Alan Cox wrote:
>> "You plug in PCI DEBUG card and it overclocks your machine" is bad
>> scenario.. (I don't know if it does... can PCI card emulate ISA timings?)
> 
> Easily. Its a bit more restricted by later spec revisions but it can halt
> your box of a week or two if it wants. Video cards used to pull this
> stunt for marketing benchmark numbers.

The drivers, specifically (the old "don't check if the command FIFO is 
full before writing, just write anyway and if it's full let the whole 
PCI bus stall while the FIFO empties out" trick).

I rather doubt any of those PCI POST debug cards would bother to 
accurately emulate the ISA timings of normal port 0x80 accesses, 
however. Most likely if you plug those in, port 0x80 accesses suddenly 
become lots faster now that the writes are completing on the PCI bus 
before ever hitting ISA/LPC..

-- 
Robert Hancock      Saskatoon, SK, Canada
To email, remove "nospam" from hancockr@nospamshaw.ca
Home Page: http://www.roberthancock.com/


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-31 14:39             ` Bodo Eggert
@ 2007-12-31 15:56               ` Alan Cox
  0 siblings, 0 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-31 15:56 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: H. Peter Anvin, 7eggert, Ingo Molnar, Linus Torvalds,
	Rene Herman, dpreed, Islam Amer, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel

On Mon, 31 Dec 2007 15:39:02 +0100 (CET)
> > Actually there were, and I sent numerous people patches for that back in
> > ISA days. 
> 
> Are you talking about VGA cards requiring a delay between outb index/outb 
> data, VGA cards barfing on outw or systems barfing on outb(0x80,42)?

VGA cards barfing on outw - on some trident at least it would cause weird
display messups when scrolling the text console that went right the next
scroll.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:31           ` Alan Cox
@ 2007-12-31 14:39             ` Bodo Eggert
  2007-12-31 15:56               ` Alan Cox
  0 siblings, 1 reply; 186+ messages in thread
From: Bodo Eggert @ 2007-12-31 14:39 UTC (permalink / raw)
  To: Alan Cox
  Cc: H. Peter Anvin, 7eggert, Ingo Molnar, Linus Torvalds,
	Rene Herman, dpreed, Islam Amer, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel

On Sun, 30 Dec 2007, Alan Cox wrote:
> On Sun, 30 Dec 2007 12:53:02 -0800
> "H. Peter Anvin" <hpa@zytor.com> wrote:
> > Bodo Eggert wrote:

> > > I've never seen code which would do that, and it was not suggested by any
> > > tutorial I ever saw. I'd expect any machine to break on all kinds of software
> > > if it required this. The only thing I remember being warned about is writing
> > > the index and the data register at the same time using outw, because that
> > > would write both registers at the same time on 16-bit-cards.
> > > 
> > 
> > And we use that, and have been for 15 years.  I haven't seen any screams 
> > of pain about it.
> 
> Actually there were, and I sent numerous people patches for that back in
> ISA days. 

Are you talking about VGA cards requiring a delay between outb index/outb 
data, VGA cards barfing on outw or systems barfing on outb(0x80,42)?
-- 
Programming is an art form that fights back.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:33               ` Alan Cox
@ 2007-12-30 22:02                 ` Ingo Molnar
  0 siblings, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 22:02 UTC (permalink / raw)
  To: Alan Cox
  Cc: H. Peter Anvin, Bodo Eggert, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> > ok. Like the patch below?
> 
> Not quite - you still need the loop in case you NMI and then run off 
> into oblivion

yes indeed. Updated patch below.

	Ingo

-------------->
Subject: x86: hlt on early crash
From: Ingo Molnar <mingo@elte.hu>

H. Peter Anvin <hpa@zytor.com> wrote:

> It probably should actually HLT, to avoid sucking power, and stressing
> the thermal system.  We're dead at this point, and the early 486's
> which had problems with HLT will lock up - we don't care.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/boot/compressed/misc_32.c |    3 ++-
 arch/x86/boot/compressed/misc_64.c |    3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

Index: linux-x86.q/arch/x86/boot/compressed/misc_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_32.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_32.c
@@ -339,7 +339,8 @@ static void error(char *x)
 	putstr(x);
 	putstr("\n\n -- System halted");
 
-	while(1);	/* Halt */
+	while (1)
+		asm("hlt");
 }
 
 asmlinkage void decompress_kernel(void *rmode, unsigned long end,
Index: linux-x86.q/arch/x86/boot/compressed/misc_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_64.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_64.c
@@ -338,7 +338,8 @@ static void error(char *x)
 	putstr(x);
 	putstr("\n\n -- System halted");
 
-	while(1);	/* Halt */
+	while (1)
+		asm("hlt");
 }
 
 asmlinkage void decompress_kernel(void *rmode, unsigned long heap,


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:44               ` H. Peter Anvin
@ 2007-12-30 21:58                 ` Rene Herman
  0 siblings, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-30 21:58 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Bodo Eggert, Alan Cox, Linus Torvalds, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

On 30-12-07 22:44, H. Peter Anvin wrote:
> Ingo Molnar wrote:
>>>>
>>> It probably should actually HLT, to avoid sucking power, and 
>>> stressing the thermal system.  We're dead at this point, and the 
>>> early 486's which had problems with HLT will lock up - we don't care.
>>
>> ok. Like the patch below?
>>
> 
> Don't need the cli; we're already running with interrupts disabled.
> 
> I'd do:
> 
>     while (1)
>         asm volatile("hlt");
> 
> ... mostly on general principles.

At least with current GCC the volatile isn't strictly needed as its implied 
without output operands but I was only certain after checking that. Do you 
remember if that used to be different for previous GCC versions? I tend to 
also stick volatiles on them still...

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:00             ` Ingo Molnar
  2007-12-30 21:32               ` Bodo Eggert
  2007-12-30 21:33               ` Alan Cox
@ 2007-12-30 21:44               ` H. Peter Anvin
  2007-12-30 21:58                 ` Rene Herman
  2 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-30 21:44 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Bodo Eggert, Alan Cox, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Ingo Molnar wrote:
>>>
>> It probably should actually HLT, to avoid sucking power, and stressing 
>> the thermal system.  We're dead at this point, and the early 486's 
>> which had problems with HLT will lock up - we don't care.
> 
> ok. Like the patch below?
> 

Don't need the cli; we're already running with interrupts disabled.

I'd do:

	while (1)
		asm volatile("hlt");

... mostly on general principles.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:00             ` Ingo Molnar
  2007-12-30 21:32               ` Bodo Eggert
@ 2007-12-30 21:33               ` Alan Cox
  2007-12-30 22:02                 ` Ingo Molnar
  2007-12-30 21:44               ` H. Peter Anvin
  2 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 21:33 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: H. Peter Anvin, Bodo Eggert, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

> ok. Like the patch below?

Not quite - you still need the loop in case you NMI and then run off into
oblivion

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 21:00             ` Ingo Molnar
@ 2007-12-30 21:32               ` Bodo Eggert
  2007-12-30 21:33               ` Alan Cox
  2007-12-30 21:44               ` H. Peter Anvin
  2 siblings, 0 replies; 186+ messages in thread
From: Bodo Eggert @ 2007-12-30 21:32 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: H. Peter Anvin, Bodo Eggert, Alan Cox, Linus Torvalds,
	Rene Herman, dpreed, Islam Amer, Pavel Machek, Ingo Molnar,
	Andi Kleen, Thomas Gleixner, Linux Kernel

On Sun, 30 Dec 2007, Ingo Molnar wrote:
> * H. Peter Anvin <hpa@zytor.com> wrote:
> > Ingo Molnar wrote:
> >> * Bodo Eggert <7eggert@gmx.de> wrote:

> >>> BTW: The error function in linux-2.6.23/arch/i386/boot/compressed/misc.c 
> >>> uses while(1) without cpu_relax() in order to halt the machine. Is this 
> >>> fixed? Should it be fixed?
> >>
> >> this is early bootup so there's no need to be "nice" to other cores or 
> >> sockets - none of them are really running.
> >>
> >
> > It probably should actually HLT, to avoid sucking power, and stressing 
> > the thermal system.  We're dead at this point, and the early 486's 
> > which had problems with HLT will lock up - we don't care.
> 
> ok. Like the patch below?

>  
> -	while(1);	/* Halt */
> +	asm("cli; hlt");	/* Halt */

The other users would loop around the hlt. Cargo Cult?
-- 
Top 100 things you don't want the sysadmin to say:
97. Go get your backup tape. (You _do_ have a backup tape?)

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:53         ` H. Peter Anvin
@ 2007-12-30 21:31           ` Alan Cox
  2007-12-31 14:39             ` Bodo Eggert
  0 siblings, 1 reply; 186+ messages in thread
From: Alan Cox @ 2007-12-30 21:31 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: 7eggert, Ingo Molnar, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

On Sun, 30 Dec 2007 12:53:02 -0800
"H. Peter Anvin" <hpa@zytor.com> wrote:

> Bodo Eggert wrote:
> > 
> > I've never seen code which would do that, and it was not suggested by any
> > tutorial I ever saw. I'd expect any machine to break on all kinds of software
> > if it required this. The only thing I remember being warned about is writing
> > the index and the data register at the same time using outw, because that
> > would write both registers at the same time on 16-bit-cards.
> > 
> 
> And we use that, and have been for 15 years.  I haven't seen any screams 
> of pain about it.

Actually there were, and I sent numerous people patches for that back in
ISA days. 

Alan

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 20:56           ` H. Peter Anvin
@ 2007-12-30 21:00             ` Ingo Molnar
  2007-12-30 21:32               ` Bodo Eggert
                                 ` (2 more replies)
  0 siblings, 3 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 21:00 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Bodo Eggert, Alan Cox, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel


* H. Peter Anvin <hpa@zytor.com> wrote:

> Ingo Molnar wrote:
>> * Bodo Eggert <7eggert@gmx.de> wrote:
>>
>>> BTW: The error function in linux-2.6.23/arch/i386/boot/compressed/misc.c 
>>> uses while(1) without cpu_relax() in order to halt the machine. Is this 
>>> fixed? Should it be fixed?
>>
>> this is early bootup so there's no need to be "nice" to other cores or 
>> sockets - none of them are really running.
>>
>
> It probably should actually HLT, to avoid sucking power, and stressing 
> the thermal system.  We're dead at this point, and the early 486's 
> which had problems with HLT will lock up - we don't care.

ok. Like the patch below?

	Ingo

---------->
Subject: x86: hlt on early crash
From: Ingo Molnar <mingo@elte.hu>

H. Peter Anvin <hpa@zytor.com> wrote:

> It probably should actually HLT, to avoid sucking power, and stressing
> the thermal system.  We're dead at this point, and the early 486's
> which had problems with HLT will lock up - we don't care.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 arch/x86/boot/compressed/misc_32.c |    2 +-
 arch/x86/boot/compressed/misc_64.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

Index: linux-x86.q/arch/x86/boot/compressed/misc_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_32.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_32.c
@@ -339,7 +339,7 @@ static void error(char *x)
 	putstr(x);
 	putstr("\n\n -- System halted");
 
-	while(1);	/* Halt */
+	asm("cli; hlt");	/* Halt */
 }
 
 asmlinkage void decompress_kernel(void *rmode, unsigned long end,
Index: linux-x86.q/arch/x86/boot/compressed/misc_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_64.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_64.c
@@ -338,7 +338,7 @@ static void error(char *x)
 	putstr(x);
 	putstr("\n\n -- System halted");
 
-	while(1);	/* Halt */
+	asm("cli; hlt");	/* Halt */
 }
 
 asmlinkage void decompress_kernel(void *rmode, unsigned long heap,

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 18:10         ` Ingo Molnar
@ 2007-12-30 20:56           ` H. Peter Anvin
  2007-12-30 21:00             ` Ingo Molnar
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-30 20:56 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Bodo Eggert, Alan Cox, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Ingo Molnar wrote:
> * Bodo Eggert <7eggert@gmx.de> wrote:
> 
>> BTW: The error function in 
>> linux-2.6.23/arch/i386/boot/compressed/misc.c uses while(1) without 
>> cpu_relax() in order to halt the machine. Is this fixed? Should it be 
>> fixed?
> 
> this is early bootup so there's no need to be "nice" to other cores or 
> sockets - none of them are really running.
> 

It probably should actually HLT, to avoid sucking power, and stressing 
the thermal system.  We're dead at this point, and the early 486's which 
had problems with HLT will lock up - we don't care.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 17:50       ` Bodo Eggert
  2007-12-30 18:10         ` Ingo Molnar
@ 2007-12-30 20:53         ` H. Peter Anvin
  2007-12-30 21:31           ` Alan Cox
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-30 20:53 UTC (permalink / raw)
  To: 7eggert
  Cc: Ingo Molnar, Alan Cox, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Bodo Eggert wrote:
> 
> I've never seen code which would do that, and it was not suggested by any
> tutorial I ever saw. I'd expect any machine to break on all kinds of software
> if it required this. The only thing I remember being warned about is writing
> the index and the data register at the same time using outw, because that
> would write both registers at the same time on 16-bit-cards.
> 

And we use that, and have been for 15 years.  I haven't seen any screams 
of pain about it.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
       [not found]         ` <fa.8g+KfLLge6wS5cEnKhZJmdkIVAI@ifi.uio.no>
@ 2007-12-30 18:22           ` Robert Hancock
  0 siblings, 0 replies; 186+ messages in thread
From: Robert Hancock @ 2007-12-30 18:22 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Alan Cox, Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel

Ingo Molnar wrote:
> * Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
> 
>>> i dont get your last point. Firstly, we do an "outb $0x80" not an 
>>> inb.
>> outb not inb sorry yes
>>
>>> Secondly, outb $0x80 has no PCI posting side-effects AFAICS. 
>>> Thirdly,
>> It does. The last mmio write cycle to the bridge gets pushed out 
>> before the 0x80 cycle goes to the PCI bridge, times out and goes to 
>> the LPC bus.
> 
> ok. Is it more of a "gets flushed due to timing out", or a 
> specified-for-sure POST flushing property of all out 0x80 cycles going 
> to the PCI bridge? I thought PCI posting policy is up to the CPU, it can 
> delay PCI space writes arbitrarily (within reasonable timeouts) as long 
> as no read is done from the _same_ IO space address. Note that the port 
> 0x80 cycle is neither a read, nor for the same address.

There's no guarantee in the spec that any IO access will flush pending 
MMIO writes. However, I suspect in the majority of implementations 
(perhaps all), it indeed does.

-- 
Robert Hancock      Saskatoon, SK, Canada
To email, remove "nospam" from hancockr@nospamshaw.ca
Home Page: http://www.roberthancock.com/


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
  2007-12-30 17:50       ` Bodo Eggert
@ 2007-12-30 18:10         ` Ingo Molnar
  2007-12-30 20:56           ` H. Peter Anvin
  2007-12-30 20:53         ` H. Peter Anvin
  1 sibling, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-30 18:10 UTC (permalink / raw)
  To: Bodo Eggert
  Cc: Alan Cox, Linus Torvalds, Rene Herman, dpreed, Islam Amer, hpa,
	Pavel Machek, Ingo Molnar, Andi Kleen, Thomas Gleixner,
	Linux Kernel


* Bodo Eggert <7eggert@gmx.de> wrote:

> BTW: The error function in 
> linux-2.6.23/arch/i386/boot/compressed/misc.c uses while(1) without 
> cpu_relax() in order to halt the machine. Is this fixed? Should it be 
> fixed?

this is early bootup so there's no need to be "nice" to other cores or 
sockets - none of them are really running.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override
       [not found]     ` <9G8qN-4TX-13@gated-at.bofh.it>
@ 2007-12-30 17:50       ` Bodo Eggert
  2007-12-30 18:10         ` Ingo Molnar
  2007-12-30 20:53         ` H. Peter Anvin
  0 siblings, 2 replies; 186+ messages in thread
From: Bodo Eggert @ 2007-12-30 17:50 UTC (permalink / raw)
  To: Ingo Molnar, Alan Cox, Linus Torvalds, Rene Herman, dpreed,
	Islam Amer, hpa, Pavel Machek, Ingo Molnar, Andi Kleen,
	Thomas Gleixner, Linux Kernel

Ingo Molnar <mingo@elte.hu> wrote:

> do you have any memories about the outb_p() use of misc_32.c:
> 
>         pos = (x + cols * y) * 2;       /* Update cursor position */
>         outb_p(14, vidport);
>         outb_p(0xff & (pos >> 9), vidport+1);
>         outb_p(15, vidport);
>         outb_p(0xff & (pos >> 1), vidport+1);
> 
> was this ever needed? This is so early in the bootup that can we cannot
> do any sensible delay. Perhaps we could try a natural delay sequence via
> inb from 0x3cc:
> 
>         outb(14, vidport);
>          inb(0x3cc); /* delay */
>         outb(0xff & (pos >> 9), vidport+1);

I've never seen code which would do that, and it was not suggested by any
tutorial I ever saw. I'd expect any machine to break on all kinds of software
if it required this. The only thing I remember being warned about is writing
the index and the data register at the same time using outw, because that
would write both registers at the same time on 16-bit-cards.


BTW: The error function in linux-2.6.23/arch/i386/boot/compressed/misc.c
uses while(1) without cpu_relax() in order to halt the machine. Is this fixed?
Should it be fixed?


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 22:01                                                               ` Rene Herman
@ 2007-12-17 22:18                                                                 ` David P. Reed
  0 siblings, 0 replies; 186+ messages in thread
From: David P. Reed @ 2007-12-17 22:18 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Alan Cox, H. Peter Anvin, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Besides the two reports of freezes on bugzilla.kernel.org (9511, 6307), 
the following two bug reports on bugzilla.redhat.com are almost 
certainly due to the same cause (imo, of course): 245834, 227234.

Ubuntu launchpad bug 158849 also seems to report the same problem, for 
an HP dv6258se 64-bit machine.

Also this one: 
http://www.mail-archive.com/linux-acpi@vger.kernel.org/msg10321.html

If you want to collect dmidecode data from these folks, perhaps we might 
get a wider sense of what categories of machines are affected.  They all 
seem to be recemt HP and Compaq AMD64 laptops, probably all Quanta 
motherboards.



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:56                                                             ` Ingo Molnar
@ 2007-12-17 22:01                                                               ` Rene Herman
  2007-12-17 22:18                                                                 ` David P. Reed
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17 22:01 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rene Herman, Alan Cox, David P. Reed, H. Peter Anvin,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

On 17-12-07 22:56, Ingo Molnar wrote:

> * Rene Herman <rene.herman@gmail.com> wrote:
> 
>>>> Signed-off-by: Rene Herman <rene.herman@gmail.com>
>>> hm, i see this as a step backwards from the pretty flexible patch 
>>> that David already tested. (and which also passed a few hundred 
>>> bootup tests on my x86 test-grid)
>> Please see Alan's comment that udelay (and none) shouldn't yet be 
>> provided as a choice. It opens race windows in drivers even when it 
>> works in practice on most setups. The version with "udelay" and "none" 
>> is not minimal, not low risk and certainly not .24 material.
> 
> huh? By default we still use port 0x80. Any udelay is non-default and 
> needs the user to explicitly switch to it.  But it enables us to debug
> any suspected drivers by asking testers to: "please try this driver with 
> io_delay=udelay, does it still work fine?". So those extra options are 
> quite sensible. If you have any real technical arguments against that 
> then please let us know.

Ingo, have lots of fun playing with yourself, but remove my sign off from 
anything with the udelay and none methods.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:47                                                           ` Rene Herman
@ 2007-12-17 21:56                                                             ` Ingo Molnar
  2007-12-17 22:01                                                               ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 21:56 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Rene Herman <rene.herman@gmail.com> wrote:

>>> Signed-off-by: Rene Herman <rene.herman@gmail.com>
>>
>> hm, i see this as a step backwards from the pretty flexible patch 
>> that David already tested. (and which also passed a few hundred 
>> bootup tests on my x86 test-grid)
>
> Please see Alan's comment that udelay (and none) shouldn't yet be 
> provided as a choice. It opens race windows in drivers even when it 
> works in practice on most setups. The version with "udelay" and "none" 
> is not minimal, not low risk and certainly not .24 material.

huh? By default we still use port 0x80. Any udelay is non-default and 
needs the user to explicitly switch to it. But it enables us to debug 
any suspected drivers by asking testers to: "please try this driver with 
io_delay=udelay, does it still work fine?". So those extra options are 
quite sensible. If you have any real technical arguments against that 
then please let us know.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:40                                                             ` H. Peter Anvin
  2007-12-17 21:46                                                               ` Ingo Molnar
@ 2007-12-17 21:50                                                               ` Rene Herman
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17 21:50 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rene Herman, Ingo Molnar, Alan Cox, Ingo Molnar, David P. Reed,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel, rol

On 17-12-07 22:40, H. Peter Anvin wrote:

> Rene Herman wrote:
>>
>> Well, yes, I guess that does make sense. It's back again. Named the 
>> choices "standard" and "alternate" again as I feel "0x80" and "0xed" 
>> suggest they're free values a bit too much but if anyone feels 
>> strongly about it, so be it.
>>
> 
> They ARE -- or really, should be, free values (0xeb and 0xf0 are other 
> reasonable values, for example.)

I was afraid someone would say that. Making a random port available is fine 
for testing purposes but a failry dangerous thing to do generally. For a 
minimal version at -rc4 time, I believe sticking with 0x80 and 0xed ie best.

Lots of time during .25 to go wild...

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:41                                                         ` Ingo Molnar
@ 2007-12-17 21:47                                                           ` Rene Herman
  2007-12-17 21:56                                                             ` Ingo Molnar
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17 21:47 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rene Herman, Alan Cox, David P. Reed, H. Peter Anvin,
	Paul Rolland, Pavel Machek, Thomas Gleixner, linux-kernel,
	Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 1752 bytes --]

On 17-12-07 22:41, Ingo Molnar wrote:
> * Rene Herman <rene.herman@gmail.com> wrote:
> 
>> On 17-12-07 17:12, Alan Cox wrote:
>>
>>> I don't think we should be offering udelay based delays at this point.
>>> There are a lot of drivers to fix first. This is just one trivial example
>> I agree. This thread's too full of people calling this outb method a 
>> dumb hack. It's a well-known legacy PC thing and while in practice the 
>> udelay might be a functional replacement for a majority of cases (save 
>> the races you are finding) a delay proportional to the bus speed makes 
>> great sense certainly when talking to hardware that itself runs 
>> proportinal to the bus speed for example.
>>
>> So, really, how about just sticking in this minimal version for now? 
>> Only switches the port to 0xed based on DMI and is all that is needed 
>> to fix the actual problem. This should be minimal and no-risk enough 
>> that it could also go to .24 if people want it to. It'll fix a few HP 
>> laptops (I'll try and get/verify the dv6000z DMI strings as well).
>>
>> Ingo?
>>
>> Signed-off-by: Rene Herman <rene.herman@gmail.com>
> 
> hm, i see this as a step backwards from the pretty flexible patch that 
> David already tested. (and which also passed a few hundred bootup tests 
> on my x86 test-grid)

Please see Alan's comment that udelay (and none) shouldn't yet be provided 
as a choice. It opens race windows in drivers even when it works in practice 
on most setups. The version with "udelay" and "none" is not minimal, not low 
risk and certainly not .24 material.

David tested this part of the patch just as well.

Attached again (with the boot param) since I see I left in an extraneous 
'Use the" in the kernel-parameters.txt file.

Rene.

[-- Attachment #2: dmi-port80-minimal-bootparam.diff --]
[-- Type: text/plain, Size: 10708 bytes --]

commit c12c7a47b9af87e8d867d5aa0ca5c6bcdd2463da
Author: Rene Herman <rene.herman@gmail.com>
Date:   Mon Dec 17 21:23:55 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP) laptops experience trouble from our port 0x80 I/O delay
    writes. This patch provides for a DMI based switch to the "alternate
    diagnostic port" 0xed (as used by some BIOSes as well) for these.
    
    David P. Reed confirmed that port 0xed works for him and provides a
    proper delay. The symptoms of _not_ working are a hanging machine,
    with "hwclock" use being a direct trigger.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist, but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but still leaves:
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally various drivers are racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    An early boot parameter to make the choice manually (and override any
    possible DMI based decision) is also provided:
    
    	io_delay=standard|alternate
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as tested by David P. Reed. He moreover reported that booting with
    "acpi=off" also fixed things and seeing as how ACPI isn't touched
    until after this DMI based I/O port switch leaving the ones in the
    boot code be is safe.
    
    The DMI strings from David's HP Pavilion dv9000z are in there already
    and we need to get/verify the DMI info from other machines with the
    problem, notably the HP Pavilion dv6000z.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 33121d6..6948e25 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -785,6 +785,12 @@ and is between 256 and 4096 characters. It is defined in the file
 			for translation below 32 bit and if not available
 			then look in the higher range.
 
+	io_delay=	[X86-32,X86-64] I/O delay port
+		standard
+			Use the 0x80 standard I/O delay port (default)
+		alternate
+			Use the 0xed alternate I/O delay port
+
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..5029e7a
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,69 @@
+/*
+ * I/O delay strategies for inb_p/outb_p
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+/*
+ * Allow for a DMI based override of port 0x80
+ */
+#define IO_DELAY_PORT_STD 0x80
+#define IO_DELAY_PORT_ALT 0xed
+
+static unsigned short io_delay_port __read_mostly = IO_DELAY_PORT_STD;
+
+void native_io_delay(void)
+{
+	asm volatile ("outb %%al, %w0" : : "d" (io_delay_port));
+}
+EXPORT_SYMBOL(native_io_delay);
+
+static int __init dmi_io_delay_port_alt(const struct dmi_system_id *id)
+{
+	printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident);
+	io_delay_port = IO_DELAY_PORT_ALT;
+	return 0;
+}
+
+static struct dmi_system_id __initdata dmi_io_delay_port_alt_table[] = {
+	{
+		.callback	= dmi_io_delay_port_alt,
+		.ident		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{
+	}
+};
+
+static int __initdata io_delay_override;
+
+static int __init io_delay_param(char *s)
+{
+	if (!s)
+		return -EINVAL;
+
+	if (!strcmp(s, "standard"))
+		io_delay_port = IO_DELAY_PORT_STD;
+	else if (!strcmp(s, "alternate"))
+		io_delay_port = IO_DELAY_PORT_ALT;
+	else
+		return -EINVAL;
+
+	io_delay_override = 1;
+	return 0;
+}
+
+early_param("io_delay", io_delay_param);
+
+void __init io_delay_init(void)
+{
+	if (!io_delay_override)
+		dmi_check_system(dmi_io_delay_port_alt_table);
+}
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..690b8f4 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..b2d4994 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,18 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
+static inline void slow_down_io(void)
+{
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +55,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \

^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:40                                                             ` H. Peter Anvin
@ 2007-12-17 21:46                                                               ` Ingo Molnar
  2007-12-17 21:50                                                               ` Rene Herman
  1 sibling, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 21:46 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rene Herman, Ingo Molnar, Alan Cox, David P. Reed, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, rol


* H. Peter Anvin <hpa@zytor.com> wrote:

> Rene Herman wrote:
>>
>> Well, yes, I guess that does make sense. It's back again. Named the 
>> choices "standard" and "alternate" again as I feel "0x80" and "0xed" 
>> suggest they're free values a bit too much but if anyone feels 
>> strongly about it, so be it.
>
> They ARE -- or really, should be, free values (0xeb and 0xf0 are other 
> reasonable values, for example.)

yeah. We've got the variant below for now, tested by David. We can still 
change things later on if the need arises.

	Ingo

-------------->
Subject: x86: provide a DMI based port 0x80 I/O delay override.
From: Rene Herman <rene.herman@gmail.com>

x86: provide a DMI based port 0x80 I/O delay override.

Certain (HP) laptops experience trouble from our port 0x80 I/O delay
writes. This patch provides for a DMI based switch to the "alternate
diagnostic port" 0xed (as used by some BIOSes as well) for these.

David P. Reed confirmed that port 0xed works for him and provides a
proper delay. The symptoms of _not_ working are a hanging machine,
with "hwclock" use being a direct trigger.

Earlier versions of this attempted to simply use udelay(2), with the
2 being a value tested to be a nicely conservative upper-bound with
help from many on the linux-kernel mailinglist but that approach has
two problems.

First, pre-loops_per_jiffy calibration (which is post PIT init while
some implementations of the PIT are actually one of the historically
problematic devices that need the delay) udelay() isn't particularly
well-defined. We could initialise loops_per_jiffy conservatively (and
based on CPU family so as to not unduly delay old machines) which
would sort of work, but...

Second, delaying isn't the only effect that a write to port 0x80 has.
It's also a PCI posting barrier which some devices may be explicitly
or implicitly relying on. Alan Cox did a survey and found evidence
that additionally some drivers may be racy on SMP without the bus
locking outb.

Switching to an inb() makes the timing too unpredictable and as such,
this DMI based switch should be the safest approach for now. Any more
invasive changes should get more rigid testing first. It's moreover
only very few machines with the problem and a DMI based hack seems
to fit that situation.

This also introduces a command-line parameter "io_delay" to override
the DMI based choice again:

	io_delay=<0x80|0xed|udelay|none>

where 0x80 means using the standard port 0x80 and 0xed means the
alternate port 0xed.

All these methods can also be selected via the kernel .config,
and can be runtime tuned via /proc/sys/kernel/io_delay_type (for
debugging purposes).

The DMI strings from David's HP Pavilion dv9000z are in there already
and we need to get/verify the DMI info from other machines with the
problem, notably the HP Pavilion dv6000z.

This patch is partly based on earlier patches from Pavel Machek and
David P. Reed.

[ mingo@elte.hu:
  - add the io_delay=none method
  - make each method selectable from the kernel config
  - eliminate the indirect function calls
  - add the /proc/sys/kernel/io_delay_type sysctl
  - change 'standard' and 'alternate' to 0x80 and 0xed
  - make the io delay config not depend on CONFIG_DEBUG_KERNEL ]

Signed-off-by: Rene Herman <rene.herman@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: "David P. Reed" <dpreed@reed.com>
---
 Documentation/kernel-parameters.txt |   10 +++
 arch/x86/Kconfig.debug              |   74 +++++++++++++++++++++++++++
 arch/x86/boot/compressed/misc_32.c  |    8 +-
 arch/x86/boot/compressed/misc_64.c  |    8 +-
 arch/x86/kernel/Makefile_32         |    2 
 arch/x86/kernel/Makefile_64         |    2 
 arch/x86/kernel/io_delay.c          |   98 ++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/setup_32.c          |    2 
 arch/x86/kernel/setup_64.c          |    2 
 include/asm-x86/io_32.h             |    8 +-
 include/asm-x86/io_64.h             |   29 ++++++----
 kernel/sysctl.c                     |    9 +++
 12 files changed, 227 insertions(+), 25 deletions(-)

Index: linux-x86.q/Documentation/kernel-parameters.txt
===================================================================
--- linux-x86.q.orig/Documentation/kernel-parameters.txt
+++ linux-x86.q/Documentation/kernel-parameters.txt
@@ -785,6 +785,16 @@ and is between 256 and 4096 characters. 
 			for translation below 32 bit and if not available
 			then look in the higher range.
 
+	io_delay=	[X86-32,X86-64] I/O delay method
+		0x80
+			Standard port 0x80 based delay
+		0xed
+			Alternate port 0xed based delay (needed on some systems)
+		udelay
+			Simple two microseconds delay
+		none
+			No delay
+
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
Index: linux-x86.q/arch/x86/Kconfig.debug
===================================================================
--- linux-x86.q.orig/arch/x86/Kconfig.debug
+++ linux-x86.q/arch/x86/Kconfig.debug
@@ -112,4 +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.
 
+#
+# 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
+	  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
Index: linux-x86.q/arch/x86/boot/compressed/misc_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_32.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
Index: linux-x86.q/arch/x86/boot/compressed/misc_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_64.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
Index: linux-x86.q/arch/x86/kernel/Makefile_32
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/Makefile_32
+++ linux-x86.q/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
Index: linux-x86.q/arch/x86/kernel/Makefile_64
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/Makefile_64
+++ linux-x86.q/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
Index: linux-x86.q/arch/x86/kernel/io_delay.c
===================================================================
--- /dev/null
+++ linux-x86.q/arch/x86/kernel/io_delay.c
@@ -0,0 +1,98 @@
+/*
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
+EXPORT_SYMBOL_GPL(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) {
+		printk(KERN_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		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{ }
+};
+
+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 (!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);
Index: linux-x86.q/arch/x86/kernel/setup_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/setup_32.c
+++ linux-x86.q/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
Index: linux-x86.q/arch/x86/kernel/setup_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/setup_64.c
+++ linux-x86.q/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
Index: linux-x86.q/include/asm-x86/io_32.h
===================================================================
--- linux-x86.q.orig/include/asm-x86/io_32.h
+++ linux-x86.q/include/asm-x86/io_32.h
@@ -250,10 +250,10 @@ static inline void flush_write_buffers(v
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+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>
Index: linux-x86.q/include/asm-x86/io_64.h
===================================================================
--- linux-x86.q.orig/include/asm-x86/io_64.h
+++ linux-x86.q/include/asm-x86/io_64.h
@@ -35,13 +35,20 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+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();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +57,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
Index: linux-x86.q/kernel/sysctl.c
===================================================================
--- linux-x86.q.orig/kernel/sysctl.c
+++ linux-x86.q/kernel/sysctl.c
@@ -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);
@@ -683,6 +684,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)
 	{

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 20:48                                                       ` Rene Herman
  2007-12-17 20:57                                                         ` H. Peter Anvin
@ 2007-12-17 21:41                                                         ` Ingo Molnar
  2007-12-17 21:47                                                           ` Rene Herman
  1 sibling, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 21:41 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, David P. Reed, H. Peter Anvin, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Rene Herman <rene.herman@gmail.com> wrote:

> On 17-12-07 17:12, Alan Cox wrote:
>
>> I don't think we should be offering udelay based delays at this point.
>> There are a lot of drivers to fix first. This is just one trivial example
>
> I agree. This thread's too full of people calling this outb method a 
> dumb hack. It's a well-known legacy PC thing and while in practice the 
> udelay might be a functional replacement for a majority of cases (save 
> the races you are finding) a delay proportional to the bus speed makes 
> great sense certainly when talking to hardware that itself runs 
> proportinal to the bus speed for example.
>
> So, really, how about just sticking in this minimal version for now? 
> Only switches the port to 0xed based on DMI and is all that is needed 
> to fix the actual problem. This should be minimal and no-risk enough 
> that it could also go to .24 if people want it to. It'll fix a few HP 
> laptops (I'll try and get/verify the dv6000z DMI strings as well).
>
> Ingo?
>
> Signed-off-by: Rene Herman <rene.herman@gmail.com>

hm, i see this as a step backwards from the pretty flexible patch that 
David already tested. (and which also passed a few hundred bootup tests 
on my x86 test-grid)

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:33                                                           ` Rene Herman
@ 2007-12-17 21:40                                                             ` H. Peter Anvin
  2007-12-17 21:46                                                               ` Ingo Molnar
  2007-12-17 21:50                                                               ` Rene Herman
  0 siblings, 2 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17 21:40 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Alan Cox, Ingo Molnar, David P. Reed, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, rol

Rene Herman wrote:
> 
> Well, yes, I guess that does make sense. It's back again. Named the 
> choices "standard" and "alternate" again as I feel "0x80" and "0xed" 
> suggest they're free values a bit too much but if anyone feels strongly 
> about it, so be it.
> 

They ARE -- or really, should be, free values (0xeb and 0xf0 are other 
reasonable values, for example.)

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 20:57                                                         ` H. Peter Anvin
@ 2007-12-17 21:33                                                           ` Rene Herman
  2007-12-17 21:40                                                             ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17 21:33 UTC (permalink / raw)
  To: H. Peter Anvin, Ingo Molnar
  Cc: Rene Herman, Alan Cox, Ingo Molnar, David P. Reed, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, rol

[-- Attachment #1: Type: text/plain, Size: 1695 bytes --]

On 17-12-07 21:57, H. Peter Anvin wrote:

> Rene Herman wrote:
>> On 17-12-07 17:12, Alan Cox wrote:
>>
>>> I don't think we should be offering udelay based delays at this point.
>>> There are a lot of drivers to fix first. This is just one trivial 
>>> example
>>
>> I agree. This thread's too full of people calling this outb method a 
>> dumb hack. It's a well-known legacy PC thing and while in practice the 
>> udelay might be a functional replacement for a majority of cases (save 
>> the races you are finding) a delay proportional to the bus speed makes 
>> great sense certainly when talking to hardware that itself runs 
>> proportinal to the bus speed for example.
>>
>> So, really, how about just sticking in this minimal version for now? 
>> Only switches the port to 0xed based on DMI and is all that is needed 
>> to fix the actual problem. This should be minimal and no-risk enough 
>> that it could also go to .24 if people want it to. It'll fix a few HP 
>> laptops (I'll try and get/verify the dv6000z DMI strings as well).
>>
> 
> I think retaining the command-line option available is a good thing, 
> though.  If nothing else, it is something very quick we can ask other 
> people to try if they seem to have similar problems.

Well, yes, I guess that does make sense. It's back again. Named the choices 
"standard" and "alternate" again as I feel "0x80" and "0xed" suggest they're 
free values a bit too much but if anyone feels strongly about it, so be it.

> Other than that, this alternate-port patch is a low-impact patch not 
> affecting hardware not on the blacklist, which makes it appropriate for 
> 2.6.24 IMO.

Signed-off-by: Rene Herman <rene.herman@gmail.com>

[-- Attachment #2: dmi-port80-minimal-bootparam.diff --]
[-- Type: text/plain, Size: 10720 bytes --]

commit c83008ff40e95f89407807cb122127c5444b3bc4
Author: Rene Herman <rene.herman@gmail.com>
Date:   Mon Dec 17 21:23:55 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP) laptops experience trouble from our port 0x80 I/O delay
    writes. This patch provides for a DMI based switch to the "alternate
    diagnostic port" 0xed (as used by some BIOSes as well) for these.
    
    David P. Reed confirmed that port 0xed works for him and provides a
    proper delay. The symptoms of _not_ working are a hanging machine,
    with "hwclock" use being a direct trigger.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist, but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but still leaves:
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally various drivers are racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    An early boot parameter to make the choice manually (and override any
    possible DMI based decision) is also provided:
    
    	io_delay=standard|alternate
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as tested by David P. Reed. He moreover reported that booting with
    "acpi=off" also fixed things and seeing as how ACPI isn't touched
    until after this DMI based I/O port switch leaving the ones in the
    boot code be is safe.
    
    The DMI strings from David's HP Pavilion dv9000z are in there already
    and we need to get/verify the DMI info from other machines with the
    problem, notably the HP Pavilion dv6000z.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 33121d6..ff66cf4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -785,6 +785,13 @@ and is between 256 and 4096 characters. It is defined in the file
 			for translation below 32 bit and if not available
 			then look in the higher range.
 
+	io_delay=	[X86-32,X86-64] I/O delay port
+		standard
+			Use the 0x80 standard I/O delay port (default)
+		alternate
+			Use the 0xed alternate I/O delay port
+
+			Use the
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..5029e7a
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,69 @@
+/*
+ * I/O delay strategies for inb_p/outb_p
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+/*
+ * Allow for a DMI based override of port 0x80
+ */
+#define IO_DELAY_PORT_STD 0x80
+#define IO_DELAY_PORT_ALT 0xed
+
+static unsigned short io_delay_port __read_mostly = IO_DELAY_PORT_STD;
+
+void native_io_delay(void)
+{
+	asm volatile ("outb %%al, %w0" : : "d" (io_delay_port));
+}
+EXPORT_SYMBOL(native_io_delay);
+
+static int __init dmi_io_delay_port_alt(const struct dmi_system_id *id)
+{
+	printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident);
+	io_delay_port = IO_DELAY_PORT_ALT;
+	return 0;
+}
+
+static struct dmi_system_id __initdata dmi_io_delay_port_alt_table[] = {
+	{
+		.callback	= dmi_io_delay_port_alt,
+		.ident		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{
+	}
+};
+
+static int __initdata io_delay_override;
+
+static int __init io_delay_param(char *s)
+{
+	if (!s)
+		return -EINVAL;
+
+	if (!strcmp(s, "standard"))
+		io_delay_port = IO_DELAY_PORT_STD;
+	else if (!strcmp(s, "alternate"))
+		io_delay_port = IO_DELAY_PORT_ALT;
+	else
+		return -EINVAL;
+
+	io_delay_override = 1;
+	return 0;
+}
+
+early_param("io_delay", io_delay_param);
+
+void __init io_delay_init(void)
+{
+	if (!io_delay_override)
+		dmi_check_system(dmi_io_delay_port_alt_table);
+}
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..690b8f4 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..b2d4994 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,18 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
+static inline void slow_down_io(void)
+{
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +55,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \

^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 19:38                                                     ` David P. Reed
  2007-12-17 19:55                                                       ` H. Peter Anvin
@ 2007-12-17 21:28                                                       ` Ingo Molnar
  1 sibling, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 21:28 UTC (permalink / raw)
  To: David P. Reed
  Cc: Rene Herman, H. Peter Anvin, Paul Rolland, Alan Cox,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* David P. Reed <dpreed@reed.com> wrote:

> Ingo -
>
> I finished testing the rolled up patch that you provided.  It seems to work 
> just fine.  Thank you for putting this all together and persevering in this 
> long and complex discussion. 
> Here are the results, on the offending laptop, using 2.6.24-rc5 plus that 
> one patch.
>
> First: booted with normal boot parameters (no io_delay=):
>
>    According to dmesg, 0xed is used.
>
>    hwclock ran fine, hundreds of times.
>    my shell script loop doing "cat /dev/nvram > /dev/null" ran fine, 
> several times.
>    Running Rene's "port 80" speed test ran fine once, then froze the system 
> hard.  (expected)
>
> Second: booted with io_delay=0x80, several tests, rebooting after freezes:
>
>    hwclock froze system hard.  (this is the problem that drove me to find 
> this bug).
>    my shell script loop froze system hard.
>
> Third: booted with io_delay=none:
>
>    hwclock ran fine, also hundreds of times.
>    my shell script loop ran fine several times.
>    Running rene's port80 test ran fine twice, froze system hard on third 
> try.
>
> Fourth: booted with io_delay=udelay:
>
>    hwclock ran fine, also hundreds of times.
>    my shell script loop ran fine several times.
>    Running Rene's port80 test ran fine, froze system hard on second try.
>
> Analysis:
>
>    patch works fine, and default to 0xed seems super conservative. I 
> will probably use the boot parameter io_delay=none, because I don't 
> seem to have any I/O
>    devices that require any delays - and this way I can find any that 
>    do.

great, and thanks for the extensive testing! I've added this line to the 
patch:

 Tested-by: "David P. Reed" <dpreed@reed.com>

if you dont mind.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 19:43                                                   ` David P. Reed
  2007-12-17 19:55                                                     ` H. Peter Anvin
@ 2007-12-17 21:25                                                     ` Alan Cox
  2008-01-01 15:57                                                       ` David P. Reed
  2008-01-01 15:59                                                       ` David P. Reed
  1 sibling, 2 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-17 21:25 UTC (permalink / raw)
  To: David P. Reed
  Cc: H. Peter Anvin, Rene Herman, Ingo Molnar, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

> responds to reads differently than "unused" ports.  In particular, an 
> inb takes 1/2 the elapsed time compared to a read to "known" unused port 
> 0xed - 792 tsc ticks for port 80 compared to about 1450 tsc ticks for 
> port 0xed and other unused ports (tsc at 800 MHz).

Well at least we know where the port is now - thats too fast for an LPC
bus device, so it must be an SMI trap.

Only easy way to find out is to use the debugging event counters and see
how many instruction cycles are issued as part of the 0x80 port. If its
suprisingly high then you've got a firmware bug and can go spank HP.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 21:02                                                       ` David P. Reed
@ 2007-12-17 21:17                                                         ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17 21:17 UTC (permalink / raw)
  To: David P. Reed
  Cc: Rene Herman, Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

David P. Reed wrote:
> 
> Note that I can run the port 80 test once, the second time I get the 
> hard freeze.  I didn't try writing to port 70 from userspace - that 
> one's dangerous, but the reading of it was included for a timing typical 
> of a chipset supported device.  These are all pretty consistent.
> 
> I find the "read" timing from 0x80 verrrrry interesting.  The write 
> timeing is also interesting, being faster than an unused port.
> 

Once again: reading from port 0x80 goes to the DMA page device.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 19:55                                                     ` H. Peter Anvin
@ 2007-12-17 21:02                                                       ` David P. Reed
  2007-12-17 21:17                                                         ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: David P. Reed @ 2007-12-17 21:02 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rene Herman, Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol



H. Peter Anvin wrote:
> David P. Reed wrote:
>> As support: port 80 on the reporter's (my) HP dv9000z laptop clearly 
>> responds to reads differently than "unused" ports.  In particular, an 
>> inb takes 1/2 the elapsed time compared to a read to "known" unused 
>> port 0xed - 792 tsc ticks for port 80 compared to about 1450 tsc 
>> ticks for port 0xed and other unused ports (tsc at 800 MHz).
>>
>
> Any timings for port 0xf0 (write zero), out of curiosity?
>

Here's a bunch of data:

port 0xF0: cycles: out 919, in 933
port 0xed: cycles: out 2541, in 2036
port 0x70: cycles: out n/a,  in 934
port 0x80: cycles: out 1424, in 795

AMD Turion 64x2 TL-60 CPU running at 800 MHz, nVidia MCP51 chipset, 
Quanta motherboard.  Running 2.6.24-rc5 with Ingo's patch so inb_p, etc. 
use port 0xed.

Note that I can run the port 80 test once, the second time I get the 
hard freeze.  I didn't try writing to port 70 from userspace - that 
one's dangerous, but the reading of it was included for a timing typical 
of a chipset supported device.  These are all pretty consistent.

I find the "read" timing from 0x80 verrrrry interesting.  The write 
timeing is also interesting, being faster than an unused port. 



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 20:48                                                       ` Rene Herman
@ 2007-12-17 20:57                                                         ` H. Peter Anvin
  2007-12-17 21:33                                                           ` Rene Herman
  2007-12-17 21:41                                                         ` Ingo Molnar
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17 20:57 UTC (permalink / raw)
  To: Rene Herman
  Cc: Alan Cox, Ingo Molnar, David P. Reed, Paul Rolland, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> On 17-12-07 17:12, Alan Cox wrote:
> 
>> I don't think we should be offering udelay based delays at this point.
>> There are a lot of drivers to fix first. This is just one trivial example
> 
> I agree. This thread's too full of people calling this outb method a 
> dumb hack. It's a well-known legacy PC thing and while in practice the 
> udelay might be a functional replacement for a majority of cases (save 
> the races you are finding) a delay proportional to the bus speed makes 
> great sense certainly when talking to hardware that itself runs 
> proportinal to the bus speed for example.
> 
> So, really, how about just sticking in this minimal version for now? 
> Only switches the port to 0xed based on DMI and is all that is needed to 
> fix the actual problem. This should be minimal and no-risk enough that 
> it could also go to .24 if people want it to. It'll fix a few HP laptops 
> (I'll try and get/verify the dv6000z DMI strings as well).
> 

I think retaining the command-line option available is a good thing, 
though.  If nothing else, it is something very quick we can ask other 
people to try if they seem to have similar problems.

Other than that, this alternate-port patch is a low-impact patch not 
affecting hardware not on the blacklist, which makes it appropriate for 
2.6.24 IMO.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 16:12                                                     ` Alan Cox
  2007-12-17 16:48                                                       ` Ingo Molnar
@ 2007-12-17 20:48                                                       ` Rene Herman
  2007-12-17 20:57                                                         ` H. Peter Anvin
  2007-12-17 21:41                                                         ` Ingo Molnar
  1 sibling, 2 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17 20:48 UTC (permalink / raw)
  To: Alan Cox
  Cc: Ingo Molnar, David P. Reed, H. Peter Anvin, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 988 bytes --]

On 17-12-07 17:12, Alan Cox wrote:

> I don't think we should be offering udelay based delays at this point.
> There are a lot of drivers to fix first. This is just one trivial example

I agree. This thread's too full of people calling this outb method a dumb 
hack. It's a well-known legacy PC thing and while in practice the udelay 
might be a functional replacement for a majority of cases (save the races 
you are finding) a delay proportional to the bus speed makes great sense 
certainly when talking to hardware that itself runs proportinal to the bus 
speed for example.

So, really, how about just sticking in this minimal version for now? Only 
switches the port to 0xed based on DMI and is all that is needed to fix the 
actual problem. This should be minimal and no-risk enough that it could also 
go to .24 if people want it to. It'll fix a few HP laptops (I'll try and 
get/verify the dv6000z DMI strings as well).

Ingo?

Signed-off-by: Rene Herman <rene.herman@gmail.com>

[-- Attachment #2: dmi-port80-minimal.diff --]
[-- Type: text/plain, Size: 9464 bytes --]

commit e5f4d11c2470550500e8d8b798d902f2fe07b5c4
Author: Rene Herman <rene.herman@gmail.com>
Date:   Mon Dec 17 21:23:55 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP) laptops experience trouble from our port 0x80 I/O delay
    writes. This patch provides for a DMI based switch to the "alternate
    diagnostic port" 0xed (as used by some BIOSes as well) for these.
    
    David P. Reed confirmed that port 0xed works for him and provides a
    proper delay. The symptoms of _not_ working are a hanging machine,
    with "hwclock" use being a direct trigger.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist, but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but still leaves:
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally various drivers are racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as tested by David P. Reed. He moreover reported that booting with
    "acpi=off" also fixed things and seeing as how ACPI isn't touched
    until after this DMI based I/O port switch leaving the ones in the
    boot code be is safe.
    
    The DMI strings from David's HP Pavilion dv9000z are in there already
    and we need to get/verify the DMI info from other machines with the
    problem, notably the HP Pavilion dv6000z.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>

diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..e736bab
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,48 @@
+/*
+ * I/O delay strategies for inb_p/outb_p
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+/*
+ * Allow for a DMI based override of port 0x80
+ */
+#define IO_DELAY_PORT_STD 0x80
+#define IO_DELAY_PORT_ALT 0xed
+
+static unsigned short io_delay_port __read_mostly = IO_DELAY_PORT_STD;
+
+void native_io_delay(void)
+{
+	asm volatile ("outb %%al, %w0" : : "d" (io_delay_port));
+}
+EXPORT_SYMBOL(native_io_delay);
+
+static int __init dmi_io_delay_port_alt(const struct dmi_system_id *id)
+{
+	printk(KERN_NOTICE "%s: using alternate I/O delay port\n", id->ident);
+	io_delay_port = IO_DELAY_PORT_ALT;
+	return 0;
+}
+
+static struct dmi_system_id __initdata dmi_io_delay_port_alt_table[] = {
+	{
+		.callback	= dmi_io_delay_port_alt,
+		.ident		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{
+	}
+};
+
+void __init io_delay_init(void)
+{
+	dmi_check_system(dmi_io_delay_port_alt_table);
+}
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..690b8f4 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..b2d4994 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,18 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
+static inline void slow_down_io(void)
+{
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +55,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \

^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 19:43                                                   ` David P. Reed
@ 2007-12-17 19:55                                                     ` H. Peter Anvin
  2007-12-17 21:02                                                       ` David P. Reed
  2007-12-17 21:25                                                     ` Alan Cox
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17 19:55 UTC (permalink / raw)
  To: David P. Reed
  Cc: Rene Herman, Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

David P. Reed wrote:
> H. Peter Anvin wrote:
>> Rene Herman wrote:
>>>
>>> I do not know how universal that is, but _reading_ port 0xf0 might in 
>>> fact be sensible then? And should even work on a 386/387 pair? (I 
>>> have a 386/387 in fact, although I'd need to dig it up).
>>>
>>
>> No.  Someone might have used 0xf0 as a readonly port for other uses.
>>
> As support: port 80 on the reporter's (my) HP dv9000z laptop clearly 
> responds to reads differently than "unused" ports.  In particular, an 
> inb takes 1/2 the elapsed time compared to a read to "known" unused port 
> 0xed - 792 tsc ticks for port 80 compared to about 1450 tsc ticks for 
> port 0xed and other unused ports (tsc at 800 MHz).
> 

Any timings for port 0xf0 (write zero), out of curiosity?

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 19:38                                                     ` David P. Reed
@ 2007-12-17 19:55                                                       ` H. Peter Anvin
  2007-12-17 21:28                                                       ` Ingo Molnar
  1 sibling, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17 19:55 UTC (permalink / raw)
  To: David P. Reed
  Cc: Ingo Molnar, Rene Herman, Paul Rolland, Alan Cox, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

David P. Reed wrote:
> 
> Still wondering:
> 
>    what the heck is going on with port 80 on my laptop motherboard.  
> Clearly it "does something".
>    I will in my spare time continue investigating, though having a 
> reliable system is GREAT.
> 

Almost guaranteed to be some kind of debugging hack, probably 
implemented either in the SuperIO chip or in SMM (or both).  When some 
sort of log buffer fills up, the system dies.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 17:14                                                 ` H. Peter Anvin
@ 2007-12-17 19:43                                                   ` David P. Reed
  2007-12-17 19:55                                                     ` H. Peter Anvin
  2007-12-17 21:25                                                     ` Alan Cox
  0 siblings, 2 replies; 186+ messages in thread
From: David P. Reed @ 2007-12-17 19:43 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rene Herman, Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

H. Peter Anvin wrote:
> Rene Herman wrote:
>>
>> I do not know how universal that is, but _reading_ port 0xf0 might in 
>> fact be sensible then? And should even work on a 386/387 pair? (I 
>> have a 386/387 in fact, although I'd need to dig it up).
>>
>
> No.  Someone might have used 0xf0 as a readonly port for other uses.
>
As support: port 80 on the reporter's (my) HP dv9000z laptop clearly 
responds to reads differently than "unused" ports.  In particular, an 
inb takes 1/2 the elapsed time compared to a read to "known" unused port 
0xed - 792 tsc ticks for port 80 compared to about 1450 tsc ticks for 
port 0xed and other unused ports (tsc at 800 MHz).


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 14:39                                                   ` Ingo Molnar
  2007-12-17 16:12                                                     ` Alan Cox
@ 2007-12-17 19:38                                                     ` David P. Reed
  2007-12-17 19:55                                                       ` H. Peter Anvin
  2007-12-17 21:28                                                       ` Ingo Molnar
  1 sibling, 2 replies; 186+ messages in thread
From: David P. Reed @ 2007-12-17 19:38 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rene Herman, H. Peter Anvin, Paul Rolland, Alan Cox,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Ingo -

I finished testing the rolled up patch that you provided.  It seems to 
work just fine.  Thank you for putting this all together and persevering 
in this long and complex discussion. 

Here are the results, on the offending laptop, using 2.6.24-rc5 plus 
that one patch.

First: booted with normal boot parameters (no io_delay=):

    According to dmesg, 0xed is used.

    hwclock ran fine, hundreds of times.
    my shell script loop doing "cat /dev/nvram > /dev/null" ran fine, 
several times.
    Running Rene's "port 80" speed test ran fine once, then froze the 
system hard.  (expected)

Second: booted with io_delay=0x80, several tests, rebooting after freezes:

    hwclock froze system hard.  (this is the problem that drove me to 
find this bug).
    my shell script loop froze system hard.

Third: booted with io_delay=none:

    hwclock ran fine, also hundreds of times.
    my shell script loop ran fine several times.
    Running rene's port80 test ran fine twice, froze system hard on 
third try.

Fourth: booted with io_delay=udelay:

    hwclock ran fine, also hundreds of times.
    my shell script loop ran fine several times.
    Running Rene's port80 test ran fine, froze system hard on second try.

Analysis:

    patch works fine, and default to 0xed seems super conservative.
    I will probably use the boot parameter io_delay=none, because I 
don't seem to have any I/O
    devices that require any delays - and this way I can find any that do.

Still wondering:

    what the heck is going on with port 80 on my laptop motherboard.  
Clearly it "does something".
    I will in my spare time continue investigating, though having a 
reliable system is GREAT.




   


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:02                                               ` Rene Herman
@ 2007-12-17 17:14                                                 ` H. Peter Anvin
  2007-12-17 19:43                                                   ` David P. Reed
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17 17:14 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> 
> I do not know how universal that is, but _reading_ port 0xf0 might in 
> fact be sensible then? And should even work on a 386/387 pair? (I have a 
> 386/387 in fact, although I'd need to dig it up).
> 

No.  Someone might have used 0xf0 as a readonly port for other uses.

	-hpa


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 16:12                                                     ` Alan Cox
@ 2007-12-17 16:48                                                       ` Ingo Molnar
  2007-12-17 20:48                                                       ` Rene Herman
  1 sibling, 0 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 16:48 UTC (permalink / raw)
  To: Alan Cox
  Cc: David P. Reed, Rene Herman, H. Peter Anvin, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:

> I don't think we should be offering udelay based delays at this point. 
> There are a lot of drivers to fix first. This is just one trivial 
> example
> 
> ...
> 
> --- drivers/watchdog/wdt.c~	2007-12-17 15:58:49.000000000 +0000
> +++ drivers/watchdog/wdt.c	2007-12-17 15:58:49.000000000 +0000
> @@ -70,6 +70,8 @@
>  static int io=0x240;
>  static int irq=11;
>  
> +static DEFINE_SPINLOCK(wdt_lock);
> +
>  module_param(io, int, 0);
>  MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
>  module_param(irq, int, 0);
> @@ -109,6 +111,8 @@
>  
>  static int wdt_start(void)
>  {
> +	unsigned long flags;
> +	spin_lock_irqsave(&wdt_lock, flags);
>  	inb_p(WDT_DC);			/* Disable watchdog */
>  	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3:

a really stupid question, in what way does:

  inb_p(WDT_DC);

work better than:

  inb(WDT_DC);
  delay(2);

?

(i'm not suggesting you are wrong, this detail just fails to click at 
the moment.)

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 14:39                                                   ` Ingo Molnar
@ 2007-12-17 16:12                                                     ` Alan Cox
  2007-12-17 16:48                                                       ` Ingo Molnar
  2007-12-17 20:48                                                       ` Rene Herman
  2007-12-17 19:38                                                     ` David P. Reed
  1 sibling, 2 replies; 186+ messages in thread
From: Alan Cox @ 2007-12-17 16:12 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: David P. Reed, Rene Herman, H. Peter Anvin, Paul Rolland,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

I don't think we should be offering udelay based delays at this point.
There are a lot of drivers to fix first. This is just one trivial example

...

--- drivers/watchdog/wdt.c~	2007-12-17 15:58:49.000000000 +0000
+++ drivers/watchdog/wdt.c	2007-12-17 15:58:49.000000000 +0000
@@ -70,6 +70,8 @@
 static int io=0x240;
 static int irq=11;
 
+static DEFINE_SPINLOCK(wdt_lock);
+
 module_param(io, int, 0);
 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
 module_param(irq, int, 0);
@@ -109,6 +111,8 @@
 
 static int wdt_start(void)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
 	inb_p(WDT_DC);			/* Disable watchdog */
 	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3:
Square Wave Generator */ wdt_ctr_mode(1,2);		/* Program
CTR1 for Mode 2: Rate Generator */ @@ -117,6 +121,7 @@
 	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
 	wdt_ctr_load(2,65535);		/* Length of reset pulse */
 	outb_p(0, WDT_DC);		/* Enable watchdog */
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	return 0;
 }
 
@@ -128,9 +133,12 @@
 
 static int wdt_stop (void)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
 	/* Turn the card off */
 	inb_p(WDT_DC);			/* Disable watchdog */
 	wdt_ctr_load(2,0);		/* 0 length reset pulses now */
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	return 0;
 }
 
@@ -143,11 +151,14 @@
 
 static int wdt_ping(void)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
 	/* Write a watchdog value */
 	inb_p(WDT_DC);			/* Disable watchdog */
 	wdt_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2:
Rate Generator */ wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
 	outb_p(0, WDT_DC);		/* Enable watchdog */
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	return 0;
 }
 
@@ -182,7 +193,12 @@
 
 static int wdt_get_status(int *status)
 {
-	unsigned char new_status=inb_p(WDT_SR);
+	unsigned char new_status;
+	unsigned long flags;
+
+	spinlock_irqsave(&wdt_lock, flags);	
+	new_status = inb_p(WDT_SR);
+	spin_unlock_irqrestore(&wdt_lock, flags);
 
 	*status=0;
 	if (new_status & WDC_SR_ISOI0)
@@ -214,8 +230,12 @@
 
 static int wdt_get_temperature(int *temperature)
 {
-	unsigned short c=inb_p(WDT_RT);
+	unsigned short c;
+	unsigned long flags;
 
+	spinlock_irqsave(&wdt_lock, flags);	
+	c=inb_p(WDT_RT);
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	*temperature = (c * 11 / 15) + 7;
 	return 0;
 }
@@ -237,7 +257,10 @@
 	 *	Read the status register see what is up and
 	 *	then printk it.
 	 */
-	unsigned char status=inb_p(WDT_SR);
+	unsigned char status;
+	
+	spin_lock(&wdt_lock);
+	status = inb_p(WDT_SR);
 
 	printk(KERN_CRIT "WDT status %d\n", status);
 
@@ -265,6 +288,7 @@
 		printk(KERN_CRIT "Reset in 5ms.\n");
 #endif
 	}
+	spin_unlock(&wdt_lock);
 	return IRQ_HANDLED;
 }
 

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:32                                                 ` David P. Reed
  2007-12-17 13:36                                                   ` Rene Herman
@ 2007-12-17 14:39                                                   ` Ingo Molnar
  2007-12-17 16:12                                                     ` Alan Cox
  2007-12-17 19:38                                                     ` David P. Reed
  1 sibling, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 14:39 UTC (permalink / raw)
  To: David P. Reed
  Cc: Rene Herman, H. Peter Anvin, Paul Rolland, Alan Cox,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* David P. Reed <dpreed@reed.com> wrote:

> Rene Herman wrote:
>> No, most definitely not. Having the user select udelay or none through the 
>> kernel config and then the kernel deciding "ah, you know what, I'll know 
>> better and use port access anyway" is _utterly_ broken behaviour. Software 
>> needs to listen to its master.
>
> When acting as an ordinary user, the .config is beyond my control 
> (except on Gentoo).  It is in control of the distro (Fedora, Ubuntu, 
> ... but perhaps not Gentoo).  I think the distro guys want a default 
> behavior that is set in .config, with quirk overrides being done when 
> needed.  And of course the user in his/her boot params gets the final 
> say.

yeah, that's exactly the thinking. Distros basically set general policy, 
but a quirk is (almost) always specific and correct enough to override 
that. We could perhaps refine this by directing the quirk to only be 
applied if the current type is 0x80 - because in that case we know that 
it's definitely not going to work. I.e. something like the small patch 
below?

	Ingo

---
 arch/x86/kernel/io_delay.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Index: linux-x86.q/arch/x86/kernel/io_delay.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/io_delay.c
+++ linux-x86.q/arch/x86/kernel/io_delay.c
@@ -47,8 +47,11 @@ EXPORT_SYMBOL(native_io_delay);
 
 static int __init dmi_io_delay_0xed_port(const struct dmi_system_id *id)
 {
-	printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", id->ident);
-	io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
+	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;
 }

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:32                                                 ` David P. Reed
@ 2007-12-17 13:36                                                   ` Rene Herman
  2007-12-17 14:39                                                   ` Ingo Molnar
  1 sibling, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17 13:36 UTC (permalink / raw)
  To: David P. Reed
  Cc: Ingo Molnar, H. Peter Anvin, Paul Rolland, Alan Cox,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 14:32, David P. Reed wrote:

> Rene Herman wrote:
>> No, most definitely not. Having the user select udelay or none through 
>> the kernel config and then the kernel deciding "ah, you know what, 
>> I'll know better and use port access anyway" is _utterly_ broken 
>> behaviour. Software needs to listen to its master.
>>
> When acting as an ordinary user, the .config is beyond my control 
> (except on Gentoo).   It is in control of the distro (Fedora, Ubuntu, 
> ... but perhaps not Gentoo).  I think the distro guys want a default 
> behavior that is set in .config, with quirk overrides being done when 
> needed.   And of course the user in his/her boot params gets the final say.

Yes, and when the user/distributor specifically selected udelay or none as 
an I/O delay method it makes no sense whatsoever to have the kernel override 
that again -- the DMI hack only fixes something for the default case, when 
_no_ specific choice had been made (which the current setup can't express 
but mine did).

I feel particularly strongly (always) about that "listen to its master" bit. 
The kernel does not know better then whomever configured it, even when it does.

Rene.



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 11:29                                           ` Ingo Molnar
@ 2007-12-17 13:34                                             ` David P. Reed
  0 siblings, 0 replies; 186+ messages in thread
From: David P. Reed @ 2007-12-17 13:34 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Rene Herman, H. Peter Anvin, Paul Rolland, Alan Cox,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

About to start building and testing.  It will take a few hours.

Ingo Molnar wrote:
> here's an updated rollup patch, against 2.6.24-rc4. David, could you 
> please try this? This should work out of box on your system, without any 
> boot option or other tweak needed.
>
>
>   

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:22                                               ` Rene Herman
  2007-12-17 13:31                                                 ` Pavel Machek
@ 2007-12-17 13:32                                                 ` David P. Reed
  2007-12-17 13:36                                                   ` Rene Herman
  2007-12-17 14:39                                                   ` Ingo Molnar
  1 sibling, 2 replies; 186+ messages in thread
From: David P. Reed @ 2007-12-17 13:32 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, H. Peter Anvin, Paul Rolland, Alan Cox,
	Pavel Machek, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> No, most definitely not. Having the user select udelay or none through 
> the kernel config and then the kernel deciding "ah, you know what, 
> I'll know better and use port access anyway" is _utterly_ broken 
> behaviour. Software needs to listen to its master.
>
When acting as an ordinary user, the .config is beyond my control 
(except on Gentoo).   It is in control of the distro (Fedora, Ubuntu, 
... but perhaps not Gentoo).  I think the distro guys want a default 
behavior that is set in .config, with quirk overrides being done when 
needed.   And of course the user in his/her boot params gets the final say.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:22                                               ` Rene Herman
@ 2007-12-17 13:31                                                 ` Pavel Machek
  2007-12-17 13:31                                                   ` Rene Herman
  2007-12-17 13:32                                                 ` David P. Reed
  1 sibling, 1 reply; 186+ messages in thread
From: Pavel Machek @ 2007-12-17 13:31 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, H. Peter Anvin, Paul Rolland, Alan Cox,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On Mon 2007-12-17 14:22:26, Rene Herman wrote:
> On 17-12-07 14:09, Ingo Molnar wrote:
>
>>>> -#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;
>>>> +	printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", id->ident);
>>>> +	io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
>>>> +
>>>>  	return 0;
>>>>  }
>>> This isn't correct. DMI shouldn't override the CONFIG choice or someone 
>>> with matching DMI will have a defective CONFIG option. That's why I put 
>>> all of it inside #ifndef.
>> no, the DMI quirk is just that: a quirk that makes boxes work. The DMI 
>> quirk takes precedence over just about any .config default, except an 
>> explicit boot-commandline override.
>
> No, most definitely not. Having the user select udelay or none through the 
> kernel config and then the kernel deciding "ah, you know what, I'll know 
> better and use port access anyway" is _utterly_ broken behaviour. Software 
> needs to listen to its master.

That's what command line is for. Ingo is right here.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:31                                                 ` Pavel Machek
@ 2007-12-17 13:31                                                   ` Rene Herman
  0 siblings, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17 13:31 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Ingo Molnar, H. Peter Anvin, Paul Rolland, Alan Cox,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 14:31, Pavel Machek wrote:

> On Mon 2007-12-17 14:22:26, Rene Herman wrote:
>> On 17-12-07 14:09, Ingo Molnar wrote:
>>
>>>>> -#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;
>>>>> +	printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", id->ident);
>>>>> +	io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
>>>>> +
>>>>>  	return 0;
>>>>>  }
>>>> This isn't correct. DMI shouldn't override the CONFIG choice or someone 
>>>> with matching DMI will have a defective CONFIG option. That's why I put 
>>>> all of it inside #ifndef.
>>> no, the DMI quirk is just that: a quirk that makes boxes work. The DMI 
>>> quirk takes precedence over just about any .config default, except an 
>>> explicit boot-commandline override.
>> No, most definitely not. Having the user select udelay or none through the 
>> kernel config and then the kernel deciding "ah, you know what, I'll know 
>> better and use port access anyway" is _utterly_ broken behaviour. Software 
>> needs to listen to its master.
> 
> That's what command line is for. Ingo is right here.

No. The kernel shouldn't provide defective config options.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 13:09                                             ` Ingo Molnar
@ 2007-12-17 13:22                                               ` Rene Herman
  2007-12-17 13:31                                                 ` Pavel Machek
  2007-12-17 13:32                                                 ` David P. Reed
  0 siblings, 2 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17 13:22 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 14:09, Ingo Molnar wrote:

>>> -#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;
>>> +	printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", id->ident);
>>> +	io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
>>> +
>>>  	return 0;
>>>  }
>> This isn't correct. DMI shouldn't override the CONFIG choice or 
>> someone with matching DMI will have a defective CONFIG option. That's 
>> why I put all of it inside #ifndef.
> 
> no, the DMI quirk is just that: a quirk that makes boxes work. The DMI 
> quirk takes precedence over just about any .config default, except an 
> explicit boot-commandline override.

No, most definitely not. Having the user select udelay or none through the 
kernel config and then the kernel deciding "ah, you know what, I'll know 
better and use port access anyway" is _utterly_ broken behaviour. Software 
needs to listen to its master.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 12:15                                           ` Rene Herman
@ 2007-12-17 13:09                                             ` Ingo Molnar
  2007-12-17 13:22                                               ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 13:09 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Rene Herman <rene.herman@gmail.com> wrote:

> On 17-12-07 11:57, Ingo Molnar wrote:
>
>> thanks Rene! I've added your patch to x86.git. I changed a few things 
>> ontop of it, see the additional changelog and delta patch below.
>
> "appropriated it", more. [...]

huh?

> [...] Definitely not going to forgive you for deleting that comment.

Do you mean:

+/*
+ * High on a hill was a lonely goatherd
+ */

?

>>  void native_io_delay(void)
>>  {
>> -	io_delay();
>> +	switch (io_delay_type) {
>
> That's the clumsy bit. native_io_delay() used to be an inline outb, 
> now it's a switch. Yes, sure, versus an indirect call it's not 
> actually worse, except as an uglification.

the switch enableds the sysctl. I dont see the callback as in any way 
cleaner. (in fact it made things more inflexible.)

>> -#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;
>> +	printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", id->ident);
>> +	io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
>> +
>>  	return 0;
>>  }
>
> This isn't correct. DMI shouldn't override the CONFIG choice or 
> someone with matching DMI will have a defective CONFIG option. That's 
> why I put all of it inside #ifndef.

no, the DMI quirk is just that: a quirk that makes boxes work. The DMI 
quirk takes precedence over just about any .config default, except an 
explicit boot-commandline override.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  3:35                                             ` H. Peter Anvin
@ 2007-12-17 13:02                                               ` Rene Herman
  2007-12-17 17:14                                                 ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17 13:02 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 04:35, H. Peter Anvin wrote:

> Well, we probably should leave the possibility in to use 0x80 -- for one 
> thing, we need to use 0x80 on 386, and there is always the possibility 
> that the switch will have different timing properties on some or all 
> machines.
> 
> Note that this doesn't require that a machine actually implements port 
> 0xf0 for FERR/IGNNE, it just requires that they don't use it for 
> something else.
> 
> I would be rather inclined to try using port 0xf0 by default as long as 
> family > 3[*] (with fallback to port 0x80) at least experimentally (-mm).

Possible timing differences would be what worry me. 0x80 is well-known for 
its delay purposes, and frankly, I dont believe that one type of machine 
having a problem, which may very well have to be categorized a possibly BIOS 
fixable bug, is enough ground for switching everyone over to a different port

It's enough ground to look at not doing outputs at all AFAIC but that's more 
due to the outb being somewhat cheesy to start with which using a different 
port wouldn't change. But, on the other hand:

> We *might* even be able to use port 0xf0 unconditionally in the setup 
> code, since we're not using the FPU there (the only FPU instructions in 
> the setup code are there to detect the FPU.)
> 
> One thing: although I believe most actual implementations of port 0xf0 
> implement it as a strobe alone (data is ignored), all documentation I've 
> found, including "The Undocumented PC" specifically says "write 0x00 to 
> this port."  This *could* mean there are platforms which use other 
> values than 0x00 for other hacks.

The Intel PIIX/PIIX3 datasheet confirms that the data is of no consequence, 
but yes, most documentation talks about 0.

The PIIX/PIIX3 datasheet also says that both reads and writes flow through 
to the ISA bus, while for port 0x80 only writes do, and reads do not.

I do not know how universal that is, but _reading_ port 0xf0 might in fact 
be sensible then? And should even work on a 386/387 pair? (I have a 386/387 
in fact, although I'd need to dig it up).

Versus the out it has the al clobber disadvantage, but givne that we're by 
now seem to be talking about out of line switch() native_io_delays anyways, 
that's not much of a problem anymore...

> [*] The following statements are equivalent:
>     - family > 3.
>     - CR0.NE is settable.
>     - EFLAGS.AC is settable.

For the boot code, I gather (which could I suppose then also plug in the 
delay port in the zero page or somewhere for use by the kernel proper? I 
don't know how/if these bits communicate).

But, well, _reading_ port 0xf0 sounds promising across the board and low 
risk replacement _if_ teh PIIX/PIIX3 behaviour is as guaranteed as the port 
0x80 behaviour...

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 10:57                                         ` Ingo Molnar
  2007-12-17 11:29                                           ` Ingo Molnar
@ 2007-12-17 12:15                                           ` Rene Herman
  2007-12-17 13:09                                             ` Ingo Molnar
  1 sibling, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17 12:15 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 11:57, Ingo Molnar wrote:

> thanks Rene! I've added your patch to x86.git. I changed a few things 
> ontop of it, see the additional changelog and delta patch below.

"appropriated it", more. Definitely not going to forgive you for deleting 
that comment.

>  void native_io_delay(void)
>  {
> -	io_delay();
> +	switch (io_delay_type) {

That's the clumsy bit. native_io_delay() used to be an inline outb, now it's 
a switch. Yes, sure, versus an indirect call it's not actually worse, except 
  as an uglification.

> -#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;
> +	printk(KERN_NOTICE "%s: using 0xed I/O delay port\n", id->ident);
> +	io_delay_type = CONFIG_IO_DELAY_TYPE_0XED;
> +
>  	return 0;
>  }

This isn't correct. DMI shouldn't override the CONFIG choice or someone with 
matching DMI will have a defective CONFIG option. That's why I put all of it 
inside #ifndef.

Rene.



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17 10:57                                         ` Ingo Molnar
@ 2007-12-17 11:29                                           ` Ingo Molnar
  2007-12-17 13:34                                             ` David P. Reed
  2007-12-17 12:15                                           ` Rene Herman
  1 sibling, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 11:29 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Ingo Molnar <mingo@elte.hu> wrote:

> > So how is this? Also fixes a few problems with the previous version.
> 
> thanks Rene! I've added your patch to x86.git. I changed a few things 
> ontop of it, see the additional changelog and delta patch below.

here's an updated rollup patch, against 2.6.24-rc4. David, could you 
please try this? This should work out of box on your system, without any 
boot option or other tweak needed.

	Ingo

------------------------->
Subject: x86: provide a DMI based port 0x80 I/O delay override.
From: Rene Herman <rene.herman@gmail.com>

x86: provide a DMI based port 0x80 I/O delay override.

Certain (HP) laptops experience trouble from our port 0x80 I/O delay
writes. This patch provides for a DMI based switch to the "alternate
diagnostic port" 0xed (as used by some BIOSes as well) for these.

David P. Reed confirmed that port 0xed works for him and provides a
proper delay. The symptoms of _not_ working are a hanging machine,
with "hwclock" use being a direct trigger.

Earlier versions of this attempted to simply use udelay(2), with the
2 being a value tested to be a nicely conservative upper-bound with
help from many on the linux-kernel mailinglist but that approach has
two problems.

First, pre-loops_per_jiffy calibration (which is post PIT init while
some implementations of the PIT are actually one of the historically
problematic devices that need the delay) udelay() isn't particularly
well-defined. We could initialise loops_per_jiffy conservatively (and
based on CPU family so as to not unduly delay old machines) which
would sort of work, but...

Second, delaying isn't the only effect that a write to port 0x80 has.
It's also a PCI posting barrier which some devices may be explicitly
or implicitly relying on. Alan Cox did a survey and found evidence
that additionally some drivers may be racy on SMP without the bus
locking outb.

Switching to an inb() makes the timing too unpredictable and as such,
this DMI based switch should be the safest approach for now. Any more
invasive changes should get more rigid testing first. It's moreover
only very few machines with the problem and a DMI based hack seems
to fit that situation.

This also introduces a command-line parameter "io_delay" to override
the DMI based choice again:

	io_delay=<0x80|0xed|udelay|none>

where 0x80 means using the standard port 0x80 and 0xed means the
alternate port 0xed.

All these methods can also be selected via the kernel .config,
and can be runtime tuned via /proc/sys/kernel/io_delay_type (for
debugging purposes).

The DMI strings from David's HP Pavilion dv9000z are in there already
and we need to get/verify the DMI info from other machines with the
problem, notably the HP Pavilion dv6000z.

This patch is partly based on earlier patches from Pavel Machek and
David P. Reed.

[ mingo@elte.hu:
  - add the io_delay=none method
  - make each method selectable from the kernel config
  - eliminate the indirect function calls
  - add the /proc/sys/kernel/io_delay_type sysctl
  - change 'standard' and 'alternate' to 0x80 and 0xed
  - make the io delay config not depend on CONFIG_DEBUG_KERNEL ]

Signed-off-by: Rene Herman <rene.herman@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 Documentation/kernel-parameters.txt |   10 +++
 arch/x86/Kconfig.debug              |   74 ++++++++++++++++++++++++++++
 arch/x86/boot/compressed/misc_32.c  |    8 +--
 arch/x86/boot/compressed/misc_64.c  |    8 +--
 arch/x86/kernel/Makefile_32         |    2 
 arch/x86/kernel/Makefile_64         |    2 
 arch/x86/kernel/io_delay.c          |   95 ++++++++++++++++++++++++++++++++++++
 arch/x86/kernel/setup_32.c          |    2 
 arch/x86/kernel/setup_64.c          |    2 
 include/asm-x86/io_32.h             |    8 +--
 include/asm-x86/io_64.h             |   29 ++++++----
 kernel/sysctl.c                     |    9 +++
 12 files changed, 224 insertions(+), 25 deletions(-)

Index: linux-x86.q/Documentation/kernel-parameters.txt
===================================================================
--- linux-x86.q.orig/Documentation/kernel-parameters.txt
+++ linux-x86.q/Documentation/kernel-parameters.txt
@@ -785,6 +785,16 @@ and is between 256 and 4096 characters. 
 			for translation below 32 bit and if not available
 			then look in the higher range.
 
+	io_delay=	[X86-32,X86-64] I/O delay method
+		0x80
+			Standard port 0x80 based delay
+		0xed
+			Alternate port 0xed based delay (needed on some systems)
+		udelay
+			Simple two microseconds delay
+		none
+			No delay
+
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
Index: linux-x86.q/arch/x86/Kconfig.debug
===================================================================
--- linux-x86.q.orig/arch/x86/Kconfig.debug
+++ linux-x86.q/arch/x86/Kconfig.debug
@@ -112,4 +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.
 
+#
+# 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
+	  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
Index: linux-x86.q/arch/x86/boot/compressed/misc_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_32.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
Index: linux-x86.q/arch/x86/boot/compressed/misc_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/boot/compressed/misc_64.c
+++ linux-x86.q/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
Index: linux-x86.q/arch/x86/kernel/Makefile_32
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/Makefile_32
+++ linux-x86.q/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
Index: linux-x86.q/arch/x86/kernel/Makefile_64
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/Makefile_64
+++ linux-x86.q/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
Index: linux-x86.q/arch/x86/kernel/io_delay.c
===================================================================
--- /dev/null
+++ linux-x86.q/arch/x86/kernel/io_delay.c
@@ -0,0 +1,95 @@
+/*
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
+EXPORT_SYMBOL_GPL(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)
+{
+	printk(KERN_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		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{ }
+};
+
+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 (!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);
Index: linux-x86.q/arch/x86/kernel/setup_32.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/setup_32.c
+++ linux-x86.q/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
Index: linux-x86.q/arch/x86/kernel/setup_64.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/setup_64.c
+++ linux-x86.q/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
Index: linux-x86.q/include/asm-x86/io_32.h
===================================================================
--- linux-x86.q.orig/include/asm-x86/io_32.h
+++ linux-x86.q/include/asm-x86/io_32.h
@@ -250,10 +250,10 @@ static inline void flush_write_buffers(v
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+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>
Index: linux-x86.q/include/asm-x86/io_64.h
===================================================================
--- linux-x86.q.orig/include/asm-x86/io_64.h
+++ linux-x86.q/include/asm-x86/io_64.h
@@ -35,13 +35,20 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+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();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +57,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
Index: linux-x86.q/kernel/sysctl.c
===================================================================
--- linux-x86.q.orig/kernel/sysctl.c
+++ linux-x86.q/kernel/sysctl.c
@@ -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);
@@ -683,6 +684,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)
 	{

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  1:43                                       ` Rene Herman
  2007-12-17  2:05                                         ` H. Peter Anvin
@ 2007-12-17 10:57                                         ` Ingo Molnar
  2007-12-17 11:29                                           ` Ingo Molnar
  2007-12-17 12:15                                           ` Rene Herman
  1 sibling, 2 replies; 186+ messages in thread
From: Ingo Molnar @ 2007-12-17 10:57 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Rene Herman <rene.herman@gmail.com> wrote:

> On 16-12-07 16:22, Ingo Molnar wrote:
>
>> looks good to me. Could you please also provide three more controls that i 
>> suggested earlier:
>>
>>  - a boot option enabling/disabling the udelay based code
>>  - a .config method of enabling/disabling the udelay based code
>>  - a sysctl to toggle it
>>
>> if we want to clean this all up we'll need as many controls as possible.
>
> This version does the boot and the .config option but not the sysctl. 
> It makes for clumsy code and I don't believe it provides for much 
> added value as soon as you have the boot option. I am moreover not 
> completely confident about things such as paravirt liking the 
> possibility of the native_io_delay being changed out from under them 
> at unpredictable times.
>
> So how is this? Also fixes a few problems with the previous version.

thanks Rene! I've added your patch to x86.git. I changed a few things 
ontop of it, see the additional changelog and delta patch below.

	Ingo

------------>

- 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 'standard' and 'alternate' to 0x80 and 0xed
- make the io delay config not depend on CONFIG_DEBUG_KERNEL

---
 Documentation/kernel-parameters.txt |   12 ++--
 arch/x86/Kconfig.debug              |   79 +++++++++++++++++++++++++--
 arch/x86/kernel/io_delay.c          |  103 ++++++++++++++++--------------------
 include/asm-x86/io_32.h             |    2 
 include/asm-x86/io_64.h             |    2 
 kernel/sysctl.c                     |    9 +++
 6 files changed, 138 insertions(+), 69 deletions(-)

Index: linux-x86.q/Documentation/kernel-parameters.txt
===================================================================
--- linux-x86.q.orig/Documentation/kernel-parameters.txt
+++ linux-x86.q/Documentation/kernel-parameters.txt
@@ -786,12 +786,14 @@ and is between 256 and 4096 characters. 
 			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
Index: linux-x86.q/arch/x86/Kconfig.debug
===================================================================
--- linux-x86.q.orig/arch/x86/Kconfig.debug
+++ linux-x86.q/arch/x86/Kconfig.debug
@@ -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
-	  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.
+	  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
Index: linux-x86.q/arch/x86/kernel/io_delay.c
===================================================================
--- linux-x86.q.orig/arch/x86/kernel/io_delay.c
+++ linux-x86.q/arch/x86/kernel/io_delay.c
@@ -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,83 @@
 #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
+int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE;
+EXPORT_SYMBOL_GPL(io_delay_type);
 
-/*
- * 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;
+	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;
 }
 
Index: linux-x86.q/include/asm-x86/io_32.h
===================================================================
--- linux-x86.q.orig/include/asm-x86/io_32.h
+++ linux-x86.q/include/asm-x86/io_32.h
@@ -259,6 +259,8 @@ static inline void io_delay_init(void)
 #endif
 extern void native_io_delay(void);
 
+extern int io_delay_type;
+
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
 #else
Index: linux-x86.q/include/asm-x86/io_64.h
===================================================================
--- linux-x86.q.orig/include/asm-x86/io_64.h
+++ linux-x86.q/include/asm-x86/io_64.h
@@ -44,6 +44,8 @@ static inline void io_delay_init(void)
 #endif
 extern void native_io_delay(void);
 
+extern int io_delay_type;
+
 static inline void slow_down_io(void)
 {
 	native_io_delay();
Index: linux-x86.q/kernel/sysctl.c
===================================================================
--- linux-x86.q.orig/kernel/sysctl.c
+++ linux-x86.q/kernel/sysctl.c
@@ -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);
@@ -683,6 +684,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)
 	{

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  2:19                                           ` Rene Herman
  2007-12-17  3:35                                             ` H. Peter Anvin
@ 2007-12-17  4:09                                             ` H. Peter Anvin
  1 sibling, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17  4:09 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> On 17-12-07 03:05, H. Peter Anvin wrote:
> 
>> Incidentally, I had the thought earlier today that port 0xf0 might be 
>> a suitable delay port.  It is used only by the 387-emulating-a-287 
>> hack for IRQ 13, which Linux doesn't use on 486+.
> 
> rene@7ixe4:~/src/port80$ su -c ./port80
> cycles: out 2400, in 2400
> rene@7ixe4:~/src/port80$ su -c ./portf0
> cycles: out 2400, in 2400
> 
> (Duron 1300)
> 
> I suppose you mean using it instead of port 0x80 always and not just as 
> an alternate port? For the latter 0xed is alright I guess...
> 

FWIW, the criterion used in the kernel for when to use IRQ 13 is:

         /*
          * External FPU? Set up irq13 if so, for
          * original braindamaged IBM FERR coupling.
          */
         if (boot_cpu_data.hard_math && !cpu_has_fpu)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                 setup_irq(FPU_IRQ, &fpu_irq);

In that case we can't actually use port 0xF0 (it is, however, safe to 
use it during setup, specifically before we can take our first FPU 
exception.)

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  2:19                                           ` Rene Herman
@ 2007-12-17  3:35                                             ` H. Peter Anvin
  2007-12-17 13:02                                               ` Rene Herman
  2007-12-17  4:09                                             ` H. Peter Anvin
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17  3:35 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> On 17-12-07 03:05, H. Peter Anvin wrote:
> 
>> Incidentally, I had the thought earlier today that port 0xf0 might be 
>> a suitable delay port.  It is used only by the 387-emulating-a-287 
>> hack for IRQ 13, which Linux doesn't use on 486+.
> 
> rene@7ixe4:~/src/port80$ su -c ./port80
> cycles: out 2400, in 2400
> rene@7ixe4:~/src/port80$ su -c ./portf0
> cycles: out 2400, in 2400
> 
> (Duron 1300)
> 
> I suppose you mean using it instead of port 0x80 always and not just as 
> an alternate port? For the latter 0xed is alright I guess...
> 

Well, we probably should leave the possibility in to use 0x80 -- for one 
thing, we need to use 0x80 on 386, and there is always the possibility 
that the switch will have different timing properties on some or all 
machines.

Note that this doesn't require that a machine actually implements port 
0xf0 for FERR/IGNNE, it just requires that they don't use it for 
something else.

I would be rather inclined to try using port 0xf0 by default as long as 
family > 3[*] (with fallback to port 0x80) at least experimentally (-mm).

We *might* even be able to use port 0xf0 unconditionally in the setup 
code, since we're not using the FPU there (the only FPU instructions in 
the setup code are there to detect the FPU.)

One thing: although I believe most actual implementations of port 0xf0 
implement it as a strobe alone (data is ignored), all documentation I've 
found, including "The Undocumented PC" specifically says "write 0x00 to 
this port."  This *could* mean there are platforms which use other 
values than 0x00 for other hacks.

	-hpa


[*] The following statements are equivalent:
     - family > 3.
     - CR0.NE is settable.
     - EFLAGS.AC is settable.


^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  2:05                                         ` H. Peter Anvin
@ 2007-12-17  2:19                                           ` Rene Herman
  2007-12-17  3:35                                             ` H. Peter Anvin
  2007-12-17  4:09                                             ` H. Peter Anvin
  0 siblings, 2 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17  2:19 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 03:05, H. Peter Anvin wrote:

> Incidentally, I had the thought earlier today that port 0xf0 might be a 
> suitable delay port.  It is used only by the 387-emulating-a-287 hack 
> for IRQ 13, which Linux doesn't use on 486+.

rene@7ixe4:~/src/port80$ su -c ./port80
cycles: out 2400, in 2400
rene@7ixe4:~/src/port80$ su -c ./portf0
cycles: out 2400, in 2400

(Duron 1300)

I suppose you mean using it instead of port 0x80 always and not just as an 
alternate port? For the latter 0xed is alright I guess...


Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  2:04                                         ` H. Peter Anvin
@ 2007-12-17  2:15                                           ` Rene Herman
  0 siblings, 0 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17  2:15 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: David P. Reed, Paul Rolland, Alan Cox, Pavel Machek, Ingo Molnar,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 17-12-07 03:04, H. Peter Anvin wrote:

> Rene Herman wrote:
>> On 17-12-07 00:12, David P. Reed wrote:
>>
>>> Rene Herman wrote:
>>>> David: I've plugged in your DMI values in this. Could you perhaps 
>>>> test this to confirm that it works for you?
>>>>
>>> Will test it by tomorrow morning.
>>
>> Might as well test the new version then. Ingo Molnar requested a few 
>> changes and this fixes a couple of problems as well.
>>
> 
> As far as I can tell, the code still uses udelay() before calibration if 
> io_delay=udelay?
> 
> Just so we're clear on that...

Yes. This patch is explicitly about the alternate port and not about udelay. 
  As discussed (and changelogged) the calibration is just one problem with 
PCI posting and possible SMP races the other ones. Ingo Molnar wanted it as 
a debugging thing already though.

Once we start discussing udelay() again I believe we should go with the 
simple per CPU-Family loops_per_jiffy initialization to fix that first 
problem (and I guess I could hack that in now) but then the bigger problem 
remains and will need a fair amount of testing at least and mostly on 
machines that are by now gathering dust in a few basements...

Rene



^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  1:43                                       ` Rene Herman
@ 2007-12-17  2:05                                         ` H. Peter Anvin
  2007-12-17  2:19                                           ` Rene Herman
  2007-12-17 10:57                                         ` Ingo Molnar
  1 sibling, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17  2:05 UTC (permalink / raw)
  To: Rene Herman
  Cc: Ingo Molnar, Paul Rolland, Alan Cox, Pavel Machek, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> On 16-12-07 16:22, Ingo Molnar wrote:
> 
>> looks good to me. Could you please also provide three more controls 
>> that i suggested earlier:
>>
>>  - a boot option enabling/disabling the udelay based code
>>  - a .config method of enabling/disabling the udelay based code
>>  - a sysctl to toggle it
>>
>> if we want to clean this all up we'll need as many controls as possible.
> 
> This version does the boot and the .config option but not the sysctl. It 
> makes for clumsy code and I don't believe it provides for much added 
> value as soon as you have the boot option. I am moreover not completely 
> confident about things such as paravirt liking the possibility of the 
> native_io_delay being changed out from under them at unpredictable times.
> 

Incidentally, I had the thought earlier today that port 0xf0 might be a 
suitable delay port.  It is used only by the 387-emulating-a-287 hack 
for IRQ 13, which Linux doesn't use on 486+.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  1:56                                       ` Rene Herman
@ 2007-12-17  2:04                                         ` H. Peter Anvin
  2007-12-17  2:15                                           ` Rene Herman
  0 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17  2:04 UTC (permalink / raw)
  To: Rene Herman
  Cc: David P. Reed, Paul Rolland, Alan Cox, Pavel Machek, Ingo Molnar,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> On 17-12-07 00:12, David P. Reed wrote:
> 
>> Rene Herman wrote:
>>> David: I've plugged in your DMI values in this. Could you perhaps 
>>> test this to confirm that it works for you?
>>>
>> Will test it by tomorrow morning.
> 
> Might as well test the new version then. Ingo Molnar requested a few 
> changes and this fixes a couple of problems as well.
> 

As far as I can tell, the code still uses udelay() before calibration if 
io_delay=udelay?

Just so we're clear on that...

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-16 23:12                                     ` David P. Reed
@ 2007-12-17  1:56                                       ` Rene Herman
  2007-12-17  2:04                                         ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17  1:56 UTC (permalink / raw)
  To: David P. Reed
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	Ingo Molnar, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 351 bytes --]

On 17-12-07 00:12, David P. Reed wrote:

> Rene Herman wrote:
>> David: I've plugged in your DMI values in this. Could you perhaps test 
>> this to confirm that it works for you?
>>
> Will test it by tomorrow morning.

Might as well test the new version then. Ingo Molnar requested a few changes 
and this fixes a couple of problems as well.

Rene.



[-- Attachment #2: dmi-io_delay2.diff --]
[-- Type: text/plain, Size: 12737 bytes --]

commit 5001121e449040aa9cc021f69bfb191662c13004
Author: Rene Herman <rene.herman@gmail.com>
Date:   Sun Dec 16 13:36:39 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP) laptops experience trouble from our port 0x80 I/O delay
    writes. This patch provides for a DMI based switch to the "alternate
    diagnostic port" 0xed (as used by some BIOSes as well) for these.
    
    David P. Reed confirmed that port 0xed works for him and provides a
    proper delay. The symptoms of _not_ working are a hanging machine,
    with "hwclock" use being a direct trigger.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but...
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally some drivers may be racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    This also introduces a command-line parameter "io_delay" to override
    the DMI based choice again:
    
    	io_delay=<standard|alternate>
    
    where "standard" means using the standard port 0x80 and "alternate"
    port 0xed.
    
    At the request of Ingo Molnar this retains the udelay method as a
    config (CONFIG_UDELAY_IO_DELAY) and command-line ("io_delay=udelay")
    choice for testing purposes as well.
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as David P. Reed reported the problem was already gone after using the
    udelay version. He moreover reported that booting with "acpi=off" also
    fixed things and seeing as how ACPI isn't touched until after this DMI
    based I/O port switch I believe it's safe to leave the ones in the boot
    code be.
    
    The DMI strings from David's HP Pavilion dv9000z are in there already
    and we need to get/verify the DMI info from other machines with the
    problem, notably the HP Pavilion dv6000z.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 33121d6..9dce154 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -785,6 +785,14 @@ and is between 256 and 4096 characters. It is defined in the file
 			for translation below 32 bit and if not available
 			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
+		udelay
+			Simple two microsecond delay
+
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 761ca7b..40aba67 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -112,4 +112,13 @@ 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
+	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.
+
 endmenu
diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..4d955e7
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,106 @@
+/*
+ * I/O delay strategies for inb_p/outb_p
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#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);
+}
+
+#ifndef CONFIG_UDELAY_IO_DELAY
+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.
+ */
+void native_io_delay(void)
+{
+	io_delay();
+}
+EXPORT_SYMBOL(native_io_delay);
+
+#ifndef CONFIG_UDELAY_IO_DELAY
+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);
+	io_delay = alternate_io_delay;
+	return 0;
+}
+
+static struct dmi_system_id __initdata alternate_io_delay_port_dmi_table[] = {
+	{
+		.callback	= dmi_alternate_io_delay_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);
+}
+#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;
+	else if (!strcmp(s, "udelay"))
+		io_delay = udelay_io_delay;
+	else
+		return -EINVAL;
+
+#ifndef CONFIG_UDELAY_IO_DELAY
+	io_delay_override = 1;
+#endif
+	return 0;
+}
+
+early_param("io_delay", io_delay_param);
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..a8d25c3 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,10 +250,14 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
+#ifndef CONFIG_UDELAY_IO_DELAY
+extern void io_delay_init(void);
+#else
+static inline void io_delay_init(void)
 {
-	asm volatile("outb %%al,$0x80" : : : "memory");
 }
+#endif
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..5bebaf9 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,24 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+#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);
 
+static inline void slow_down_io(void)
+{
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +61,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \

^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-17  1:48                                       ` Rene Herman
@ 2007-12-17  1:53                                         ` H. Peter Anvin
  0 siblings, 0 replies; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-17  1:53 UTC (permalink / raw)
  To: Rene Herman
  Cc: Paul Rolland, Alan Cox, Pavel Machek, Ingo Molnar, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> 
> Do you expect a BIOS update to be able to fix it? If so, I guess any DMI 
> hack should take BIOS version into account.
> 

Hard to know without knowing what it is.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-16 21:42                                     ` H. Peter Anvin
@ 2007-12-17  1:48                                       ` Rene Herman
  2007-12-17  1:53                                         ` H. Peter Anvin
  0 siblings, 1 reply; 186+ messages in thread
From: Rene Herman @ 2007-12-17  1:48 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Paul Rolland, Alan Cox, Pavel Machek, Ingo Molnar, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

On 16-12-07 22:42, H. Peter Anvin wrote:

> It probably comes down to which version is bigger (you probably also 
> want to try uninlining.)

slow_down_io() sort of needs to stay inline due to the REALLY_SLOW_IO thing. 
That stuff could use a cleanup, but that would be a diferent patch.

>> Thanks for the heads up (also saw the SMBIOS update to this) but those 
>> don't seem to be a problem in fact. David Reed has been running with 
>> the simple udelay(2) version of this and reported no more hangs. He 
>> moreover reported no trouble after booting with "acpi=off" meaning 
>> that things seem to be fine pre-acpi which the boot code (and this 
>> io_delay_init) is. So I believe we get to ignore those.
> 
> Okay, so there is something inside ACPI which tickles this.  Which 
> brings further credibility that it's activating a debugging hack, 
> probably inside the SuperIO/system controller chip.
> 
> It would be interesting to know exactly which part of ACPI triggers 
> this.  I bet it is a reference to system controller namespace.

Do you expect a BIOS update to be able to fix it? If so, I guess any DMI 
hack should take BIOS version into account.

Rene.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-16 15:22                                     ` Ingo Molnar
@ 2007-12-17  1:43                                       ` Rene Herman
  2007-12-17  2:05                                         ` H. Peter Anvin
  2007-12-17 10:57                                         ` Ingo Molnar
  0 siblings, 2 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-17  1:43 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 1427 bytes --]

On 16-12-07 16:22, Ingo Molnar wrote:

> looks good to me. Could you please also provide three more controls that 
> i suggested earlier:
> 
>  - a boot option enabling/disabling the udelay based code
>  - a .config method of enabling/disabling the udelay based code
>  - a sysctl to toggle it
> 
> if we want to clean this all up we'll need as many controls as possible.

This version does the boot and the .config option but not the sysctl. It 
makes for clumsy code and I don't believe it provides for much added value 
as soon as you have the boot option. I am moreover not completely confident 
about things such as paravirt liking the possibility of the native_io_delay 
being changed out from under them at unpredictable times.

So how is this? Also fixes a few problems with the previous version.

  Documentation/kernel-parameters.txt |    8 ++
  arch/x86/Kconfig.debug              |    9 +++
  arch/x86/boot/compressed/misc_32.c  |    8 +-
  arch/x86/boot/compressed/misc_64.c  |    8 +-
  arch/x86/kernel/Makefile_32         |    2
  arch/x86/kernel/Makefile_64         |    2
  arch/x86/kernel/io_delay.c          |  103 
++++++++++++++++++++++++++++++++++++
  arch/x86/kernel/setup_32.c          |    2
  arch/x86/kernel/setup_64.c          |    2
  include/asm-x86/io_32.h             |    6 --
  include/asm-x86/io_64.h             |   27 +++++----
  11 files changed, 152 insertions(+), 25 deletions(-)

Rene.

[-- Attachment #2: dmi-io_delay2.diff --]
[-- Type: text/plain, Size: 12737 bytes --]

commit 5001121e449040aa9cc021f69bfb191662c13004
Author: Rene Herman <rene.herman@gmail.com>
Date:   Sun Dec 16 13:36:39 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP) laptops experience trouble from our port 0x80 I/O delay
    writes. This patch provides for a DMI based switch to the "alternate
    diagnostic port" 0xed (as used by some BIOSes as well) for these.
    
    David P. Reed confirmed that port 0xed works for him and provides a
    proper delay. The symptoms of _not_ working are a hanging machine,
    with "hwclock" use being a direct trigger.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but...
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally some drivers may be racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    This also introduces a command-line parameter "io_delay" to override
    the DMI based choice again:
    
    	io_delay=<standard|alternate>
    
    where "standard" means using the standard port 0x80 and "alternate"
    port 0xed.
    
    At the request of Ingo Molnar this retains the udelay method as a
    config (CONFIG_UDELAY_IO_DELAY) and command-line ("io_delay=udelay")
    choice for testing purposes as well.
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as David P. Reed reported the problem was already gone after using the
    udelay version. He moreover reported that booting with "acpi=off" also
    fixed things and seeing as how ACPI isn't touched until after this DMI
    based I/O port switch I believe it's safe to leave the ones in the boot
    code be.
    
    The DMI strings from David's HP Pavilion dv9000z are in there already
    and we need to get/verify the DMI info from other machines with the
    problem, notably the HP Pavilion dv6000z.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 33121d6..9dce154 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -785,6 +785,14 @@ and is between 256 and 4096 characters. It is defined in the file
 			for translation below 32 bit and if not available
 			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
+		udelay
+			Simple two microsecond delay
+
 	io7=		[HW] IO7 for Marvel based alpha systems
 			See comment before marvel_specify_io7 in
 			arch/alpha/kernel/core_marvel.c.
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 761ca7b..40aba67 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -112,4 +112,13 @@ 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
+	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.
+
 endmenu
diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..4d955e7
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,106 @@
+/*
+ * I/O delay strategies for inb_p/outb_p
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#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);
+}
+
+#ifndef CONFIG_UDELAY_IO_DELAY
+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.
+ */
+void native_io_delay(void)
+{
+	io_delay();
+}
+EXPORT_SYMBOL(native_io_delay);
+
+#ifndef CONFIG_UDELAY_IO_DELAY
+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);
+	io_delay = alternate_io_delay;
+	return 0;
+}
+
+static struct dmi_system_id __initdata alternate_io_delay_port_dmi_table[] = {
+	{
+		.callback	= dmi_alternate_io_delay_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);
+}
+#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;
+	else if (!strcmp(s, "udelay"))
+		io_delay = udelay_io_delay;
+	else
+		return -EINVAL;
+
+#ifndef CONFIG_UDELAY_IO_DELAY
+	io_delay_override = 1;
+#endif
+	return 0;
+}
+
+early_param("io_delay", io_delay_param);
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..a8d25c3 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,10 +250,14 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
+#ifndef CONFIG_UDELAY_IO_DELAY
+extern void io_delay_init(void);
+#else
+static inline void io_delay_init(void)
 {
-	asm volatile("outb %%al,$0x80" : : : "memory");
 }
+#endif
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..5bebaf9 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,24 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+#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);
 
+static inline void slow_down_io(void)
+{
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
+}
 
 /*
  * Talk about misusing macros..
@@ -50,21 +61,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \

^ permalink raw reply related	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-16 13:15                                   ` [PATCH] x86: provide a DMI based port 0x80 I/O delay override Rene Herman
  2007-12-16 15:22                                     ` Ingo Molnar
  2007-12-16 21:42                                     ` H. Peter Anvin
@ 2007-12-16 23:12                                     ` David P. Reed
  2007-12-17  1:56                                       ` Rene Herman
  2 siblings, 1 reply; 186+ messages in thread
From: David P. Reed @ 2007-12-16 23:12 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	Ingo Molnar, Thomas Gleixner, linux-kernel, Ingo Molnar, rol



Rene Herman wrote:
> David: I've plugged in your DMI values in this. Could you perhaps test 
> this to confirm that it works for you?
>
Will test it by tomorrow morning.

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-16 13:15                                   ` [PATCH] x86: provide a DMI based port 0x80 I/O delay override Rene Herman
  2007-12-16 15:22                                     ` Ingo Molnar
@ 2007-12-16 21:42                                     ` H. Peter Anvin
  2007-12-17  1:48                                       ` Rene Herman
  2007-12-16 23:12                                     ` David P. Reed
  2 siblings, 1 reply; 186+ messages in thread
From: H. Peter Anvin @ 2007-12-16 21:42 UTC (permalink / raw)
  To: Rene Herman
  Cc: Paul Rolland, Alan Cox, Pavel Machek, Ingo Molnar, David P. Reed,
	Thomas Gleixner, linux-kernel, Ingo Molnar, rol

Rene Herman wrote:
> 
> Well, I suppose. With stuff inline, constantly reloading dx also bloats 
> things up a bit but yes, out of line who cares. Do you think this 
> version is better?
> 

It probably comes down to which version is bigger (you probably also 
want to try uninlining.)

>> In the boot code, io_delay() is used to slow down accesses to the KBC, 
>> interrupt controller, INT13h logic, and the NMI gate, and to provide a 
>> fixed delay during A20 stabilization.
> 
> Thanks for the heads up (also saw the SMBIOS update to this) but those 
> don't seem to be a problem in fact. David Reed has been running with the 
> simple udelay(2) version of this and reported no more hangs. He moreover 
> reported no trouble after booting with "acpi=off" meaning that things 
> seem to be fine pre-acpi which the boot code (and this io_delay_init) 
> is. So I believe we get to ignore those.

Okay, so there is something inside ACPI which tickles this.  Which 
brings further credibility that it's activating a debugging hack, 
probably inside the SuperIO/system controller chip.

It would be interesting to know exactly which part of ACPI triggers 
this.  I bet it is a reference to system controller namespace.

	-hpa

^ permalink raw reply	[flat|nested] 186+ messages in thread

* Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-16 13:15                                   ` [PATCH] x86: provide a DMI based port 0x80 I/O delay override Rene Herman
@ 2007-12-16 15:22                                     ` Ingo Molnar
  2007-12-17  1:43                                       ` Rene Herman
  2007-12-16 21:42                                     ` H. Peter Anvin
  2007-12-16 23:12                                     ` David P. Reed
  2 siblings, 1 reply; 186+ messages in thread
From: Ingo Molnar @ 2007-12-16 15:22 UTC (permalink / raw)
  To: Rene Herman
  Cc: H. Peter Anvin, Paul Rolland, Alan Cox, Pavel Machek,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol


* Rene Herman <rene.herman@gmail.com> wrote:

> Any ACKs, NAKs or further comments from others in this thread also 
> welcome.

looks good to me. Could you please also provide three more controls that 
i suggested earlier:

 - a boot option enabling/disabling the udelay based code
 - a .config method of enabling/disabling the udelay based code
 - a sysctl to toggle it

if we want to clean this all up we'll need as many controls as possible.

	Ingo

^ permalink raw reply	[flat|nested] 186+ messages in thread

* [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
  2007-12-15 23:51                                 ` H. Peter Anvin
@ 2007-12-16 13:15                                   ` Rene Herman
  2007-12-16 15:22                                     ` Ingo Molnar
                                                       ` (2 more replies)
  0 siblings, 3 replies; 186+ messages in thread
From: Rene Herman @ 2007-12-16 13:15 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Rene Herman, Paul Rolland, Alan Cox, Pavel Machek, Ingo Molnar,
	David P. Reed, Thomas Gleixner, linux-kernel, Ingo Molnar, rol

[-- Attachment #1: Type: text/plain, Size: 2355 bytes --]

On 16-12-07 00:51, H. Peter Anvin wrote:

> Rene Herman wrote:
>>
>> I hope this is considered half-way correct/sane (note by the way that 
>> it's not a good idea to switch a "native_io_delay_port" value since 
>> plugging in a variable port would clobber register dx for every 
>> outb_p, which would then have to be reloaded for the next outb again). 
>> Comments appreciated.
> 
> That actually wouldn't be that big of a deal.  Switching values in and 
> out of registers is dirt cheap (and MUCH cheaper than an indirect 
> function call)

Well, I suppose. With stuff inline, constantly reloading dx also bloats 
things up a bit but yes, out of line who cares. Do you think this version is 
better?

> Note, however, that your code doesn't deal with io_delay()'s in the boot 
> code (arch/x86/boot) at all, nor (obviously) io_delay()'s in boot 
> loaders.  In the boot code, access to DMI data is NOT available (we 
> can't even use the INT 15h mover if we want to continue to support 
> Loadlin.)
> 
> In the boot code, io_delay() is used to slow down accesses to the KBC, 
> interrupt controller, INT13h logic, and the NMI gate, and to provide a 
> fixed delay during A20 stabilization.

Thanks for the heads up (also saw the SMBIOS update to this) but those don't 
seem to be a problem in fact. David Reed has been running with the simple 
udelay(2) version of this and reported no more hangs. He moreover reported 
no trouble after booting with "acpi=off" meaning that things seem to be fine 
pre-acpi which the boot code (and this io_delay_init) is. So I believe we 
get to ignore those.

David: I've plugged in your DMI values in this. Could you perhaps test this 
to confirm that it works for you?

Any ACKs, NAKs or further comments from others in this thread also welcome.

Changelog in the patch.

  arch/x86/boot/compressed/misc_32.c |    8 ++---
  arch/x86/boot/compressed/misc_64.c |    8 ++---
  arch/x86/kernel/Makefile_32        |    2 -
  arch/x86/kernel/Makefile_64        |    2 -
  arch/x86/kernel/io_delay.c         |   54 
+++++++++++++++++++++++++++++++++++++
  arch/x86/kernel/setup_32.c         |    2 +
  arch/x86/kernel/setup_64.c         |    2 +
  include/asm-x86/io_32.h            |   17 ++---------
  include/asm-x86/io_64.h            |   23 ++++++---------
  9 files changed, 80 insertions(+), 38 deletions(-)

Rene.

[-- Attachment #2: dmi-io_delay.diff --]
[-- Type: text/plain, Size: 9858 bytes --]

commit a17ccb1964b53fd4ab00d501b7f229a9a6cf91d1
Author: Rene Herman <rene.herman@gmail.com>
Date:   Sun Dec 16 13:36:39 2007 +0100

    x86: provide a DMI based port 0x80 I/O delay override.
    
    Certain (HP) laptops experience trouble from our port 0x80 I/O delay
    writes. This patch provides for a DMI based switch to the "alternate
    diagnostic port" 0xed (as used by some BIOSes as well) for these.
    
    David P. Reed confirmed that port 0xed works for him and provides a
    proper delay. The symptoms of _not_ working are a hanging machine,
    with "hwclock" use being a direct trigger.
    
    Earlier versions of this attempted to simply use udelay(2), with the
    2 being a value tested to be a nicely conservative upper-bound with
    help from many on the linux-kernel mailinglist, but that approach has
    two problems.
    
    First, pre-loops_per_jiffy calibration (which is post PIT init while
    some implementations of the PIT are actually one of the historically
    problematic devices that need the delay) udelay() isn't particularly
    well-defined. We could initialise loops_per_jiffy conservatively (and
    based on CPU family so as to not unduly delay old machines) which
    would sort of work, but still leaves problem 2.
    
    Second, delaying isn't the only effect that a write to port 0x80 has.
    It's also a PCI posting barrier which some devices may be explicitly
    or implicitly relying on. Alan Cox did a survey and found evidence
    that additionally some drivers may be racy on SMP without the bus
    locking outb.
    
    Switching to an inb() makes the timing too unpredictable and as such,
    this DMI based switch should be the safest approach for now. Any more
    invasive changes should get more rigid testing first. It's moreover
    only very few machines with the problem and a DMI based hack seems
    to fit that situation.
    
    This does not change the io_delay() in the boot code which is using
    the same port 0x80 I/O delay but those do not appear to be a problem
    as David P. Reed reported the problem was already gone after using the
    udelay(2) version of this. He moreover reported that booting with
    "acpi=off" also fixed things and seeing as how ACPI isn't touched
    until after this DMI based I/O port switch I believe it's safe to
    leave the ones in the boot code be.
    
    The DMI strings from David's HP Pavilion dv9000z are in there already
    and we need to get/verify the DMI info from other machines with the
    problem, notably the HP Pavilion dv6000z.
    
    This patch is partly based on earlier patches from Pavel Machek and
    David P. Reed.
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>

diff --git a/arch/x86/boot/compressed/misc_32.c b/arch/x86/boot/compressed/misc_32.c
index b74d60d..288e162 100644
--- a/arch/x86/boot/compressed/misc_32.c
+++ b/arch/x86/boot/compressed/misc_32.c
@@ -276,10 +276,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/boot/compressed/misc_64.c b/arch/x86/boot/compressed/misc_64.c
index 6ea015a..43e5fcc 100644
--- a/arch/x86/boot/compressed/misc_64.c
+++ b/arch/x86/boot/compressed/misc_64.c
@@ -269,10 +269,10 @@ static void putstr(const char *s)
 	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
-	outb_p(14, vidport);
-	outb_p(0xff & (pos >> 9), vidport+1);
-	outb_p(15, vidport);
-	outb_p(0xff & (pos >> 1), vidport+1);
+	outb(14, vidport);
+	outb(0xff & (pos >> 9), vidport+1);
+	outb(15, vidport);
+	outb(0xff & (pos >> 1), vidport+1);
 }
 
 static void* memset(void* s, int c, unsigned n)
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index a7bc93c..0cc1981 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 5a88890..08a68f0 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -11,7 +11,7 @@ obj-y	:= process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
 		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
-		i8253.o
+		i8253.o io_delay.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
diff --git a/arch/x86/kernel/io_delay.c b/arch/x86/kernel/io_delay.c
new file mode 100644
index 0000000..d889c43
--- /dev/null
+++ b/arch/x86/kernel/io_delay.c
@@ -0,0 +1,54 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <asm/io.h>
+
+/*
+ * Some machines get upset at port 0x80 writes which we use as
+ * an I/O delay. Allow for a DMI based override to alternate
+ * port 0xed.
+ */
+#define STANDARD_IO_DELAY_PORT	0x80
+#define ALTERNATE_IO_DELAY_PORT	0xed
+
+static unsigned short io_delay_port = STANDARD_IO_DELAY_PORT;
+
+void native_io_delay(void)
+{
+	asm volatile ("outb %%al, %w0" : : "d" (io_delay_port));
+}
+
+void slow_down_io(void) {
+	native_io_delay();
+#ifdef REALLY_SLOW_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
+#endif
+}
+EXPORT_SYMBOL(slow_down_io);
+
+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);
+	io_delay_port = ALTERNATE_IO_DELAY_PORT;
+	return 0;
+}
+
+static struct dmi_system_id __initdata alternate_io_delay_port_dmi_table[] = {
+	{
+		.callback	= dmi_alternate_io_delay_port,
+		.ident		= "HP Pavilion dv9000z",
+		.matches	= {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+			DMI_MATCH(DMI_BOARD_NAME, "30B9")
+		}
+	},
+	{
+	}
+};
+
+void __init io_delay_init(void)
+{
+	dmi_check_system(alternate_io_delay_port_dmi_table);
+}
diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c
index e1e18c3..6c3a3b4 100644
--- a/arch/x86/kernel/setup_32.c
+++ b/arch/x86/kernel/setup_32.c
@@ -648,6 +648,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();;
+
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe();
 #endif	
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 30d94d1..ec976ed 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -311,6 +311,8 @@ void __init setup_arch(char **cmdline_p)
 
 	dmi_scan_machine();
 
+	io_delay_init();
+
 #ifdef CONFIG_SMP
 	/* setup to use the static apicid table during kernel startup */
 	x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init;
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index fe881cd..5d4e5e5 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -250,24 +250,13 @@ static inline void flush_write_buffers(void)
 
 #endif /* __KERNEL__ */
 
-static inline void native_io_delay(void)
-{
-	asm volatile("outb %%al,$0x80" : : : "memory");
-}
+extern void io_delay_init(void);
+extern void native_io_delay(void);
 
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
 #else
-
-static inline void slow_down_io(void) {
-	native_io_delay();
-#ifdef REALLY_SLOW_IO
-	native_io_delay();
-	native_io_delay();
-	native_io_delay();
-#endif
-}
-
+extern void slow_down_io(void);
 #endif
 
 #ifdef CONFIG_X86_NUMAQ
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h
index a037b07..486a110 100644
--- a/include/asm-x86/io_64.h
+++ b/include/asm-x86/io_64.h
@@ -35,13 +35,8 @@
   *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   */
 
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
-
-#ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
-#endif
+extern void io_delay_init(void);
+extern void slow_down_io(void);
 
 /*
  * Talk about misusing macros..
@@ -50,21 +45,21 @@
 static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" : : "a" (value), "Nd" (port))
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUT1(s,x) __OUT2(s,s1,"w"); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w"); slow_down_io(); }
 
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
+__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" : "=a" (_v) : "Nd" (port))
 
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+#define __IN(s,s1) \
+__IN1(s) __IN2(s,s1,"w"); return _v; } \
+__IN1(s##_p) __IN2(s,s1,"w"); slow_down_io(); return _v; }
 
 #define __INS(s) \
 static inline void ins##s(unsigned short port, void * addr, unsigned long count) \

^ permalink raw reply related	[flat|nested] 186+ messages in thread

end of thread, other threads:[~2008-01-09 21:01 UTC | newest]

Thread overview: 186+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-12-30  3:34 [PATCH] x86: provide a DMI based port 0x80 I/O delay override Rene Herman
2007-12-30  9:30 ` Linus Torvalds
2007-12-30 12:48   ` Andi Kleen
2007-12-30 13:05     ` Ingo Molnar
2007-12-30 16:08       ` Andi Kleen
2007-12-30 16:28         ` Ingo Molnar
2007-12-30 18:21           ` Andi Kleen
2007-12-30 13:03   ` Ingo Molnar
2007-12-30 14:14   ` Rene Herman
2007-12-30 14:47   ` Alan Cox
2007-12-30 15:28     ` Ingo Molnar
2007-12-30 15:38       ` Alan Cox
2007-12-30 16:01         ` Ingo Molnar
2007-12-30 16:48           ` Alan Cox
2007-12-30 17:08             ` Ingo Molnar
2007-12-30 18:14             ` Rene Herman
2007-12-30 18:39               ` Alan Cox
2007-12-30 19:33                 ` Rene Herman
2007-12-30 20:00                   ` Linus Torvalds
2007-12-30 20:09                     ` Rene Herman
2007-12-30 21:20                     ` David P. Reed
2007-12-30 21:36                       ` Alan Cox
2007-12-30 23:14                         ` David P. Reed
2007-12-31  0:23                           ` H. Peter Anvin
2007-12-31 11:59                             ` Alan Cox
2007-12-31 18:19                               ` H. Peter Anvin
2007-12-31 12:23               ` Alan Cox
2007-12-31 14:35                 ` Rene Herman
2007-12-31 15:56                   ` Alan Cox
2007-12-31 20:22                     ` Ondrej Zary
2007-12-31 21:25                       ` Alan Cox
2007-12-31 21:47                         ` H. Peter Anvin
2007-12-31 23:24                           ` Alan Cox
2007-12-31 23:41                             ` H. Peter Anvin
2008-01-02  3:01                     ` Rene Herman
2007-12-30 17:10         ` Juergen Beisert
2007-12-30 20:50           ` H. Peter Anvin
2007-12-31  1:03             ` David P. Reed
2007-12-31  1:40               ` H. Peter Anvin
2007-12-30 15:47       ` Rene Herman
2007-12-30 16:07         ` Ingo Molnar
2007-12-30 16:27           ` Rene Herman
2007-12-30 17:06             ` Ingo Molnar
2007-12-30 17:54               ` Rene Herman
2007-12-30 18:29               ` Alan Cox
2007-12-30 18:43                 ` Andi Kleen
2007-12-30 20:46                 ` Ingo Molnar
2007-12-30 21:07                   ` Rene Herman
2007-12-30 21:25                     ` Ingo Molnar
2007-12-30 21:29                   ` Alan Cox
2007-12-30 22:03                     ` Ingo Molnar
2007-12-31 13:11                   ` Pavel Machek
2008-01-01 16:48                     ` Ingo Molnar
2007-12-30 18:40         ` Linus Torvalds
2007-12-30 20:34           ` Ingo Molnar
2007-12-30 21:28             ` Alan Cox
2007-12-30 21:54               ` Ingo Molnar
2007-12-30 21:13           ` Alan Cox
2007-12-31 15:29             ` Christer Weinigel
2007-12-31 13:21           ` Pavel Machek
2007-12-31 12:29             ` Alan Cox
     [not found] <9BdU5-1YW-9@gated-at.bofh.it>
     [not found] ` <9BeZN-3Gf-5@gated-at.bofh.it>
     [not found]   ` <9BnTB-1As-31@gated-at.bofh.it>
     [not found]     ` <9BrX4-8go-1@gated-at.bofh.it>
     [not found]       ` <9BuBG-4eR-51@gated-at.bofh.it>
     [not found]         ` <9BvRd-6aL-71@gated-at.bofh.it>
     [not found]           ` <9GRQW-1DX-13@gated-at.bofh.it>
     [not found]             ` <9GSah-23W-1@gated-at.bofh.it>
     [not found]               ` <9GSDy-2GD-23@gated-at.bofh.it>
     [not found]                 ` <9GTpK-40d-15@gated-at.bofh.it>
     [not found]                   ` <9GUvy-5H2-11@gated-at.bofh.it>
     [not found]                     ` <9GVKU-7SS-25@gated-at.bofh.it>
2008-01-07 19:38                       ` Bodo Eggert
2008-01-07 19:46                         ` H. Peter Anvin
2008-01-07 22:02                           ` Bodo Eggert
2008-01-07 22:10                             ` H. Peter Anvin
2008-01-07 22:27                               ` Bodo Eggert
2008-01-07 22:59                                 ` Rene Herman
2008-01-07 23:24                                   ` H. Peter Anvin
2008-01-07 23:26                                     ` Rene Herman
2008-01-08  0:10                                       ` [linux-kernel] " David P. Reed
2008-01-09 21:01                                         ` Matthieu castet
2008-01-08 12:51                                       ` Bodo Eggert
2008-01-08 14:09                                         ` Rene Herman
2008-01-08 14:31                                         ` Alan Cox
2008-01-07 23:25                             ` Alan Cox
2008-01-08 13:17                               ` Bodo Eggert
2008-01-08 14:38                                 ` Alan Cox
2008-01-08  3:15                         ` Christer Weinigel
     [not found] <fa.PuxU73ceCfHAUeWLO4W21Zbrm7A@ifi.uio.no>
     [not found] ` <fa.ipKZdmvkNYmQ40C0cO+2u3eYohw@ifi.uio.no>
     [not found]   ` <fa.ppsa4qOLo1V8UlDNTucnaqIJmKA@ifi.uio.no>
     [not found]     ` <fa.3IG7z0AfHuLo9eQjn7Gkl/+/lnA@ifi.uio.no>
     [not found]       ` <fa.slc2tTnUBrTGO2aTi/C5UGHEEEM@ifi.uio.no>
     [not found]         ` <fa.8g+KfLLge6wS5cEnKhZJmdkIVAI@ifi.uio.no>
2007-12-30 18:22           ` Robert Hancock
     [not found]       ` <fa.XY5q1SY4QX+yjnE6p8T3kbTt/8I@ifi.uio.no>
     [not found]         ` <fa.KEBfnq5vGkAJSEhZSx7+yy+Hdbs@ifi.uio.no>
     [not found]           ` <fa.MLKgXLxgzIKzm4bQXjEOqg9oDwU@ifi.uio.no>
     [not found]             ` <fa.KbCnGLPlUEYe/Ibajd+hTY7A7Qw@ifi.uio.no>
2007-12-31 18:21               ` Robert Hancock
     [not found] <9FXbU-3M4-11@gated-at.bofh.it>
     [not found] ` <9G2Om-4hg-1@gated-at.bofh.it>
     [not found]   ` <9G7O3-3O2-7@gated-at.bofh.it>
     [not found]     ` <9G8qN-4TX-13@gated-at.bofh.it>
2007-12-30 17:50       ` Bodo Eggert
2007-12-30 18:10         ` Ingo Molnar
2007-12-30 20:56           ` H. Peter Anvin
2007-12-30 21:00             ` Ingo Molnar
2007-12-30 21:32               ` Bodo Eggert
2007-12-30 21:33               ` Alan Cox
2007-12-30 22:02                 ` Ingo Molnar
2007-12-30 21:44               ` H. Peter Anvin
2007-12-30 21:58                 ` Rene Herman
2007-12-30 20:53         ` H. Peter Anvin
2007-12-30 21:31           ` Alan Cox
2007-12-31 14:39             ` Bodo Eggert
2007-12-31 15:56               ` Alan Cox
     [not found] <469578CD.3080609@reed.com>
     [not found] ` <1184216528.12353.203.camel@chaos>
     [not found]   ` <1184218962.12353.209.camel@chaos>
     [not found]     ` <46964352.7040301@reed.com>
     [not found]       ` <1184253339.12353.223.camel@chaos>
     [not found]         ` <469697C6.50903@reed.com>
     [not found]           ` <1184274754.12353.254.camel@chaos>
2007-12-14  2:59             ` [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc David P. Reed
2007-12-14 13:15               ` Ingo Molnar
2007-12-14 18:02                 ` H. Peter Anvin
2007-12-14 21:06                   ` Pavel Machek
2007-12-14 22:13                     ` H. Peter Anvin
2007-12-14 23:29                       ` Alan Cox
2007-12-15  8:08                         ` Paul Rolland
2007-12-15  8:13                           ` Rene Herman
2007-12-15 20:27                             ` H. Peter Anvin
2007-12-15 23:26                               ` [PATCH] x86: " Rene Herman
2007-12-15 23:51                                 ` H. Peter Anvin
2007-12-16 13:15                                   ` [PATCH] x86: provide a DMI based port 0x80 I/O delay override Rene Herman
2007-12-16 15:22                                     ` Ingo Molnar
2007-12-17  1:43                                       ` Rene Herman
2007-12-17  2:05                                         ` H. Peter Anvin
2007-12-17  2:19                                           ` Rene Herman
2007-12-17  3:35                                             ` H. Peter Anvin
2007-12-17 13:02                                               ` Rene Herman
2007-12-17 17:14                                                 ` H. Peter Anvin
2007-12-17 19:43                                                   ` David P. Reed
2007-12-17 19:55                                                     ` H. Peter Anvin
2007-12-17 21:02                                                       ` David P. Reed
2007-12-17 21:17                                                         ` H. Peter Anvin
2007-12-17 21:25                                                     ` Alan Cox
2008-01-01 15:57                                                       ` David P. Reed
2008-01-01 21:16                                                         ` H. Peter Anvin
2008-01-01 15:59                                                       ` David P. Reed
2008-01-01 16:15                                                         ` Alan Cox
2008-01-01 16:43                                                           ` Ingo Molnar
2008-01-01 17:32                                                             ` Alan Cox
2008-01-01 18:45                                                               ` Ingo Molnar
2008-01-01 20:14                                                                 ` Christer Weinigel
2008-01-01 21:13                                                                   ` Alan Cox
2008-01-01 21:07                                                                 ` Alan Cox
2008-01-02 10:04                                                                   ` Ingo Molnar
2008-01-02 13:47                                                                     ` Alan Cox
2008-01-02 15:35                                                                       ` Rene Herman
2008-01-02 15:50                                                                         ` Rene Herman
2008-01-01 17:32                                                             ` Christer Weinigel
2008-01-01 18:46                                                               ` Ingo Molnar
2008-01-01 19:35                                                                 ` Christer Weinigel
2008-01-01 19:59                                                                   ` Rene Herman
2008-01-01 20:55                                                                     ` Christer Weinigel
2008-01-01 21:24                                                                       ` H. Peter Anvin
2008-01-01 21:01                                                                   ` Ingo Molnar
2008-01-01 21:26                                                                     ` Alan Cox
2008-01-01 21:42                                                                     ` Christer Weinigel
2008-01-01 21:42                                                                       ` Rene Herman
2008-01-01 21:50                                                                       ` H. Peter Anvin
2008-01-01 21:21                                                                   ` H. Peter Anvin
2008-01-01 23:05                                                                     ` Christer Weinigel
2008-01-01 23:12                                                                       ` Alan Cox
2008-01-02  0:23                                                                         ` Christer Weinigel
2008-01-02 10:00                                                                     ` Ingo Molnar
2008-01-01 17:32                                                           ` David P. Reed
2008-01-01 17:38                                                             ` Alan Cox
2008-01-01 21:15                                                           ` H. Peter Anvin
2008-01-01 21:35                                                             ` Rene Herman
2008-01-01 21:44                                                               ` H. Peter Anvin
2008-01-01 22:35                                                                 ` Rene Herman
2008-01-01 22:39                                                                   ` H. Peter Anvin
2008-01-01 23:11                                                                     ` Rene Herman
2008-01-02  0:25                                                                       ` Rene Herman
2008-01-02  0:55                                                                       ` Christer Weinigel
2008-01-02  1:00                                                                         ` Rene Herman
2008-01-02  2:27                                                                         ` H. Peter Anvin
2008-01-09 17:27                                                                 ` Maciej W. Rozycki
2008-01-09 18:18                                                                   ` H. Peter Anvin
2008-01-01 17:31                                                         ` Pavel Machek
2008-01-01 17:33                                                           ` David P. Reed
2007-12-17  4:09                                             ` H. Peter Anvin
2007-12-17 10:57                                         ` Ingo Molnar
2007-12-17 11:29                                           ` Ingo Molnar
2007-12-17 13:34                                             ` David P. Reed
2007-12-17 12:15                                           ` Rene Herman
2007-12-17 13:09                                             ` Ingo Molnar
2007-12-17 13:22                                               ` Rene Herman
2007-12-17 13:31                                                 ` Pavel Machek
2007-12-17 13:31                                                   ` Rene Herman
2007-12-17 13:32                                                 ` David P. Reed
2007-12-17 13:36                                                   ` Rene Herman
2007-12-17 14:39                                                   ` Ingo Molnar
2007-12-17 16:12                                                     ` Alan Cox
2007-12-17 16:48                                                       ` Ingo Molnar
2007-12-17 20:48                                                       ` Rene Herman
2007-12-17 20:57                                                         ` H. Peter Anvin
2007-12-17 21:33                                                           ` Rene Herman
2007-12-17 21:40                                                             ` H. Peter Anvin
2007-12-17 21:46                                                               ` Ingo Molnar
2007-12-17 21:50                                                               ` Rene Herman
2007-12-17 21:41                                                         ` Ingo Molnar
2007-12-17 21:47                                                           ` Rene Herman
2007-12-17 21:56                                                             ` Ingo Molnar
2007-12-17 22:01                                                               ` Rene Herman
2007-12-17 22:18                                                                 ` David P. Reed
2007-12-17 19:38                                                     ` David P. Reed
2007-12-17 19:55                                                       ` H. Peter Anvin
2007-12-17 21:28                                                       ` Ingo Molnar
2007-12-16 21:42                                     ` H. Peter Anvin
2007-12-17  1:48                                       ` Rene Herman
2007-12-17  1:53                                         ` H. Peter Anvin
2007-12-16 23:12                                     ` David P. Reed
2007-12-17  1:56                                       ` Rene Herman
2007-12-17  2:04                                         ` H. Peter Anvin
2007-12-17  2:15                                           ` Rene Herman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).