time: fix typo that makes sync_cmos_clock erratic
Subsystems (6)
PATCH 1/1 time: fix typo that makes sync_cmos_clock erratic
In reply to a message not in the archiveFrom: David P. Reed
Fix a typo in ntp.c that has caused updating of the persistent (RTC) clock when synced to NTP to behave erratically.
---
When debugging a freeze that arises on my AMD64 machines when I run the ntpd service, I added a number of printk's to monitor the sync_cmos_clock procedure. I discovered that it was not syncing to cmos RTC every 11 minutes as documented, but instead would keep trying every second for hours at a time. The reason turned out to be a typo in sync_cmos_clock, where it attempts to ensure that update_persistent_clock is called very close to 500 msec. after a 1 second boundary (required by the PC RTC's spec). That typo referred to "xtime" in one spot, rather than "now", which is derived from "xtime" but not equal to it. This makes the test erratic, creating a "coin-flip" that decides when update_persistent_clock is called - when it is called, which is rarely, it may be at any time during the one second period, rather than close to 500 msec, so the value written is needlessly incorrect, too.
I rewrote the code to fix the typo and to be a little more clear about the logic that was intended here. I have thoroughly tested this on several x86_64 machines, and also on one 32-bit machine. I have also submitted a patch to fix the freeze cited above, but both patches are independent, and should be treated separately.
The patch works in 2.6.24rc2, but it should also work in 2.6.23.
kernel/time/ntp.c +0 -0
@@ -188,6 +188,7 @@ static DEFINE_TIMER(sync_cmos_timer, syn
static void sync_cmos_clock(unsigned long dummy)
{
struct timespec now, next;
+ long delta_from_target_time;
int fail = 1;
/*
@@ -205,7 +206,10 @@ static void sync_cmos_clock(unsigned lon
return;
getnstimeofday(&now);- if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+ delta_from_target_time = abs(now.tv_nsec - (NSEC_PER_SEC / 2));
+
+ /* set CMOS clock, only if close enough to 500 msec point */
+ if (delta_from_target_time <= tick_nsec / 2)
fail = update_persistent_clock(now);
next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;PATCH 1/1 x86: fix locking and sync bugs in x86_64 RTC code in time_64.c
In reply to a message not in the archiveFrom: David P. Reed
Fix two bugs in arch/x86/kernel/time_64.c that affect the x86_64 kernel. 1) a repeatable hard freeze due to interrupts when the ntpd service calls update_persistent_clock(), 2) potentially unstable PC RTC timer values when timer is read.
---
More explanation:
1) A repeatable but randomly timed freeze has been happening in Fedora 6 and 7 for the last year, whenever I run the ntpd service on my AMD64x2 HP Pavilion dv9000z laptop. This freeze is due to the use of spin_lock(&rtc_lock) under the assumption (per a bad comment) that set_rtc_mmss is called only with interrupts disabled. The call from ntp.c to update_persistent_clock is made with interrupts enabled.
2) the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably. I realize that not all "clones" of the
The patch updates the misleading comments and minimizes the amount of time that the kernel disables interrupts.
I have thoroughly tested this patch on a number of x86_64 machines with various numbers of cores and chipsets, using 2.6.24rc2 kernel source. Note that while testing the ntp code I found another bug in kernel/time/ntp.c which is independent of this fix - neither patch requires the other.
If possible, I'd love to see the patch merged with 2.6.24, and even with 2.6.23.
arch/x86/kernel/time_64.c +4 -5
@@ -82,13 +82,12 @@ static int set_rtc_mmss(unsigned long noint retval =0 ;int real_seconds, real_minutes, cmos_minutes;unsigned char control, freq_select; +unsigned long flags; -/* -* IRQs are disabled when we're called from the timer interrupt, -* no need for spin_lock_irqsave() +/* +* set_rtc_mmss is called when irqs are enabled, so disable irqs here */ - -spin_lock (&rtc_lock); +spin_lock_irqsave (&rtc_lock, flags);
/*
* Tell the clock it's being set and stop it.
@@ -138,7 +137,7 @@ static int set_rtc_mmss(unsigned long no
CMOS_WRITE(control, RTC_CONTROL);
CMOS_WRITE(freq_select, RTC_FREQ_SELECT);- spin_unlock(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return retval;
}
@@ -163,22 +162,30 @@ unsigned long read_persistent_clock(void
unsigned long flags;
unsigned century = 0;- spin_lock_irqsave(&rtc_lock, flags);
+ retry: spin_lock_irqsave(&rtc_lock, flags);
+ /* if UIP is clear, then we have >= 244 microseconds before RTC
+ * registers will be updated. Spec sheet says that this is the
+ * reliable way to read RTC - registers invalid (off bus) during update
+ */
+ if ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) {
+ spin_unlock_irqrestore(&rtc_lock, flags); + cpu_relax(); + goto retry;
+ }
- do {
- sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); + /* now read all RTC registers while stable with interrupts disabled */ + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR);
#ifdef CONFIG_ACPI
- if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
- acpi_gbl_FADT.century)
- century = CMOS_READ(acpi_gbl_FADT.century);
+ if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+ acpi_gbl_FADT.century)
+ century = CMOS_READ(acpi_gbl_FADT.century);
#endif
- } while (sec != CMOS_READ(RTC_SECONDS));
-
spin_unlock_irqrestore(&rtc_lock, flags);
/*PATCH 1/1 time: fix typo that makes sync_cmos_clock erratic
In reply to a message not in the archiveFrom: David P. Reed
Fix a typo in ntp.c that has caused updating of the persistent (RTC) clock when synced to NTP to behave erratically.
---
When debugging a freeze that arises on my AMD64 machines when I run the ntpd service, I added a number of printk's to monitor the sync_cmos_clock procedure. I discovered that it was not syncing to cmos RTC every 11 minutes as documented, but instead would keep trying every
second for hours at a time. The reason turned out to be a typo insync_cmos_clock, where it attempts to ensure that update_persistent_clock is called very close to 500 msec. after a 1 second boundary (required by the PC RTC's spec). That typo referred to "xtime" in one spot, rather than "now", which is derived from "xtime" but not equal to it. This makes the test erratic, creating a "coin-flip" that decides when update_persistent_clock is called - when it is called, which is rarely, it may be at any time during the one second period, rather than close to 500 msec, so the value written is needlessly incorrect, too.
I rewrote the code to fix the typo and to be a little more clear about the logic that was intended here. I have thoroughly tested this on several x86_64 machines, and also on one 32-bit machine. I have also submitted a patch to fix the freeze cited above, but both patches are independent, and should be treated separately.
The patch works in 2.6.24rc2, but it should also work in 2.6.23.
kernel/time/ntp.c +0 -0
@@ -188,6 +188,7 @@ static DEFINE_TIMER(sync_cmos_timer, syn
static void sync_cmos_clock(unsigned long dummy)
{
struct timespec now, next;
+ long delta_from_target_time;
int fail = 1;
/*
@@ -205,7 +206,10 @@ static void sync_cmos_clock(unsigned lon
return;
getnstimeofday(&now);- if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+ delta_from_target_time = abs(now.tv_nsec - (NSEC_PER_SEC / 2));
+
+ /* set CMOS clock, only if close enough to 500 msec point */
+ if (delta_from_target_time <= tick_nsec / 2)
fail = update_persistent_clock(now);
next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;Re: [PATCH] x86: fix locking and sync bugs in x86_64 RTC code in time_64.c
In reply to David P. ReedDavid,
Quoted 6 lines · David P. Reed
From: David P. Reed
Fix two bugs in
arch/x86/kernel/time_64.cthat affect thex86_64kernel. 1) a repeatable hard freeze due to interrupts when the ntpd service callsupdate_persistent_clock(), 2) potentially unstable PC RTC timer values when timer is read.
1) Please send separate patches for separate problems.
2) Your patch is white space damaged and does not apply. Please run it through scripts/checkpatch.pl before submitting, maybe send it to yourself first and verify that it applies correctly.
Quoted 9 lines
Signed-off-by David P. Reed <[email protected]>---
More explanation:
1) A repeatable but randomly timed freeze has been happening in Fedora 6 and 7 for the last year, whenever I run the ntpd service on my AMD64x2 HP Pavilion dv9000z laptop. This freeze is due to the use ofspin_lock(&rtc_lock)under the assumption (per a bad comment) thatset_rtc_mmssis called only with interrupts disabled. The call fromntp.ctoupdate_persistent_clockis made with interrupts enabled.
Good catch.
Quoted 6 lines
2) the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably. I realize that not all "clones" of the
of the what ?
Also put the detailed description into the patch comment, please.
Quoted 10 lines
The patch updates the misleading comments and minimizes the amount of time that the kernel disables interrupts.
I have thoroughly tested this patch on a number of
x86_64machines with various numbers of cores and chipsets, using 2.6.24rc2 kernel source. Note that while testing the ntp code I found another bug inkernel/time/ntp.cwhich is independent of this fix - neither patch requires the other.If possible, I'd love to see the patch merged with 2.6.24, and even with 2.6.23.
Care to resend ?
Thanks,
tglx
David,
Quoted 4 lines · David P. Reed
From: David P. Reed
Fix a typo in
ntp.cthat has caused updating of the persistent (RTC) clock when synced to NTP to behave erratically.
Good catch.
Quoted 1 line
Signed-off-by David P. Reed
Whitespace damaged as well. Please fix and resend
Quoted 5 lines
---
When debugging a freeze that arises on my AMD64 machines when I run the ntpd service, I added a number of printk's to monitor thesync_cmos_clockprocedure. I discovered that it was not syncing to cmos RTC every 11 minutes as documented, but instead would keep trying every second for hours at a time.
Quoted 8 lines
The reason turned out to be a typo in
sync_cmos_clock, where it attempts to ensure thatupdate_persistent_clockis called very close to 500 msec. after a 1 second boundary (required by the PC RTC's spec). That typo referred to "xtime" in one spot, rather than "now", which is derived from "xtime" but not equal to it. This makes the test erratic, creating a "coin-flip" that decides whenupdate_persistent_clockis called - when it is called, which is rarely, it may be at any time during the one second period, rather than close to 500 msec, so the value written is needlessly incorrect, too.
Please put the explanation into the changelog.
Quoted 1 line
The patch works in 2.6.24rc2, but it should also work in 2.6.23.
Yup
Review static void sync_cmos_clock(unsigned lon · line 208
Quoted 5 lines
(quoted diff) +0
-1@@ -205,7 +206,10 @@ static void sync_cmos_clock(unsigned lon return; getnstimeofday(&now); - if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
Can we just s/xtime/now/ ? There is no value in an extra variable.
Thanks,
tglx
Re: [PATCH] x86: fix locking and sync bugs in x86_64 RTC code in time_64.c
In reply to Thomas GleixnerWill make two patches and resend.
Quoted 66 lines · Thomas Gleixner
David,
Quoted 7 lines · David P. Reed
From: David P. Reed
Fix two bugs in
arch/x86/kernel/time_64.cthat affect thex86_64kernel. 1) a repeatable hard freeze due to interrupts when the ntpd service callsupdate_persistent_clock(), 2) potentially unstable PC RTC timer values when timer is read.1) Please send separate patches for separate problems.
2) Your patch is white space damaged and does not apply. Please run it through
scripts/checkpatch.plbefore submitting, maybe send it to yourself first and verify that it applies correctly.Quoted 10 lines
Signed-off-by David P. Reed <[email protected]>---
More explanation:
1) A repeatable but randomly timed freeze has been happening in Fedora 6 and 7 for the last year, whenever I run the ntpd service on my AMD64x2 HP Pavilion dv9000z laptop. This freeze is due to the use ofspin_lock(&rtc_lock)under the assumption (per a bad comment) thatset_rtc_mmssis called only with interrupts disabled. The call fromntp.ctoupdate_persistent_clockis made with interrupts enabled.Good catch.
Quoted 7 lines
2) the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably. I realize that not all "clones" of the
of the what ?
Also put the detailed description into the patch comment, please.
Quoted 11 lines
The patch updates the misleading comments and minimizes the amount of time that the kernel disables interrupts.
I have thoroughly tested this patch on a number of
x86_64machines with various numbers of cores and chipsets, using 2.6.24rc2 kernel source. Note that while testing the ntp code I found another bug inkernel/time/ntp.cwhich is independent of this fix - neither patch requires the other.If possible, I'd love to see the patch merged with 2.6.24, and even with 2.6.23.
Care to resend ?
Thanks,
tglx
Re: [PATCH] x86: fix locking and sync bugs in x86_64 RTC code in time_64.c
Quoted 1 line · David P. Reed
Will make two patches and resend.
I've already got a set of patches brewing to fix the UIP problem across all the affected arches (11+).
Signature · 1 line
Mathematics is the supreme nostalgia of our time.
Re: [PATCH] x86: fix locking and sync bugs in x86_64 RTC code in time_64.c
Cool. More reason to separate this into two.
Quoted 9 lines · Matt Mackall
Quoted 2 lines · David P. Reed
Will make two patches and resend.
I've already got a set of patches brewing to fix the UIP problem across all the affected arches (11+).
PATCH 1/1 x86: fix freeze in x86_64 RTC update code in time_64.c
In reply to a message not in the archiveFix hard freeze on x86_64 when the ntpd service calls update_persistent_clock()
A repeatable but randomly timed freeze has been happening in Fedora 6 and 7 for the last year, whenever I run the ntpd service on my AMD64x2 HP Pavilion dv9000z laptop. This freeze is due to the use of spin_lock(&rtc_lock) under the assumption (per a bad comment) that set_rtc_mmss is called only with interrupts disabled. The call from ntp.c to update_persistent_clock is made with interrupts enabled.
---
I have thoroughly tested this patch on a number of x86_64 machines with various numbers of cores and chipsets, using 2.6.24rc2 kernel source.
arch/x86/kernel/time_64.c +4 -7
@@ -82,18 +82,15 @@ static int set_rtc_mmss(unsigned long noint retval =0 ;int real_seconds, real_minutes, cmos_minutes;unsigned char control, freq_select; +unsigned long flags;/* -* IRQs are disabled when we're called from the timer interrupt, -* no need for spin_lock_irqsave() +* set_rtc_mmss is called when irqs are enabled, so disable irqs here */ - -spin_lock (&rtc_lock); - +spin_lock_irqsave (&rtc_lock, flags);/* * Tell the clock it's being set and stop it. */ - control =CMOS_READ (RTC_CONTROL );CMOS_WRITE (control |RTC_SET ,RTC_CONTROL );
@@ -138,7 +135,7 @@ static int set_rtc_mmss(unsigned long noCMOS_WRITE (control,RTC_CONTROL );CMOS_WRITE (freq_select,RTC_FREQ_SELECT ); -spin_unlock (&rtc_lock); +spin_unlock_irqrestore (&rtc_lock, flags);return retval; }
PATCH 1/1 time: fix typo that makes sync_cmos_clock erratic
In reply to a message not in the archiveFix a typo in ntp.c that has caused updating of the persistent (RTC) clock when synced to NTP to behave erratically.
When debugging a freeze that arises on my AMD64 machines when I run the ntpd service, I added a number of printk's to monitor the sync_cmos_clock procedure. I discovered that it was not syncing to cmos RTC every 11 minutes as documented, but instead would keep trying every second for hours at a time. The reason turned out to be a typo in sync_cmos_clock, where it attempts to ensure that update_persistent_clock is called very close to 500 msec. after a 1 second boundary (required by the PC RTC's spec). That typo referred to "xtime" in one spot, rather than "now", which is derived from "xtime" but not equal to it. This makes the test erratic, creating a "coin-flip" that decides when update_persistent_clock is called - when it is called, which is rarely, it may be at any time during the one second period, rather than close to 500 msec, so the value written is needlessly incorrect, too.
---
I have thoroughly tested this on several x86_64 machines, and also on one 32-bit machine. I have also submitted a patch to fix the freeze cited above, but both patches are independent, and should be treated separately.
kernel/time/ntp.c +1 -1
@@ -205,7 +205,7 @@ static void sync_cmos_clock(unsigned lonreturn ;getnstimeofday (&now); -if (abs (xtime.tv_nsec - (NSEC_PER_SEC /2 )) <= tick_nsec /2 ) +if (abs (now.tv_nsec - (NSEC_PER_SEC /2 )) <= tick_nsec /2 ) fail =update_persistent_clock (now); next.tv_nsec = (NSEC_PER_SEC /2 ) - now.tv_nsec;
PATCH 1/1 x86: on x86_64, correct reading of PC RTC when update in progress in time_64.c
In reply to a message not in the archiveCorrect potentially unstable PC RTC time register reading in time_64.c
Stop the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably.
The patch updates the misleading comments and also minimizes the amount of time that the kernel disables interrupts during the reading.
---
arch/x86/kernel/time_64.c +21 -13
@@ -160,22 +160,30 @@ unsigned long read_persistent_clock(voidunsigned long flags;unsigned century =0 ; -spin_lock_irqsave (&rtc_lock, flags); + retry:spin_lock_irqsave (&rtc_lock, flags); +/* if UIP is clear, then we have >= 244 microseconds before RTC +* registers will be updated. Spec sheet says that this is the +* reliable way to read RTC - registers invalid (off bus) during update +*/ +if ((CMOS_READ (RTC_FREQ_SELECT ) &RTC_UIP )) { +spin_unlock_irqrestore (&rtc_lock, flags); +cpu_relax (); + goto retry; + } -do { - sec =CMOS_READ (RTC_SECONDS ); - min =CMOS_READ (RTC_MINUTES ); - hour =CMOS_READ (RTC_HOURS ); - day =CMOS_READ (RTC_DAY_OF_MONTH ); - mon =CMOS_READ (RTC_MONTH ); - year =CMOS_READ (RTC_YEAR ); +/* now read all RTC registers while stable with interrupts disabled */ + + sec =CMOS_READ (RTC_SECONDS ); + min =CMOS_READ (RTC_MINUTES ); + hour =CMOS_READ (RTC_HOURS ); + day =CMOS_READ (RTC_DAY_OF_MONTH ); + mon =CMOS_READ (RTC_MONTH ); + year =CMOS_READ (RTC_YEAR );#ifdef CONFIG_ACPI -if (acpi_gbl_FADT.header.revision >=FADT2_REVISION_ID && - acpi_gbl_FADT.century) - century =CMOS_READ (acpi_gbl_FADT.century); +if (acpi_gbl_FADT.header.revision >=FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century =CMOS_READ (acpi_gbl_FADT.century);#endif - }while (sec !=CMOS_READ (RTC_SECONDS )); -spin_unlock_irqrestore (&rtc_lock, flags);/*
Re: [PATCH] x86: on x86_64, correct reading of PC RTC when update in progress in time_64.c
On Wed, 14 Nov 2007, David P. Reed wrote:
Still whitespace wreckage in your patches. I guess the kernel tree you made your patches against is already white space wrecked.
I fixed that up manually, but please be more careful about that next time.
Quoted 11 lines
Correct potentially unstable PC RTC time register reading in
time_64.cStop the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably.
The patch updates the misleading comments and also minimizes the amount of time that the kernel disables interrupts during the reading.
While I think that the UIP change is correct and a must have, the locking change is not really useful. read_persistent_clock is called from exactly three places:
Right after boot, right before suspend and right after resume. None of those places is a hot path, where we really care about the interrupt enable/disable. IIRC, this is even called with interrupts disabled most of the time, so no real gain here.
Another reason not to do the locking change is the paravirt stuff which is coming for 64bit. I looked into the existing 32bit code and doing the same lock thing would introduce a real nasty hackery, which is definitely not worth the trouble.
Thanks,
tglx
Quoted 53 lines
Signed-off-by David P. Reed <[email protected]>---
Index:linux-2.6/arch/x86/kernel/time_64.c
===================================================================arch/x86/kernel/time_64.c +4
-1@@ -160,22 +160,30 @@ unsigned long read_persistent_clock(voidunsigned long flags;unsigned century =0 ; -spin_lock_irqsave (&rtc_lock, flags); + retry:spin_lock_irqsave (&rtc_lock, flags); +/* if UIP is clear, then we have >= 244 microseconds before RTC +* registers will be updated. Spec sheet says that this is the +* reliable way to read RTC - registers invalid (off bus) during update
arch/x86/kernel/time_64.c +17
-12+*/ +if ((CMOS_READ (RTC_FREQ_SELECT ) &RTC_UIP )) { +spin_unlock_irqrestore (&rtc_lock, flags); +cpu_relax (); + goto retry; + } -do { - sec =CMOS_READ (RTC_SECONDS ); - min =CMOS_READ (RTC_MINUTES ); - hour =CMOS_READ (RTC_HOURS ); - day =CMOS_READ (RTC_DAY_OF_MONTH ); - mon =CMOS_READ (RTC_MONTH ); - year =CMOS_READ (RTC_YEAR ); +/* now read all RTC registers while stable with interrupts disabled */ + + sec =CMOS_READ (RTC_SECONDS ); + min =CMOS_READ (RTC_MINUTES ); + hour =CMOS_READ (RTC_HOURS ); + day =CMOS_READ (RTC_DAY_OF_MONTH ); + mon =CMOS_READ (RTC_MONTH ); + year =CMOS_READ (RTC_YEAR );#ifdef CONFIG_ACPI -if (acpi_gbl_FADT.header.revision >=FADT2_REVISION_ID && - acpi_gbl_FADT.century) - century =CMOS_READ (acpi_gbl_FADT.century); +if (acpi_gbl_FADT.header.revision >=FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century =CMOS_READ (acpi_gbl_FADT.century);#endif - }while (sec !=CMOS_READ (RTC_SECONDS )); -spin_unlock_irqrestore (&rtc_lock, flags);/*
Re: [PATCH] x86: on x86_64, correct reading of PC RTC when update in progress in time_64.c
There are a couple of things I don't understand on this one. And I presume you thought the other two bug fixing patches I sent before this were OK to go, since on my system
Quoted 5 lines · Thomas Gleixner
Still whitespace wreckage in your patches. I guess the kernel tree you made your patches against is already white space wrecked.
I fixed that up manually, but please be more careful about that next time.
Um ... I fixed the whitespaces I detected from the first round with checkpatch.pl. Then for good measure I ran checkpatch.pl on the patches, then pasted the files directly into the emails. No problems detected. And I also just tried checkpatch.pl on the "sent" folder copy. No problems detected there.
Where was the whitespace? Was it in the patches? Would you mind showing me the output so I can do a better job in the future?
Quoted 10 lines
Quoted 10 lines
Correct potentially unstable PC RTC time register reading in
time_64.cStop the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably.
Quoted 8 lines
Quoted 3 lines
The patch updates the misleading comments and also minimizes the amount of time that the kernel disables interrupts during the reading.
While I think that the UIP change is correct and a must have, the locking change is not really useful.
read_persistent_clockis called from exactly three places:
What locking change? I didn't change how locking works in read_persistent_clock at all.
I did introduce cpu_relax() because if anyone else ever calls from a hot path, that would be good practice and its' one line.
Quoted 10 lines
Right after boot, right before suspend and right after resume. None of those places is a hot path, where we really care about the interrupt enable/disable. IIRC, this is even called with interrupts disabled most of the time, so no real gain here.
Another reason not to do the locking change is the paravirt stuff which is coming for 64bit. I looked into the existing 32bit code and doing the same lock thing would introduce a real nasty hackery, which is definitely not worth the trouble.
I presume time_64.c and time_32.c will be unified at some point, discarding time_64.c. There's no arch-specific reason to be separate. The current time_32.c depends on a different nmi path (that does some weird stuff saving and restoring the CMOS index register!), and I didn't dare usurp your long-term plan to unify architectures. But a simple cleanup here makes sense, lest someone copy the bad technique as if it were good.
Quoted 61 lines
Thanks,
tglx
Quoted 54 lines
Signed-off-by David P. Reed <[email protected]>---
Index:linux-2.6/arch/x86/kernel/time_64.c
===================================================================arch/x86/kernel/time_64.c +4
-1@@ -160,22 +160,30 @@ unsigned long read_persistent_clock(voidunsigned long flags;unsigned century =0 ; -spin_lock_irqsave (&rtc_lock, flags); + retry:spin_lock_irqsave (&rtc_lock, flags); +/* if UIP is clear, then we have >= 244 microseconds before RTC +* registers will be updated. Spec sheet says that this is the +* reliable way to read RTC - registers invalid (off bus) during update
arch/x86/kernel/time_64.c +17
-12+*/ +if ((CMOS_READ (RTC_FREQ_SELECT ) &RTC_UIP )) { +spin_unlock_irqrestore (&rtc_lock, flags); +cpu_relax (); + goto retry; + } -do { - sec =CMOS_READ (RTC_SECONDS ); - min =CMOS_READ (RTC_MINUTES ); - hour =CMOS_READ (RTC_HOURS ); - day =CMOS_READ (RTC_DAY_OF_MONTH ); - mon =CMOS_READ (RTC_MONTH ); - year =CMOS_READ (RTC_YEAR ); +/* now read all RTC registers while stable with interrupts disabled */ + + sec =CMOS_READ (RTC_SECONDS ); + min =CMOS_READ (RTC_MINUTES ); + hour =CMOS_READ (RTC_HOURS ); + day =CMOS_READ (RTC_DAY_OF_MONTH ); + mon =CMOS_READ (RTC_MONTH ); + year =CMOS_READ (RTC_YEAR );#ifdef CONFIG_ACPI -if (acpi_gbl_FADT.header.revision >=FADT2_REVISION_ID && - acpi_gbl_FADT.century) - century =CMOS_READ (acpi_gbl_FADT.century); +if (acpi_gbl_FADT.header.revision >=FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century =CMOS_READ (acpi_gbl_FADT.century);#endif - }while (sec !=CMOS_READ (RTC_SECONDS )); -spin_unlock_irqrestore (&rtc_lock, flags);/*
Re: [PATCH] x86: on x86_64, correct reading of PC RTC when update in progress in time_64.c
Quoted 3 lines · David P. Reed
There are a couple of things I don't understand on this one. And I presume you thought the other two bug fixing patches I sent before this were OK to go, since on my system
I had to fix up all of them.
Quoted 5 lines
Quoted 3 lines · Thomas Gleixner
Still whitespace wreckage in your patches. I guess the kernel tree you made your patches against is already white space wrecked.
Quoted 7 lines
Quoted 2 lines
I fixed that up manually, but please be more careful about that next time.
Um ... I fixed the whitespaces I detected from the first round with checkpatch.pl. Then for good measure
I ran checkpatch.pl on the patches, then pasted the files directly into the emails. No problems detected.
Never paste patches into mail. Also I should have checked your mail client earlier. Thunderbird is famous for this :) Documentation/email-clients.txt has some info on that.
Quoted 2 lines
And I also just tried checkpatch.pl on the "sent" folder copy. No problems detected there.
Try to apply your own patches right from the sent folder copy. They will reject.
Quoted 2 lines
Where was the whitespace? Was it in the patches? Would you mind showing me the output so I can do a better job in the future?
Well the output was a simple reject when applying the patch.
Whitespace damage was for example here:
unsigned long flags;
20 20 09 75 6e 73 69 67 6e 65 64 20 6c 6f 6e 67 20 66 6c 61 67 73 3b 0a
where the correct patch should read:
20 09 75 6e 73 69 67 6e 65 64 20 6c 6f 6e 67 20 66 6c 61 67 73 3b 0a
Your mailer or the paste added a second blank (0x20) at the beginning of the line.
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Correct potentially unstable PC RTC time register reading in
time_64.cStop the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably.
The patch updates the misleading comments and also minimizes the amount of time that the kernel disables interrupts during the reading.
Quoted 8 lines
Quoted 4 lines
While I think that the UIP change is correct and a must have, the locking change is not really useful.
read_persistent_clockis called from exactly three places:What locking change? I didn't change how locking works in
read_persistent_clockat all.
I did introducecpu_relax()because if anyone else ever calls from a hot path, that would be good practice and its' one line.
Hot path calls to this code would be extremly stupid and are forbidden by the Penguin Law. :)
cpu_relax is not the problem, but you actuall changed the locking:
Old code:
spin_lock();
do {
....
} while (stupid check);
spin_unlock();New code:
while (1) {
spin_lock();
if (useful_check) {
spin_unlock();
cpu_relax();
} else
break;}
So with the old code I can take out the inner loop and do what paravirtualization in the 32 bit code does:
spin_lock_irqsave(&rtc_lock, flags); result = get_wallclock(); spin_unlock_irqrestore(&rtc_lock, flags);
Where get_wallclock() either resolves to the plain rtc code or to the paravirtualized function depending on the boot mode of the kernel.
With your change we either would need to put lokck/unlock of rtc_lock into each incarnation of paravirt or do some nasty hack, where we convey the flags to the called function. Neither of this makes sense and is worth the work.
Quoted 10 lines
Quoted 10 lines
Right after boot, right before suspend and right after resume. None of those places is a hot path, where we really care about the interrupt enable/disable. IIRC, this is even called with interrupts disabled most of the time, so no real gain here.
Another reason not to do the locking change is the paravirt stuff which is coming for 64bit. I looked into the existing 32bit code and doing the same lock thing would introduce a real nasty hackery, which is definitely not worth the trouble.
Quoted 6 lines
I presume
time_64.candtime_32.cwill be unified at some point, discardingtime_64.c. There's no arch-specific reason to be separate. The currenttime_32.cdepends on a different nmi path (that does some weird stuff saving and restoring the CMOS index register!), and I didn't dare usurp your long-term plan to unify architectures. But a simple cleanup here makes sense, lest someone copy the bad technique as if it were good.
Yeah, those files are on the radar. The cleanup branch of the x86 git tree has a first go on this already. And I'm currently figuring out what we can do about this ugly CMOS index hack.
Anyway I keep the locking straight and simple as it is right now, the cpu_relax() works fine with a lock held, while we are waiting the bunch of usecs for UIP going away.
Thanks,
tglx
PATCH 1/1 x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to a message not in the archiveReplace use of outb to "unused" diagnostic port 0x80 for time delay with udelay based time delay on x86_64 architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.
Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
i386 family fixes (completely parallel) were not included, considering that such machines might involve more risk of problems on legacy machines.
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
include/asm/io_64.h +18 -29
79 lines not on this page · raw message
long count) \
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
include/asm/io_64.h
Quoted 43 lines · David P. Reed
Replace use of outb to "unused" diagnostic port
0x80for time delay with udelay based time delay onx86_64architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
i386 family fixes (completely parallel) were not included, considering that such machines might involve more risk of problems on legacy machines.
Signed-off-by David P. Reed <[email protected]>Index:
linux-2.6/arch/x86/boot/compressed/misc_64.c
===================================================================arch/x86/boot/compressed/misc_64.c +4
-4@@ -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-2.6/include/asm/io_64.h
===================================================================include/asm/io_64.h +0
-0
include/asm-x64/io_64.h ?
YH
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 9 lines · David P. Reed
Replace use of outb to "unused" diagnostic port
0x80for time delay with udelay based time delay onx86_64architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
Quoted 8 lines
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
i386 family fixes (completely parallel) were not included, considering that such machines might involve more risk of problems on legacy machines.
Here's the corresponding 32-bit patch. Applies fine to (and works on) v2.6.23.x as well after un-uniting the paths...
I do believe it would be better to do both; x86-64 machines can run 32-bit kernels fine and might certainly in the form of generic (installer) kernels and the like so if it's a fix lets fix it across the board -- the 2 us delay is going to be enough for everything out there, certainly given that _0_ is normally enough. With the arches just merged, minimising diferences should be a goal in itself I guess.
One thing though -- I believe we want to adjust the loops_per_jiffy default to make sure this works, or would work, pre-calibration as well? Not really sure how needed it is, but bogomips is defined as
bogomips = loops_per_jiffy / (500000 / HZ) <=> loops_per_jiffy = bogomips * (500000 / HZ)
which with assuming any machine above 1G isn't affected by any of this and bogomips coming out to 2 * MHz on anything I myself have run linux on might suggest that
loops_per_jiffy = 2 * 1000 * (500000 / HZ) = 1000000000 / HZ
could possibly be a sane if very large default? Alan?
init/main.c +2 -3
@@ -229,10 +229,9 @@ static int __init obsolete_checksetup(char *line) }/* -* This should be approx 2 Bo*oMips to start (note initial shift), and will -* still work even if initially too large, it will just take slightly longer +* Initial value roughly corresponds to a 1 GHz CPU */ -unsigned long loops_per_jiffy = (1 <<12 ); +unsigned long loops_per_jiffy =1000000000 /HZ ;EXPORT_SYMBOL (loops_per_jiffy);
From: Pavel Machek <[email protected]>
32-bit part of the port 0x80 delay replacement.
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
include/asm-x86/io_32.h +2 -12
@@ -3,6 +3,7 @@#include <linux/string.h> #include <linux/compiler.h> +#include <linux/delay.h> /* * This file contains the definitions for the x86 IO instructions
@@ -17,17 +18,6 @@* mistake somewhere. */ -/* -* Thanks to James van Artsdalen for a better timing-fix than -* the two short jumps: using outb's to a nonexistent port seems -* to guarantee better timings even on fast machines. -* -* On the other hand, I'd like to be sure of a non-existent port: -* I feel a bit unsafe about using 0x80 (should be safe, though) -* -* Linus -*/ -/* * Bit simplified and optimized by Jan Hubicka * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
@@ -252,7 +242,7 @@ static inline void flush_write_buffers(void)static inline void native_io_delay (void ) { - asmvolatile ("outb %%al,$0x80" : : :"memory" ); +udelay (2 ); }#if defined(CONFIG_PARAVIRT )
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 3 lines · David P. Reed
i386 family fixes (completely parallel) were not included, considering that such machines might involve more risk of problems on legacy machines.
They're needed because lots of people fomr some reason still boot 32bit kernels on 64bit machines.
include/asm/io_64.h line 46
Quoted 4 lines
include/asm/io_64.h +3
-0+#define __OUT (s, s1, x) \ +__OUT1(s, x) __OUT2(s, s1, "w") } \ + __OUT1(s##_p, x) __OUT2(s, s1, "w") udelay(_IOPORT_PAUSE_DELAY); } \
With the additional call this should be completely out of line now to save code size. Similar for the in variant.
-Andi
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 5 lines · Andi Kleen
"
With the additional call this should be completely out of line now to save code size. Similar for the in variant.
Sure. Want me to make a new patch with the _p croutines out-of-line?
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 15 lines · David P. Reed
Replace use of outb to "unused" diagnostic port
0x80for time delay with udelay based time delay onx86_64architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
Quoted 3 lines
i386 family fixes (completely parallel) were not included, considering that such machines might involve more risk of problems on legacy machines.
wow, cool fix! (I remember that there were other systems as well that are affected by port 0x80 muckery - i thought we had removed port 0x80 accesses long ago.)
how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
this is also something for v2.6.24 merging.
Ingo
----------------------------->
Subject: x86: fix in/out_p delays
From: Ingo Molnar <[email protected]>
Debugged by David P. Reed <[email protected]>.
Do not use port 0x80, it can cause crashes, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6307
http://bugzilla.kernel.org/show_bug.cgi?id=9511
instead of just removing _p postfixes en masse, lets just first remove the 0x80 port usage, then remove any unnecessary _p io ops gradually. It's more debuggable this way.
--- arch/x86/boot/compressed/misc_32.c | 8 ++++---- arch/x86/boot/compressed/misc_64.c | 8 ++++---- arch/x86/kernel/quirks.c | 9 +++++++++ include/asm-x86/io_32.h | 5 +---- include/asm-x86/io_64.h | 5 +---- 5 files changed, 19 insertions(+), 16 deletions(-)
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -275,10 +275,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)
arch/x86/kernel/quirks.c +9 -0
@@ -6,6 +6,15 @@#include <asm/hpet.h> +/* +* Some legacy devices need delays for IN/OUT sequences. Most are +* probably not needed but it's the safest to just do this short delay: +*/ +void native_io_delay (void ) +{ +udelay (1 ); +} +#if defined(CONFIG_X86_IO_APIC ) && defined(CONFIG_SMP ) && defined(CONFIG_PCI )static void __devinit quirk_intel_irqbalance (struct pci_dev *dev)
include/asm-x86/io_32.h +1 -4
@@ -250,10 +250,7 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +1 -4
@@ -35,10 +35,7 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 8 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
this is also something for v2.6.24 merging.
updated patch attached. (from the MakeItBuild'n'Stuff dept)
Ingo
-------------->
Subject: x86: fix in/out_p delays
From: Ingo Molnar <[email protected]>
Debugged by David P. Reed <[email protected]>.
Do not use port 0x80, it can cause crashes, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6307
http://bugzilla.kernel.org/show_bug.cgi?id=9511
instead of just removing _p postfixes en masse, lets just first remove the 0x80 port usage, then remove any unnecessary _p io ops gradually. It's more debuggable this way.
--- arch/x86/boot/compressed/misc_32.c | 8 ++++---- arch/x86/boot/compressed/misc_64.c | 8 ++++---- arch/x86/kernel/quirks.c | 10 ++++++++++ include/asm-x86/io_32.h | 5 +---- include/asm-x86/io_64.h | 5 +---- 5 files changed, 20 insertions(+), 16 deletions(-)
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -275,10 +275,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)
arch/x86/kernel/quirks.c +10 -0
@@ -3,9 +3,19 @@*/ #include <linux/pci.h> #include <linux/irq.h> +#include <linux/delay.h> #include <asm/hpet.h> +/* +* Some legacy devices need delays for IN/OUT sequences. Most are +* probably not needed but it's the safest to just do this short delay: +*/ +void native_io_delay (void ) +{ +udelay (1 ); +} +#if defined(CONFIG_X86_IO_APIC ) && defined(CONFIG_SMP ) && defined(CONFIG_PCI )static void __devinit quirk_intel_irqbalance (struct pci_dev *dev)
include/asm-x86/io_32.h +1 -4
@@ -250,10 +250,7 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +1 -4
@@ -35,10 +35,7 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 3 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
Your version does the same thing that the version from Pavel/David does for 32-bit at least.
arch/x86/kernel/quirks.c line 16
Quoted 8 lines
arch/x86/kernel/quirks.c +8
-0+/* +* Some legacy devices need delays for IN/OUT sequences. Most are +* probably not needed but it's the safest to just do this short delay: +*/ +void native_io_delay (void ) +{ +udelay (1 ); +}
Also note the thread(s) on LKML where 2 us was decided to be a nicely conservative value:
http://lkml.org/lkml/2007/12/12/309
Also see: http://lkml.org/lkml/2007/12/14/72
And also: http://lkml.org/lkml/2007/12/12/221
As such, please wait a bit for a fuller resolution. We're still discussing this.
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 1 line · Ingo Molnar
updated patch attached. (from the MakeItBuild'n'Stuff dept)
the one below is against current upstream. (previous ones were against x86.git)
Ingo
------------------->
Subject: x86: fix in/out_p delays
From: Ingo Molnar <[email protected]>
Debugged by David P. Reed <[email protected]>.
Do not use port 0x80, it can cause crashes, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6307
http://bugzilla.kernel.org/show_bug.cgi?id=9511
instead of just removing _p postfixes en masse, lets just first remove the 0x80 port usage, then remove any unnecessary _p io ops gradually. It's more debuggable this way.
--- arch/x86/boot/compressed/misc_32.c | 8 ++++---- arch/x86/boot/compressed/misc_64.c | 8 ++++---- arch/x86/kernel/quirks.c | 10 ++++++++++ include/asm-x86/io_32.h | 5 +---- include/asm-x86/io_64.h | 14 +++++--------- 5 files changed, 24 insertions(+), 21 deletions(-)
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/quirks.c +10 -0
@@ -3,9 +3,19 @@*/ #include <linux/pci.h> #include <linux/irq.h> +#include <linux/delay.h> #include <asm/hpet.h> +/* +* Some legacy devices need delays for IN/OUT sequences. Most are +* probably not needed but it's the safest to just do this short delay: +*/ +void native_io_delay (void ) +{ +udelay (1 ); +} +#if defined(CONFIG_X86_IO_APIC ) && defined(CONFIG_SMP ) && defined(CONFIG_PCI )static void __devinit quirk_intel_irqbalance (struct pci_dev *dev)
include/asm-x86/io_32.h +1 -4
@@ -250,10 +250,7 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +5 -9
@@ -35,13 +35,7 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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 native_io_delay (void );/* * Talk about misusing macros..
@@ -54,7 +48,8 @@ __asm__ __volatile__ ("out" #s " %" s1 "#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##_p,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); \ +native_io_delay(); } \#define __IN1 (s) \ static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
@@ -64,7 +59,8 @@ __asm__ __volatile__ ("in" #s " %" s2 "1 #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; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; \ +native_io_delay(); } \#define __INS (s) \ static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 11 lines · Rene Herman
Quoted 6 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
Your version does the same thing that the version from Pavel/David does for 32-bit at least.
well, if you carefully look at the code it's not the "same" but a similar but cleaner thing - it moves this quirk out of a common include file. I take back the "simpler" characterisation - my patch indeed ended up being almost the same as David's.
Quoted 11 lines
Review
Quoted 8 lines
(quoted diff) +8
-0+/* + * Some legacy devices need delays for IN/OUT sequences. Most are + * probably not needed but it's the safest to just do this short delay: + */ +void native_io_delay(void) +{ + udelay(1); +}Also note the thread(s) on LKML where 2 us was decided to be a nicely conservative value:
yep, i have updated the delay to 2 usecs. The latest patch is below, as queued up in x86.git. (not yet queued up for .24 - it's pending testing and more feedback, etc.)
Ingo
----------------->
Subject: x86: fix in_p/out_p crashes
From: David P. Reed <[email protected]>
Do not use port 0x80, it can cause crashes, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6307
http://bugzilla.kernel.org/show_bug.cgi?id=9511
Replace use of outb to "unused" diagnostic port 0x80 for time delay with udelay based time delay on x86_64 architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.
Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
[ [email protected]: minor restructuring, 32-bit support. ]
--- arch/x86/boot/compressed/misc_32.c | 8 ++++---- arch/x86/boot/compressed/misc_64.c | 8 ++++---- arch/x86/kernel/quirks.c | 10 ++++++++++ include/asm-x86/io_32.h | 5 +---- include/asm-x86/io_64.h | 14 +++++--------- 5 files changed, 24 insertions(+), 21 deletions(-)
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/quirks.c +10 -0
@@ -3,9 +3,19 @@*/ #include <linux/pci.h> #include <linux/irq.h> +#include <linux/delay.h> #include <asm/hpet.h> +/* +* Some legacy devices need delays for IN/OUT sequences. Most are +* probably not needed but it's the safest to just do this short delay: +*/ +void native_io_delay (void ) +{ +udelay (2 ); +} +#if defined(CONFIG_X86_IO_APIC ) && defined(CONFIG_SMP ) && defined(CONFIG_PCI )static void __devinit quirk_intel_irqbalance (struct pci_dev *dev)
include/asm-x86/io_32.h +1 -4
@@ -250,10 +250,7 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +5 -9
@@ -35,13 +35,7 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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 native_io_delay (void );/* * Talk about misusing macros..
@@ -54,7 +48,8 @@ __asm__ __volatile__ ("out" #s " %" s1 "#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##_p,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); \ +native_io_delay(); } \#define __IN1 (s) \ static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
@@ -64,7 +59,8 @@ __asm__ __volatile__ ("in" #s " %" s2 "1 #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; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; \ +native_io_delay(); } \#define __INS (s) \ static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 1 line · Ingo Molnar
yep, i have updated the delay to 2 usecs. The latest patch is below, as queued up in x86.git. (not yet queued up for .24 - it's pending testing and more feedback, etc.)
Yes, I'd like feedback on the initial value thing:
http://lkml.org/lkml/2007/12/14/72
and Alan's comments here:
http://lkml.org/lkml/2007/12/12/221
And as to testing -- good luck finding a machine that cares at all ;-)
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 1 line · Rene Herman
And as to testing -- good luck finding a machine that cares at all ;-)
actually, there's a whole lot more testing angle to a change like this than ancient boxes.
Ingo
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 4 lines · Rene Herman
init/main.c +0
-0@@ -229,10 +229,9 @@ static int __init obsolete_checksetup(char *line) }
init/main.c static int __init obsolete_checksetup(char *line) · line 236
Quoted 10 lines
init/main.c +2
-3/* -* This should be approx 2 Bo*oMips to start (note initial shift), and will -* still work even if initially too large, it will just take slightly longer +* Initial value roughly corresponds to a 1 GHz CPU */ -unsigned long loops_per_jiffy = (1 <<12 ); +unsigned long loops_per_jiffy =1000000000 /HZ ;EXPORT_SYMBOL (loops_per_jiffy);
this is a factor of ~2400 increase - this will take an eternity to boot on any older CPU.
Ingo
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 15 lines · Ingo Molnar
Quoted 13 lines · Rene Herman
init/main.c +2
-3@@ -229,10 +229,9 @@ static int __init obsolete_checksetup(char *line) }/* -* This should be approx 2 Bo*oMips to start (note initial shift), and will -* still work even if initially too large, it will just take slightly longer +* Initial value roughly corresponds to a 1 GHz CPU */ -unsigned long loops_per_jiffy = (1 <<12 ); +unsigned long loops_per_jiffy =1000000000 /HZ ;
Quoted 3 lines
init/main.c static int __init obsolete_checksetup(char *line) · line 236
Quoted 1 line
init/main.c +0
-0EXPORT_SYMBOL (loops_per_jiffy);this is a factor of ~2400 increase - this will take an eternity to boot on any older CPU.
Only any outb_p's used before loops_per_jiffy is calibrated are affected.
This pre-calibation thing is what's historically held this change back (it's been discussed dozens of times before). At 4096, not any machine is going to have an appreciable delay before calibration when switching from the outb to
0x80.
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 5 lines
Quoted 2 lines
updated patch attached. (from the MakeItBuild'n'Stuff dept)
the one below is against current upstream. (previous ones were against x86.git)
the last version is the one below. Pending further discussion and testing. And David, i nominate your fix as the coolest Linux kernel fix of 2007 :-)
Ingo
-------------------------------->
Subject: x86: fix in_p/out_p crashes
From: David P. Reed <[email protected]>
Do not use port 0x80, it can cause crashes, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6307
http://bugzilla.kernel.org/show_bug.cgi?id=9511
Replace use of outb to "unused" diagnostic port 0x80 for time delay with udelay based time delay on x86_64 architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.
Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
[ [email protected]: minor restructuring, 32-bit support. ]
--- arch/x86/boot/compressed/misc_32.c | 8 ++++---- arch/x86/boot/compressed/misc_64.c | 8 ++++---- arch/x86/kernel/quirks.c | 10 ++++++++++ include/asm-x86/io_32.h | 5 +---- include/asm-x86/io_64.h | 14 +++++--------- 5 files changed, 24 insertions(+), 21 deletions(-)
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/quirks.c +10 -0
@@ -3,9 +3,19 @@*/ #include <linux/pci.h> #include <linux/irq.h> +#include <linux/delay.h> #include <asm/hpet.h> +/* +* Some legacy devices need delays for IN/OUT sequences. Most are +* probably not needed but it's the safest to just do this short delay: +*/ +void native_io_delay (void ) +{ +udelay (2 ); +} +#if defined(CONFIG_X86_IO_APIC ) && defined(CONFIG_SMP ) && defined(CONFIG_PCI )static void __devinit quirk_intel_irqbalance (struct pci_dev *dev)
include/asm-x86/io_32.h +1 -4
@@ -250,10 +250,7 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +5 -9
@@ -35,13 +35,7 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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 native_io_delay (void );/* * Talk about misusing macros..
@@ -54,7 +48,8 @@ __asm__ __volatile__ ("out" #s " %" s1 "#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##_p,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); \ +native_io_delay(); } \#define __IN1 (s) \ static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
@@ -64,7 +59,8 @@ __asm__ __volatile__ ("in" #s " %" s2 "1 #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; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; \ +native_io_delay(); } \#define __INS (s) \ static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 8 lines · Rene Herman
Quoted 8 lines
Quoted 8 lines
/*
- * This should be approx 2 Bo*oMips to start (note initial shift), and will
- * still work even if initially too large, it will just take slightly longer
+ * Initial value roughly corresponds to a 1 GHz CPU
*/init/main.c +1
-1-unsigned long loops_per_jiffy = (1 <<12 ); +unsigned long loops_per_jiffy =1000000000 /HZ ;
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
EXPORT_SYMBOL(loops_per_jiffy);this is a factor of ~2400 increase - this will take an eternity to boot on any older CPU.
Only any outb_p's used before
loops_per_jiffyis calibrated are affected.
yes - but there are a couple of early udelays, which would thus be affected.
Quoted 4 lines
This pre-calibation thing is what's historically held this change back (it's been discussed dozens of times before). At 4096, not any machine is going to have an appreciable delay before calibration when switching from the outb to
0x80.
i dont think this should matter: old systems that truly _need_ the ISA delay will be slow enough to not trip up. (nor are they really affected by these early delays - the delays were more for crappy ISA devices that get initialized later down, when the delay loop is already calibrated)
modern systems learned to depend on the PCI write posting side-effects of port 0x80 activities - those wont be helped by this initialization change either. That is a far more serious concern.
Ingo
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 10 lines · Ingo Molnar
Quoted 8 lines · Rene Herman
Quoted 8 lines
Quoted 8 lines
/*
- * This should be approx 2 Bo*oMips to start (note initial shift), and will
- * still work even if initially too large, it will just take slightly longer
+ * Initial value roughly corresponds to a 1 GHz CPU
*/init/main.c +1
-1-unsigned long loops_per_jiffy = (1 <<12 ); +unsigned long loops_per_jiffy =1000000000 /HZ ;
Quoted 5 lines
Quoted 3 lines
Quoted 2 lines
Quoted 1 line
EXPORT_SYMBOL(loops_per_jiffy);this is a factor of ~2400 increase - this will take an eternity to boot on any older CPU.
Only any outb_p's used before
loops_per_jiffyis calibrated are affected.yes - but there are a couple of early udelays, which would thus be affected.
True. At the moment though they're just always not delaying anywhere close the intended amount (on anything with more than 2 bogomips). Pre-calibration all this stuff is just broken it seems.
Quoted 3 lines
Quoted 1 line
This pre-calibation thing is what's historically held this change back (it's been discussed dozens of times before). At 4096, not any machine is going to have an appreciable delay before calibration when switching from the outb to
0x80.i dont think this should matter: old systems that truly _need_ the ISA delay will be slow enough to not trip up. (nor are they really affected by these early delays - the delays were more for crappy ISA devices that get initialized later down, when the delay loop is already calibrated)
8253 (DMAC) and 8254 (PIT) have been reported in earlier versions of the thread. By Alan, I believe.
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 9 lines · David P. Reed
Replace use of outb to "unused" diagnostic port
0x80for time delay with udelay based time delay onx86_64architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
Quoted 6 lines
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
kvm will forward a virtual machine's writes to port 0x80 to the real port. The reason is that the write is much faster than exiting and emulating it; the difference is measurable when compiling kernels.
Now if the cause is simply writing to port 0x80, then we must stop doing that. But if the reason is the back-to-back writes, when we can keep it, since the other writes will be trapped by kvm and emulated. Do you which is the case?
Signature · 1 line
Any sufficiently difficult bug is indistinguishable from a feature.
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 5 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
I believe this will suffer from the issue that was raised: this will use udelay() long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)
Worse, I suspect that at least the PIT, which may need to be used for udelay calibration, is one of the devices that may be affected. I have seen the Verilog for a contemporary chipset, and it can only access the PIT once per microsecond -- this actually has to do with the definition of the PIT; some of the PIT operations are ill-defined if allowed at a higher frequency than the PIT clock.
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 4 lines · H. Peter Anvin
I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)Worse, I suspect that at least the PIT, which may need to be used for udelay calibration, is one of the devices that may be affected. I have seen the Verilog for a contemporary chipset, and it can only access the PIT once per microsecond -- this actually has to do with the definition of the PIT; some of the PIT operations are ill-defined if allowed at a higher frequency than the PIT clock.
Was reported before indeed:
http://linux.derkeiler.com/Mailing-Lists/Kernel/2003-09/5764.html
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 7 lines
Quoted 4 lines
i dont think this should matter: old systems that truly _need_ the ISA delay will be slow enough to not trip up. (nor are they really affected by these early delays - the delays were more for crappy ISA devices that get initialized later down, when the delay loop is already calibrated)
8253 (DMAC) and 8254 (PIT) have been reported in earlier versions of the thread. By Alan, I believe.
They've been seen to be problems up to PII era machines. I'm not aware of any newer than that with this problem. We also don't need to touch the DMAC that early anyway that I can see - just the PIT.
In fact if we have a fast processor we have a TSC and APIC so we don't need the PIT ?
Alan
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 9 lines · Alan Cox
Quoted 2 lines
Quoted 1 line
i dont think this should matter: old systems that truly _need_ the ISA delay will be slow enough to not trip up. (nor are they really affected by these early delays - the delays were more for crappy ISA devices that get initialized later down, when the delay loop is already calibrated)
8253 (DMAC) and 8254 (PIT) have been reported in earlier versions of the thread. By Alan, I believe.
They've been seen to be problems up to PII era machines. I'm not aware of any newer than that with this problem. We also don't need to touch the DMAC that early anyway that I can see - just the PIT.
In fact if we have a fast processor we have a TSC and APIC so we don't need the PIT ?
Well, the TSC may be unstable and the APIC may be disabled.
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Alan CoxQuoted 8 lines · Alan Cox
Quoted 7 lines
Quoted 4 lines
i dont think this should matter: old systems that truly _need_ the ISA delay will be slow enough to not trip up. (nor are they really affected by these early delays - the delays were more for crappy ISA devices that get initialized later down, when the delay loop is already calibrated)
8253 (DMAC) and 8254 (PIT) have been reported in earlier versions of the thread. By Alan, I believe.
Quoted 6 lines
They've been seen to be problems up to PII era machines. I'm not aware of any newer than that with this problem. We also don't need to touch the DMAC that early anyway that I can see - just the PIT.
In fact if we have a fast processor we have a TSC and APIC so we don't need the PIT ?
It is still good to be able to disable APIC/TSC. Neither are particulary reliable time sources.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 10 lines · H. Peter Anvin
Quoted 5 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)
how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)
?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 8 lines · Pavel Machek
Quoted 4 lines · H. Peter Anvin
Quoted 2 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.) how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
How long will that take to boot on a 386?
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 8 lines · On Fri, 14 Dec 2007 14:13:46 -0800 "H. Peter Anvin" <[email protected]> wrote:
Quoted 7 lines · Pavel Machek
Quoted 6 lines · H. Peter Anvin
Quoted 5 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)
how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
How long will that take to boot on a 386?
Well the dumb approach to fix that would seem to be to initialise it to
cpu->family 3 -> 50MHz 4 -> 300Mhz 5-> etc...
Alan
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Avi KivityQuoted 4 lines · Avi Kivity
kvm will forward a virtual machine's writes to port
0x80to the real port. The reason is that the write is much faster than exiting and emulating it; the difference is measurable when compiling kernels.Now if the cause is simply writing to port
0x80, then we must stop doing that. But if the reason is the back-to-back writes, when we can keep it, since the other writes will be trapped by kvm and emulated. Do you which is the case?
As for kvm, I don't have enough info to know anything about that. Is there a test you'd like me to try?
I think you are also asking if the crash on these laptops is caused only by back-to-back writes. Actually, it doesn't seem to matter if they are back to back. I can cause the crash if the writes to 80 are very much spread out in time - it seems only to matter how many of them get executed - almost as if there is a buffer overflow. (And of course if you do back to back writes to other ports that are apparently fully unused, such as 0xED on my machine, no crash occurs).
I believe (though no one seems to have confirming documentation from the chipset or motherboard vendor) that port 80 is actually functional for some unknown function on these machines. (They do respond to "in" instructions faster than a bus cycle abort does - more evidence).
I searched the DSDT to see if there is any evidence of an ACPI use for this port, but found nothing.
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 6 lines · David P. Reed
I believe (though no one seems to have confirming documentation from the chipset or motherboard vendor) that port 80 is actually functional for
some unknown function on these machines. (They do respond to "in"
instructions faster than a bus cycle abort does - more evidence).
This is normal. IN from port 0x80 is used by the DMA address map chip.
As far as I understand, there are other laptops with the same chipset which don't have this problem, so it's likely either a motherboard or firmware issue. My guess is that they probably let debugging code out in the field (trap port 0x80 in SMM, and then try to output it on some debugging bus.)
-hpa
-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Alan CoxJust a thought for a way to fix the "very early" timing needed to set up udelay to work in a way that works on all machines. Perhaps we haven't exploited the BIOS enough: The PC BIOS since the PC AT (286) has always had a standard "countdown timer" way to delay for n microseconds, which as far as I know still works. This can be used to measure the speed of a delay loop, without using ANY in/out instructions directly (the ones in the BIOS are presumably correctly delayed...).
So first thing in the boot sequence, one can calibrate a timing loop using this technique, and save the value to be used for all the "early" stuff.
Here's skeleton code from old ASM code I found lying around in my archives to use BIOS to measure how many unrolled short jumps can execute in 10 msec. Note that it can run without knowing anything whatsoever about port timing.
haltbyte db 0
calibrate:
les bx,haltbyte ; address of halt flag into es:bx mov ax,8300h
sub cx,cx
mov dx,10000 ; 10 msec. in cx:dx
int 15h
jc bad
sub dx,dx
sub cx,cx ; decrement counter in dx:cx
tloop:
jmp short $+2 ; 10 short jmps
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
jmp short $+2
test haltbyte
loopz tloop
jnz done
dec dx
jnz tloop
" overflowed 32 bits ... never happens, cancel BIOS event wait.
mov ax,8301h
int 15h
jmp error
done:
mov ax,cx
negl
" here dx:ax contains 32 bit loop count corresponding to 10 msec.
ret ; return 32-bit value
Doc on function 83h of int 15h should be available online.
Quoted 28 lines · Alan Cox
Quoted 9 lines · On Fri, 14 Dec 2007 14:13:46 -0800 "H. Peter Anvin" <[email protected]> wrote:
Quoted 7 lines · Pavel Machek
Quoted 5 lines · H. Peter Anvin
Quoted 3 lines · Ingo Molnar
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.) how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
How long will that take to boot on a 386?
Well the dumb approach to fix that would seem to be to initialise it to
cpu->family 3 -> 50MHz 4 -> 300Mhz 5-> etc...Alan
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 1 line · David P. Reed
Just a thought for a way to fix the "very early" timing needed to set up udelay to work in a way that works on all machines. Perhaps we haven't exploited the BIOS enough: The PC BIOS since the PC AT (286) has always had a standard "countdown timer" way to delay for n microseconds, which as far as I know still works. This can be used to measure the speed of a delay loop, without using ANY in/out instructions directly (the ones in the BIOS are presumably correctly delayed...).
If we enter from the 32-bit entrypoint, we already don't have access to the BIOS, though.
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 10 lines · H. Peter Anvin
I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)Worse, I suspect that at least the PIT, which may need to be used for udelay calibration, is one of the devices that may be affected. I have seen the Verilog for a contemporary chipset, and it can only access the PIT once per microsecond -- this actually has to do with the definition of the PIT; some of the PIT operations are ill-defined if allowed at a higher frequency than the PIT clock.
i think the native_io_delay() in quirks.c signals the obvious solution:
a DMI (or otherwise) driven quirk that activates a port 0x80 based delay on such boards. Combined with an iodelay=port80 boot option as well perhaps, just in case someone hits a system that is not blacklisted yet. This way such crazy broken hardware can be mapped correctly - like we map such quirks in every other case. Perhaps even do this workaround on the PIT driver level. Instead of perpetuating the superstition of port 80 forever.
Ingo
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 7 lines · Ingo Molnar
Quoted 3 lines · H. Peter Anvin
I believe this will suffer from the issue that was raised: this will use
udelay()long before loop calibration (and no, we can't just "be conservative" since there is no "conservative" value we can use.)Worse, I suspect that at least the PIT, which may need to be used for udelay calibration, is one of the devices that may be affected. I have seen the Verilog for a contemporary chipset, and it can only access the PIT once per microsecond -- this actually has to do with the definition of the PIT; some of the PIT operations are ill-defined if allowed at a higher frequency than the PIT clock.
i think the
native_io_delay()inquirks.csignals the obvious solution: a DMI (or otherwise) driven quirk that activates a port0x80based delay on such boards. Combined with an iodelay=port80 boot option as well perhaps, just in case someone hits a system that is not blacklisted yet. This way such crazy broken hardware can be mapped correctly - like we map such quirks in every other case. Perhaps even do this workaround on the PIT driver level. Instead of perpetuating the superstition of port 80 forever.
The issue is -- how do you safely replace the outb pre-loops_per_jiffy calibration? I'm currently running with the attached hack (not submitted, only for 32-bit and discussion) the idea of which might be the best we can do?
(And the broken is the hardware that can't take writes to port 0x80, not the other way around. It's a well-known legacy PC thing).
Rene.
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/kernel/time_32.c +15 -0
@@ -222,6 +222,19 @@ void __init hpet_time_init(void)time_init_hook (); } +static void port_io_delay (void ) +{ + asmvolatile ("outb %%al, $0x80" : : :"memory" ); +} + +static void udelay_io_delay (void ) +{ +udelay (2 ); +} + +void (*native_io_delay)(void ) = port_io_delay; +EXPORT_SYMBOL (native_io_delay); +/* * This is called directly from init code; we must delay timer setup in the * HPET case as we can't make the decision to turn on HPET this early in the
@@ -233,5 +246,7 @@ void __init hpet_time_init(void)void __init time_init (void ) {tsc_init (); +if (!tsc_disable) + native_io_delay = udelay_io_delay; late_time_init =choose_time_init (); }
include/asm-x86/io_32.h +1 -4
@@ -250,10 +250,7 @@ static inline void flush_write_buffers(void)#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void (*native_io_delay)(void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Alan CoxHello,
Quoted 11 lines · On Fri, 14 Dec 2007 23:29:55 +0000 Alan Cox <[email protected]> wrote:
Quoted 4 lines · On Fri, 14 Dec 2007 14:13:46 -0800 "H. Peter Anvin" <[email protected]> wrote:
Quoted 1 line · Pavel Machek
On Fri 2007-12-14 10:02:57, H. Peter Anvin wrote:
How long will that take to boot on a 386?
Well the dumb approach to fix that would seem to be to initialise it to
cpu->family 3 -> 50MHz 4 -> 300Mhz 5-> etc...
Just an idea : from what I've read, the problem (port 80 hanging) only occurs on 'modern' machines... So why not :
- use port 80 for old CPUs (PII, PIII) where it has never really been a problem,
- use the cpu->family to do a best match for CPU freq
thus we could avoid increasing boot time too much...
Paul
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 13 lines · Paul Rolland
Hello,
Quoted 8 lines · On Fri, 14 Dec 2007 23:29:55 +0000 Alan Cox <[email protected]> wrote:
Quoted 3 lines · On Fri, 14 Dec 2007 14:13:46 -0800 "H. Peter Anvin" <[email protected]> wrote:
Quoted 1 line · Pavel Machek
On Fri 2007-12-14 10:02:57, H. Peter Anvin wrote:
How long will that take to boot on a 386?
Well the dumb approach to fix that would seem to be to initialise it to
Quoted 8 lines
Quoted 1 line
cpu->family 3 -> 50MHz 4 -> 300Mhz 5-> etc...Just an idea : from what I've read, the problem (port 80 hanging) only occurs on 'modern' machines... So why not :
- use port 80 for old CPUs (PII, PIII) where it has never really been a problem,
- use thecpu->familyto do a best match for CPU freq
thus we could avoid increasing boot time too much...
Yes, just posted a Patch-For-Comments that switches on the availability of a TSC (tsc_init sets tsc_disable also for !cpu_has_tsc) which would mean that only really old stuff would be using the outb still. A TSC is really all we need to have a sensible udelay().
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 4 lines · Rene Herman
The issue is -- how do you safely replace the outb pre-loops_per_jiffy calibration? I'm currently running with the attached hack (not submitted, only for 32-bit and discussion) the idea of which might be the best we can do?
how about doing a known-NOP chipset cycle? For example:
inb(PIC_SLAVE_IMR)
? I.e. instead of trying to find an unused port, lets try to find a known-used platform register that has no side-effects if read. Use it unconditionally during early bootup and change it to an udelay after calibration. (or use it after early bootup too if a boot parameter has been specified) Or something like this.
Ingo
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 7 lines · Ingo Molnar
Quoted 1 line · Rene Herman
The issue is -- how do you safely replace the outb pre-loops_per_jiffy calibration? I'm currently running with the attached hack (not submitted, only for 32-bit and discussion) the idea of which might be the best we can do?
how about doing a known-NOP chipset cycle? For example:
inb(PIC_SLAVE_IMR)
An inb is annoying in that it clobbers register al (well, with an inline native_io_delay it is at least) and more importantly -- the timing of this is going to vary wildly. We really want a register that is effectively guaranteed to be unused so that it dies on ISA/LPC or we might get _much_ faster PCI only decodes. Even reading port 0x80 itself varies wildly:
http://lkml.org/lkml/2007/12/12/309
Quoted 1 line
? I.e. instead of trying to find an unused port, lets try to find a known-used platform register that has no side-effects if read. Use it unconditionally during early bootup and change it to an udelay after calibration. (or use it after early bootup too if a boot parameter has been specified) Or something like this.
It's really going to have to be a known _un_used register and (the write direction of) port 0x80 is used exactly for that reason. Port 0xed is a known "alternate diagnostic port" used by Phoenix BIOSes at least but Peter Anvin reported trouble with that one -- probably for the outb direction but assuming that means something was in fact responding, we'd have the same timing problem.
I believe we have two "good" options:
1) port 0xed was tested by the current reporter and found to be safe (and provide slow enough timing). If DMI based quirk hacks are available soon enough we can switch 0x80 to 0xed based on it. Are they?
2) the thing I posted in the message replied to where immediately after tsc_init() (which is before the PIT init) we switch to udelay() if we have a TSC which is ofcourse anything modern.
Rene.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 11 lines · On Sat, 15 Dec 2007 14:27:25 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 4 lines · Rene Herman
The issue is -- how do you safely replace the outb pre-loops_per_jiffy calibration? I'm currently running with the attached hack (not submitted, only for 32-bit and discussion) the idea of which might be the best we can do?
how about doing a known-NOP chipset cycle? For example:
inb(PIC_SLAVE_IMR)
It needs tobe a different chip to the main one (or macrocell anyway) - so PIC for PIT and vice versa. However since we know 0x80 works for everything on the planet but this one specifies of laptop which seems to need a firmware update its a very high risk approach.
Alan
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
I understand the risks of such a fundamental change, and it may be only a minor concern, but I did also point out that using an unused port causes the bus to be tied up for a microsecond or two, which matters on a fast SMP machine.
Of course all the other concerns you guys are worrying about are really important. I don't want to break anybody's running systems... I'd like to see my machine run smoothly, and all the other machines that may or may not have this problem (google "hwclock freeze" to see that I'm far from alone - I just have persevered in "bisecting" this problem with kernel tweaks for months, whereas the others did not or did not know how).
By the way, this laptop is really nice for Linux in lots of ways. Dual drives, so I set it up with software RAID for reliability, dual 64-bit processors, fast 3D graphics, etc. Great battery life. Just one last kernel issue.
I also note that curent machines like the problem machine have ACPI, and maybe those would be the ones that vendors might start to define port 80 to mean something. As I noted, it /seems/ to be only when ACPI is turned on that this problem happens on my machine - that's when the OS starts to be involved in servicing various things, so it suggests that maybe things change about port 80's unknown function on these machines when ACPI is servicing the system management code (that's not something I have been able to verify).
My belief is that my machine has some device that is responding to port 80 by doing something. And that something requires some other program to "service" port 80 in some way. But it sure would be nice to know. I can't personally sand off the top of the chipset to put probes into it - so my normal approach of putting a logic analyzer on the bus doesn't work.
PS: If I have time, I may try to build Rene's port 80 test for Windows and run it under WinXP on this machine (I still have a crappy little partition that boots it). If it freezes the same way, it's almost certain a design "feature", and if it doesn't freeze, we might suspect that there is compensating logic in either Windows ACPI code or some way that windows "sets up" the machine.
Quoted 22 lines · Alan Cox
Quoted 9 lines · On Sat, 15 Dec 2007 14:27:25 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 2 lines · Rene Herman
The issue is -- how do you safely replace the outb pre-loops_per_jiffy calibration? I'm currently running with the attached hack (not submitted, only for 32-bit and discussion) the idea of which might be the best we can do?
how about doing a known-NOP chipset cycle? For example:
inb(PIC_SLAVE_IMR)It needs tobe a different chip to the main one (or macrocell anyway) - so PIC for PIT and vice versa. However since we know
0x80works for everything on the planet but this one specifies of laptop which seems to need a firmware update its a very high risk approach.Alan
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
This change seems rather unlikely for 2.6.24 at this point (high risk), but could be good for 2.6.25.
One thing it should probably have for the early going, is a simple way to turn it on/off at boot time, so that we don't have people "stuck" unable to run the test kernels should something weird happen.
Alan / David / Ingo,
What do you think of the idea of a *temporary* boot flag for this, something like port80=on/off (pick a suitable name) ?
Cheers
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 5 lines · H. Peter Anvin
Quoted 1 line · David P. Reed
Just a thought for a way to fix the "very early" timing needed to set up udelay to work in a way that works on all machines. Perhaps we haven't exploited the BIOS enough: The PC BIOS since the PC AT (286) has always had a standard "countdown timer" way to delay for n microseconds, which as far as I know still works. This can be used to measure the speed of a delay loop, without using ANY in/out instructions directly (the ones in the BIOS are presumably correctly delayed...).
If we enter from the 32-bit entrypoint, we already don't have access to the BIOS, though.
My understanding is that the linux starts in real mode, and uses the BIOS for such things as reading the very first image. arch/x86/boot/main.c seems to use BIOS calls, and one can do what I wrote in C or asm. Good place to measure the appropriate delay timing, and pass it on forward. That's what I was suggesting, which is why I copied the ASM routine from my old code listing as I did.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 2 lines
My understanding is that the linux starts in real mode, and uses the BIOS for such things as reading the very first image.
Not always. We may enter from 32bit in some cases, and we may also not have a PC BIOS in the first place.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 3 lines
a minor concern, but I did also point out that using an unused port causes the bus to be tied up for a microsecond or two, which matters on a fast SMP machine.
And I did point out I'd found locking cases that may be relying upon this
Quoted 3 lines
I also note that curent machines like the problem machine have ACPI, and maybe those would be the ones that vendors might start to define port 80 to mean something. As I noted, it /seems/ to be only when ACPI is turned
Port 0x80 means debug. You appear to have a laptop with some kind of buggy firmware that wants a BIOS update. Everyone use 0x80 for debug - its in the chipset hardware quite often.
Quoted 5 lines
My belief is that my machine has some device that is responding to port 80 by doing something. And that something requires some other program to "service" port 80 in some way. But it sure would be nice to know. I can't personally sand off the top of the chipset to put probes into it
- so my normal approach of putting a logic analyzer on the bus doesn't work.
Almost certainly a SMI trap.
Quoted 2 lines
PS: If I have time, I may try to build Rene's port 80 test for Windows and run it under WinXP on this machine
That would be very interesting.
Alan
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 3 lines · Rene Herman
It's really going to have to be a known
_un_usedregister and (the write direction of) port0x80is used exactly for that reason. Port0xedis a known "alternate diagnostic port" used by Phoenix BIOSes at least but Peter Anvin reported trouble with that one -- probably for the outb direction but assuming that means something was in fact responding, we'd have the same timing problem.
Yes, for the outbound direction.
Quoted 3 lines
I believe we have two "good" options:
1) port
0xedwas tested by the current reporter and found to be safe (and provide slow enough timing). If DMI based quirk hacks are available soon enough we can switch0x80to0xedbased on it. Are they?
DMI is just a data structure parked in memory, so it should at least be theoretically possible to get to it.
-hpa
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Paul RollandQuoted 2 lines · Paul Rolland
Just an idea : from what I've read, the problem (port 80 hanging) only occurs on 'modern' machines...
It happens on *one single* "modern" machine...
Let's keep that in perspective.
-hpa
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 3 lines · Rene Herman
Yes, just posted a Patch-For-Comments that switches on the availability of a TSC (
tsc_initsetstsc_disablealso for !cpu_has_tsc) which would mean that only really old stuff would be using the outb still. A TSC is really all we need to have a sensibleudelay().
Uhm, no. You have no clue what the speed of the TSC is until you have been able to calibrate it against a fixed timesource - like the PIT.
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 8 lines · H. Peter Anvin
Quoted 3 lines · Paul Rolland
Just an idea : from what I've read, the problem (port 80 hanging) only occurs
on 'modern' machines...It happens on *one single* "modern" machine...
Let's keep that in perspective.
it hurts on other machines (like debug leds being useless), and it may be incorrect as soon as you insert leds-on-port-0x80-on-PCI card.
No, it is not critical but yes, I'd like to see it fixed.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 16 lines · Ingo Molnar
Quoted 13 lines · Rene Herman
init/main.c +2
-3@@ -229,10 +229,9 @@ static int __init obsolete_checksetup(char *line) }/* -* This should be approx 2 Bo*oMips to start (note initial shift), and will -* still work even if initially too large, it will just take slightly longer +* Initial value roughly corresponds to a 1 GHz CPU */ -unsigned long loops_per_jiffy = (1 <<12 ); +unsigned long loops_per_jiffy =1000000000 /HZ ;
Quoted 4 lines
init/main.c static int __init obsolete_checksetup(char *line) · line 236
Quoted 1 line
init/main.c +0
-0EXPORT_SYMBOL (loops_per_jiffy);this is a factor of ~2400 increase - this will take an eternity to boot on any older CPU.
I don't think we are using outb_p before loops_per_jiffy are initialized -- I believe I'd see oopsen if we did. Factor 2400 increase is bad, but if it only converts 10x 1usec delay into 10x 24msec delay, it is not _that_ bad.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 22 lines · Ingo Molnar
Quoted 15 lines · David P. Reed
Replace use of outb to "unused" diagnostic port
0x80for time delay with udelay based time delay onx86_64architecture machines. Fix for bugs 9511 and 6307 in bugzilla, plus bugs reported in bugzilla.redhat.com.Derived from suggestion (that didn't compile) by Pavel Machek, and tested, also based on measurements of typical timings of out's collated by Rene Herman from many in the community.
This patch fixes a number of bugs known to cause problems on HP Pavilion dv9000z and dv6000z laptops - in the form of solid freezes when hwclock is used to show or set the time. Also, it potentially improves bus utilization on SMP machines, by using a waiting process that doesn't tie up the ISA/LPC bus for 1 or 2 microseconds.
Quoted 3 lines
i386 family fixes (completely parallel) were not included, considering that such machines might involve more risk of problems on legacy machines.
Quoted 8 lines
wow, cool fix! (I remember that there were other systems as well that are affected by port
0x80muckery - i thought we had removed port0x80accesses long ago.)how about the simpler fix below, as a first-level approach? We can then remove the _p in/out sequences after this.
this is also something for v2.6.24 merging.
As much as I like this patch, I do not think it is suitable for .24. Too risky, I'd say.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 6 lines · Pavel Machek
Quoted 2 lines
this is also something for v2.6.24 merging.
As much as I like this patch, I do not think it is suitable for .24. Too risky, I'd say.
No kidding! We're talking about removing a hack that has been successful on thousands of pieces of hardware over 15 years because it breaks ONE machine.
If this should be done at all it should be done in the most careful manner possible. 2.6.25 would be an aggressive schedule.
-hpa
PATCH 1/1 x86: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 5 lines · H. Peter Anvin
Quoted 2 lines · Rene Herman
Yes, just posted a Patch-For-Comments that switches on the availability of a TSC (
tsc_initsetstsc_disablealso for !cpu_has_tsc) which would mean that only really old stuff would be using the outb still. A TSC is really all we need to have a sensibleudelay().Uhm, no. You have no clue what the speed of the TSC is until you have been able to calibrate it against a fixed timesource - like the PIT.
Yes. Hnng. Okay, this is going nowhere in a hurry, so back to the very first suggestion in this thread. How about this? This allows to switch from port 0x80 to port 0xed based on DMI.
David: I plugged in my own DMI values for testing, but obviously yours are needed. The values that are needed are retrieved by the "dmidecode" program which you will probably have installed (it might be in an sbin directory) or will be able to install through whatever package manager you use.
dmidecode -s baseboard-manufacturer
dmidecode -s baseboard-product-name
are the values you should plug into the .matches field in the dmi_system_id struct in this. It would be great if you could do that, test, and post back with those values. .ident should be a nice human name.
It's been tested on x86-32 and seems to work fine. It's not been tested on x86-64 but seems to stand a fair chance of working similarly.
It ofcourse remains possible to switch to a udelay() based method later on anyways but with all the pre-calibratin trouble, this might be the lowest risk method in the short run.
This is partly based on previous patches by Pavel Machek and David P. Reed.
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.
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 | 53 +++++++++++++++++++++++++++++++++++++ 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 ++++++----------
commit 4a7e75776c648102488a89dbfad516448830ab1a
Author: Rene Herman <[email protected]> Date: Sun Dec 16 00:24:32 2007 +0100
foo
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +53 -0
53 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +3 -14
@@ -250,24 +250,13 @@ static inline void flush_write_buffers(void)#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("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
include/asm-x86/io_64.h +9 -14
@@ -35,13 +35,8 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
H. Peter Anvin
reviewerRe: [PATCH] x86: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 3 lines · Rene Herman
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 everyoutb_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) -- of course, if there is a reason to do it for paravirtualization then that's fine; we're talking about something that makes even the slowest CPU operation look speedy anyhow.
If in*_p and out*_p are out-of-lined then %dx would be dead anyway, and so there is even less reason to deal with it.
In theory we could use an alternatives section and patch the instruction, too; seems like way overkill, though.
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.
-hpa
H. Peter Anvin
reviewerRe: [PATCH] x86: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 3 lines · H. Peter Anvin
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.)
Correction: DMI data are at least supposedly available via the PNPBIOS calls specified in the SMBIOS spec.
-hpa
Re: [PATCH] x86: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanHere we go.
# dmidecode -s baseboard-manufacturer Quanta # dmidecode -s baseboard-product-name 30B9
There do seem to be other systems, besides mine, that have the same problem. I think it's pretty likely that other machines that have this problem are Quanta machines, since Quanta is one of the primary ODM's that does HP laptops. Don't know about the product-name being common with the HP dv6000z family, which is another one reported to have this problem. We could try to ask all the reporters of hwclock freezes to report their results from dmidecode.
Quoted 38 lines · Rene Herman
Quoted 5 lines · H. Peter Anvin
Quoted 2 lines · Rene Herman
Yes, just posted a Patch-For-Comments that switches on the availability of a TSC (
tsc_initsetstsc_disablealso for !cpu_has_tsc) which would mean that only really old stuff would be using the outb still. A TSC is really all we need to have a sensibleudelay().Uhm, no. You have no clue what the speed of the TSC is until you have been able to calibrate it against a fixed timesource - like the PIT.
Yes. Hnng. Okay, this is going nowhere in a hurry, so back to the very first suggestion in this thread. How about this? This allows to switch from port
0x80to port0xedbased on DMI.David: I plugged in my own DMI values for testing, but obviously yours are needed. The values that are needed are retrieved by the "dmidecode" program which you will probably have installed (it might be in an sbin directory) or will be able to install through whatever package manager you use.
dmidecode -s baseboard-manufacturer
dmidecode -s baseboard-product-nameare the values you should plug into the .matches field in the
dmi_system_idstruct in this. It would be great if you could do that, test, and post back with those values. .ident should be a nice human name.It's been tested on x86-32 and seems to work fine. It's not been tested on x86-64 but seems to stand a fair chance of working similarly.
It ofcourse remains possible to switch to a
udelay()based method later on anyways but with all the pre-calibratin trouble, this might be the lowest risk method in the short run.This is partly based on previous patches by Pavel Machek and David P. Reed.
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 everyoutb_p, which would then have to be reloaded for the next outb again). Comments appreciated.Signed-off-by Rene Herman <[email protected]>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 | 53 +++++++++++++++++++++++++++++++++++++ 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 ++++++----------
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 7 lines · H. Peter Anvin
Quoted 2 lines · Paul Rolland
Just an idea : from what I've read, the problem (port 80 hanging) only occurs on 'modern' machines...
It happens on *one single* "modern" machine...
Let's keep that in perspective.
two or three i think (and an unknown of others where "random, unexplained freezes" were thought to be hw borkage), but yeah, it's still a very low proportion.
Ingo
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 10 lines · H. Peter Anvin
Quoted 6 lines · Pavel Machek
Quoted 2 lines
this is also something for v2.6.24 merging.
As much as I like this patch, I do not think it is suitable for .24. Too risky, I'd say.
No kidding! We're talking about removing a hack that has been successful on thousands of pieces of hardware over 15 years because it
^----[*]
Quoted 1 line
breaks ONE machine.
[*] "- none of which needs it anymore -"
there, fixed it for you ;-)
So lets keep this in perspective: this is a hack that only helps on a very low number of systems. (the PIT of one PII era chipset is known to be affected)
unfortunately this hack's side-effects are mis-used by an unknown number of drivers to mask PCI posting bugs. We want to figure out those bugs (safely and carefully) and we want to remove this hack from modern machines that dont need it. Doing anything else would be superstition.
anyway, we likely wont be doing anything about this in .24.
Ingo
PATCH 1/1 x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 5 lines · H. Peter Anvin
Quoted 2 lines · Rene Herman
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 everyoutb_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?
Quoted 3 lines
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.
commit a17ccb1964b53fd4ab00d501b7f229a9a6cf91d1
Author: Rene Herman <[email protected]> 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.
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +54 -0
54 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +3 -14
@@ -250,24 +250,13 @@ static inline void flush_write_buffers(void)#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("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
include/asm-x86/io_64.h +9 -14
@@ -35,13 +35,8 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 2 lines · Rene Herman
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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 3 lines · Rene Herman
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.)
Quoted 3 lines
Quoted 1 line
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
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Ingo MolnarQuoted 8 lines · Ingo Molnar
Quoted 6 lines · H. Peter Anvin
Quoted 4 lines · Pavel Machek
Quoted 1 line
this is also something for v2.6.24 merging.
As much as I like this patch, I do not think it is suitable for .24. Too risky, I'd say.
No kidding! We're talking about removing a hack that has been successful on thousands of pieces of hardware over 15 years because it
Quoted 8 lines
^----[*]Quoted 1 line
breaks ONE machine.
[*] "- none of which needs it anymore -"
there, fixed it for you ;-)
So lets keep this in perspective: this is a hack that only helps on a very low number of systems. (the PIT of one PII era chipset is known to be affected)
Yes, but the status quo has been *tested* on thousands of systems and is known to work. Thus, changing it puts things into unknown territory, even if only a small number of machines actually need the current configuration.
Heck, there are only a small number of 386/486 machines still in operation and being actively updated.
Quoted 3 lines
unfortunately this hack's side-effects are mis-used by an unknown number of drivers to mask PCI posting bugs. We want to figure out those bugs (safely and carefully) and we want to remove this hack from modern machines that dont need it. Doing anything else would be superstition.
anyway, we likely wont be doing anything about this in .24.
Again, 24 is "right out". 25 is a "maybe", IMO. Rene's fix could be an exception, since it is a DMI-keyed workaround for a specific machine and doesn't change behaviour in general.
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
The process of safely making delicate changes here is beyond my responsibility as just a user - believe me, I'm not suggesting that a risky fix be put in .24. I can patch my own kernels, and I can even share an unofficial patch with others for now, or suggest that Fedora and Ubuntu add it to their downstream.
May I make a small suggestion, though. If the decision is a DMI-keyed switch from out-80 to udelay(2) gets put in, perhaps there should also be a way for people to test their own configuration for the underlying problem made available as a script. Though it is a "hack", all you need to freeze a problem system is to run a loop doing about 1000 "cat /dev/nvram > /dev/null" commands. If that leads to a freeze, one might ask to have the motherboard added to the DMI-key list.
Quoted 30 lines · H. Peter Anvin
Quoted 8 lines · Ingo Molnar
Quoted 6 lines · H. Peter Anvin
Quoted 4 lines · Pavel Machek
Quoted 1 line
this is also something for v2.6.24 merging.
As much as I like this patch, I do not think it is suitable for .24. Too risky, I'd say.
No kidding! We're talking about removing a hack that has been successful on thousands of pieces of hardware over 15 years because it
Quoted 8 lines
^----[*]Quoted 1 line
breaks ONE machine.
[*] "- none of which needs it anymore -"
there, fixed it for you ;-)
So lets keep this in perspective: this is a hack that only helps on a very low number of systems. (the PIT of one PII era chipset is known to be affected)
Yes, but the status quo has been *tested* on thousands of systems and is known to work. Thus, changing it puts things into unknown territory, even if only a small number of machines actually need the current configuration.
Heck, there are only a small number of 386/486 machines still in operation and being actively updated.
Quoted 3 lines
unfortunately this hack's side-effects are mis-used by an unknown number of drivers to mask PCI posting bugs. We want to figure out those bugs (safely and carefully) and we want to remove this hack from modern machines that dont need it. Doing anything else would be superstition.
anyway, we likely wont be doing anything about this in .24.
Again, 24 is "right out". 25 is a "maybe", IMO. Rene's fix could be an exception, since it is a DMI-keyed workaround for a specific machine and doesn't change behaviour in general.
-hpa
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 2 lines · Rene Herman
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.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedHi!
Quoted 6 lines
The process of safely making delicate changes here is beyond my responsibility as just a user - believe me, I'm not suggesting that a risky
fix be put in .24. I can patch my own kernels, and I can even share an
unofficial patch with others for now, or suggest that Fedora and Ubuntu add it to their downstream.
Quoted 7 lines
May I make a small suggestion, though. If the decision is a DMI-keyed
switch from out-80 to udelay(2) gets put in, perhaps there should also be a way for people to test their own configuration for the underlying problem
made available as a script. Though it is a "hack", all you need to freeze
a problem system is to run a loop doing about 1000 "cat/dev/nvram>/dev/null" commands. If that leads to a freeze, one might ask to have the motherboard added to the DMI-key list.
Can you freeze it by catting /dev/rtc, too? That may be significant, because that is readable for group audio (at least on some systems)... which would smell like "small security hole" to me.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 10 lines · Pavel Machek
Hi!
Quoted 3 lines
The process of safely making delicate changes here is beyond my responsibility as just a user - believe me, I'm not suggesting that a risky fix be put in .24. I can patch my own kernels, and I can even share an unofficial patch with others for now, or suggest that Fedora and Ubuntu add it to their downstream.
May I make a small suggestion, though. If the decision is a DMI-keyed switch from out-80 to udelay(2) gets put in, perhaps there should also be a way for people to test their own configuration for the underlying problem made available as a script. Though it is a "hack", all you need to freeze a problem system is to run a loop doing about 1000 "cat
/dev/nvram>/dev/null" commands. If that leads to a freeze, one might ask to have the motherboard added to the DMI-key list.Can you freeze it by catting
/dev/rtc, too? That may be significant, because that is readable for group audio (at least on some systems)... which would smell like "small security hole" to me.
Pavel
Heck, on my system (Fedora 7), it's mode 644...
-hpa
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 7 lines · Ingo Molnar
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 itif 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.
commit 5001121e449040aa9cc021f69bfb191662c13004
Author: Rene Herman <[email protected]> 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.
Documentation/kernel-parameters.txt +8 -0
@@ -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.
arch/x86/Kconfig.debug +9 -0
@@ -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
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +106 -0
106 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +6 -2
@@ -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 ) { - asmvolatile ("outb %%al,$0x80" : : :"memory" ); } +#endif +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +22 -11
@@ -35,13 +35,24 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 1 line · H. Peter Anvin
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.
Quoted 5 lines
Quoted 1 line
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.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 1 line · H. Peter Anvin
Again, 24 is "right out". 25 is a "maybe", IMO. Rene's fix could be an exception, since it is a DMI-keyed workaround for a specific machine and doesn't change behaviour in general.
I've not much opinion on the schedule as I've not the problem but yes, it's intended as the low risk option.
Rene.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 3 lines · Rene Herman
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 4 lines · David P. Reed
Quoted 2 lines · Rene Herman
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.
commit 5001121e449040aa9cc021f69bfb191662c13004
Author: Rene Herman <[email protected]> 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.
Documentation/kernel-parameters.txt +8 -0
@@ -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.
arch/x86/Kconfig.debug +9 -0
@@ -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
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +106 -0
106 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +6 -2
@@ -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 ) { - asmvolatile ("outb %%al,$0x80" : : :"memory" ); } +#endif +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +22 -11
@@ -35,13 +35,24 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 9 lines · Rene Herman
Quoted 4 lines · David P. Reed
Quoted 2 lines · Rene Herman
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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 4 lines · Rene Herman
Quoted 2 lines · Ingo Molnar
looks good to me. Could you please also provide three more controls that i suggested earlier:
Quoted 8 lines
Quoted 5 lines
- a boot option enabling/disabling the udelay based code
- a .config method of enabling/disabling the udelay based code
- a sysctl to toggle itif 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_delaybeing 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 6 lines · H. Peter Anvin
Quoted 5 lines · Rene Herman
Quoted 3 lines · David P. Reed
Quoted 2 lines · Rene Herman
David: I've plugged in your DMI values in this. Could you perhaps test this to confirm that it works for you?
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 1 line · H. Peter Anvin
Incidentally, I had the thought earlier today that port
0xf0might 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.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 4 lines · Rene Herman
Quoted 1 line · H. Peter Anvin
Incidentally, I had the thought earlier today that port
0xf0might 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+.
Quoted 9 lines
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
0x80always and not just as an alternate port? For the latter0xedis 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.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 4 lines · Rene Herman
Quoted 1 line · H. Peter Anvin
Incidentally, I had the thought earlier today that port
0xf0might 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+.
Quoted 9 lines
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
0x80always and not just as an alternate port? For the latter0xedis 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 11 lines · Rene Herman
Quoted 8 lines · Ingo Molnar
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 itif we want to clean this all up we'll need as many controls as possible.
Quoted 8 lines
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_delaybeing 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(-)
Documentation/kernel-parameters.txt +7 -5
@@ -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
arch/x86/Kconfig.debug +72 -7
85 lines not on this page · raw message
arch/x86/kernel/io_delay.c +46 -57
149 lines not on this page · raw message
include/asm-x86/io_32.h +2 -0
@@ -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
include/asm-x86/io_64.h +2 -0
@@ -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 ();
kernel/sysctl.c +9 -0
@@ -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 ) {
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 4 lines · Ingo Molnar
Quoted 1 line
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 <[email protected]>
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.
[ [email protected]:
- 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 ]
--- 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(-)
Documentation/kernel-parameters.txt +10 -0
@@ -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.
arch/x86/Kconfig.debug +74 -0
78 lines not on this page · raw message
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +95 -0
95 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +4 -4
@@ -250,10 +250,10 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("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>
include/asm-x86/io_64.h +18 -11
@@ -35,13 +35,20 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
kernel/sysctl.c +9 -0
@@ -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 ) {
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 1 line · Ingo Molnar
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.
arch/x86/kernel/io_delay.c line 25
Quoted 4 lines
void
native_io_delay(void)
{arch/x86/kernel/io_delay.c +1
-1-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.
arch/x86/kernel/io_delay.c line 54
Quoted 11 lines
arch/x86/kernel/io_delay.c +4
-4-#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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 5 lines · H. Peter Anvin
Well, we probably should leave the possibility in to use
0x80-- for one thing, we need to use0x80on 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
0xf0for FERR/IGNNE, it just requires that they don't use it for something else.I would be rather inclined to try using port
0xf0by default as long as family > 3[*] (with fallback to port0x80) 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:
Quoted 3 lines
We *might* even be able to use port
0xf0unconditionally 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
0xf0implement it as a strobe alone (data is ignored), all documentation I've found, including "The Undocumented PC" specifically says "write0x00to this port." This *could* mean there are platforms which use other values than0x00for 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...
Quoted 4 lines
[*] 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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 6 lines · Rene Herman
Quoted 2 lines · Ingo Molnar
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?
Quoted 1 line
[...] Definitely not going to forgive you for deleting that comment.
Do you mean:
+/*
+ * High on a hill was a lonely goatherd
+ */
?
Quoted 8 lines
arch/x86/kernel/io_delay.c line 25
Quoted 4 lines
void
native_io_delay(void)
{arch/x86/kernel/io_delay.c +1
-1-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.)
Quoted 7 lines
Quoted 7 lines
arch/x86/kernel/io_delay.c +2
-4-#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);
Quoted 8 lines
arch/x86/kernel/io_delay.c line 54
Quoted 4 lines
arch/x86/kernel/io_delay.c +2
-0+ 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 13 lines · Ingo Molnar
Quoted 4 lines
Quoted 4 lines
arch/x86/kernel/io_delay.c +1
-2-#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) {Quoted 8 lines
arch/x86/kernel/io_delay.c line 54
Quoted 7 lines
arch/x86/kernel/io_delay.c +3
-2-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.
Quoted 1 line
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 18 lines · Rene Herman
Quoted 16 lines · Ingo Molnar
Quoted 16 lines
arch/x86/kernel/io_delay.c line 54
Quoted 13 lines
(quoted diff) +0
-2-#ifndef CONFIG_UDELAY_IO_DELAY -static int __init dmi_alternate_io_delay_port(const struct
dmi_system_id*id)
+static int__initdmi_io_delay_0xed_port(const struct dmi_system_id *id)
{arch/x86/kernel/io_delay.c +3
-2-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.
Quoted 8 lines
Quoted 3 lines
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
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 17 lines · Pavel Machek
Quoted 16 lines · Rene Herman
Quoted 14 lines · Ingo Molnar
Quoted 14 lines
arch/x86/kernel/io_delay.c line 54
Quoted 13 lines
(quoted diff) +0
-2-#ifndef CONFIG_UDELAY_IO_DELAY -static int __init dmi_alternate_io_delay_port(const struct
dmi_system_id*id)
+static int__initdmi_io_delay_0xed_port(const struct dmi_system_id *id)
{arch/x86/kernel/io_delay.c +3
-2-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.
Quoted 4 lines
Quoted 2 lines
Quoted 1 line
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 2 lines · Rene Herman
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarAbout to start building and testing. It will take a few hours.
Quoted 4 lines · Ingo Molnar
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 4 lines · David P. Reed
Quoted 2 lines · Rene Herman
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 6 lines · David P. Reed
Quoted 4 lines · Rene Herman
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.
Quoted 6 lines
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(-)
arch/x86/kernel/io_delay.c +5 -2
@@ -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 ; }
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
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
...
watchdog/wdt.c renamed from watchdog/wdt.c~ +4 -0
@@ -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;
}
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 18 lines · Alan Cox
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
...
watchdog/wdt.c renamed from watchdog/wdt.c~ +2
-0@@ -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 );
watchdog/wdt.c line 117
Quoted 7 lines
watchdog/wdt.c renamed from watchdog/wdt.c~ +2
-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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 3 lines · Rene Herman
I do not know how universal that is, but _reading_ port
0xf0might 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
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 21 lines · David P. Reed
Quoted 9 lines · Avi Kivity
kvm will forward a virtual machine's writes to port
0x80to the real port. The reason is that the write is much faster than exiting and emulating it; the difference is measurable when compiling kernels.Now if the cause is simply writing to port
0x80, then we must stop doing that. But if the reason is the back-to-back writes, when we can keep it, since the other writes will be trapped by kvm and emulated. Do you which is the case?As for kvm, I don't have enough info to know anything about that. Is there a test you'd like me to try?
I think you are also asking if the crash on these laptops is caused only by back-to-back writes. Actually, it doesn't seem to matter if they are back to back. I can cause the crash if the writes to 80 are very much spread out in time - it seems only to matter how many of them get executed - almost as if there is a buffer overflow. (And of course if you do back to back writes to other ports that are apparently fully unused, such as
0xEDon my machine, no crash occurs).
Quoted 9 lines
I believe (though no one seems to have confirming documentation from the chipset or motherboard vendor) that port 80 is actually functional for
some unknown function on these machines. (They do respond to "in"
instructions faster than a bus cycle abort does - more evidence).I searched the DSDT to see if there is any evidence of an ACPI use for this port, but found nothing.
Attached is a patch that changes the outs to ins on port 0x80. I did NOT let gcc decide what to do about modified registers. Instead, the code saves/restores EAX itself so that all of the times (whatever they are) are the same.
The code works and is running here. I also patched a very early version (2.4.26) running on a 400 MHz i486 with an real ISA bus (Adaptec AHA1453). It works too.
David, will you please try it on your machine. Maybe reading from the port is less harmful than writing.
Cheers,
Dick Johnson
Penguin : Linux version 2.6.22.1 on an i686 machine (5588.27 BogoMips). My book : http://www.AbominableFirebug.com/
_
****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to [email protected] - and destroy all copies of this information, including any attachments, without reading or disclosing them.
Thank you.
include/asm-i386/io.h renamed from include/asm-i386/io.h.orig +4 -1
@@ -252,7 +252,10 @@static inline void native_io_delay (void ) { - asmvolatile ("outb %%al,$0x80" : : :"memory" ); + asmvolatile ("pushl %%eax\n\t" +"inb $0x80, %%al\n\t" +"popl %%eax\n\t" + : : :"memory" ); }#if defined(CONFIG_PARAVIRT )
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 1 line · linux-os (Dick Johnson)
Attached is a patch that changes the outs to ins on port
0x80.
No, that isn't useful. Only a write is "guaranteed" to make ISA/LPC meaning the timing for a read varies wildly. See the in/out cycles results posted earlier. Was also reading the Intel PIIX(3) chiset datasheet today which specifically mentions that only writes flow through to ISA, reads do not.
Rene.
-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarIngo -
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 7 lines · H. Peter Anvin
Quoted 3 lines · Rene Herman
I do not know how universal that is, but _reading_ port
0xf0might 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
0xf0as 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).
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 8 lines · David P. Reed
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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 10 lines · David P. Reed
Quoted 7 lines · H. Peter Anvin
Quoted 3 lines · Rene Herman
I do not know how universal that is, but _reading_ port
0xf0might 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
0xf0as 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 port0xedand other unused ports (tsc at 800 MHz).
Any timings for port 0xf0 (write zero), out of curiosity?
-hpa
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 2 lines · Alan Cox
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?
commit e5f4d11c2470550500e8d8b798d902f2fe07b5c4
Author: Rene Herman <[email protected]> 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.
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +48 -0
48 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +2 -4
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void io_delay_init (void ); +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +16 -11
@@ -35,13 +35,18 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 9 lines · Rene Herman
Quoted 2 lines · Alan Cox
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
0xedbased 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 6 lines · H. Peter Anvin
Quoted 2 lines · David P. Reed
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 port0xedand 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.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Alan CoxQuoted 7 lines · Alan Cox
Quoted 3 lines
Quoted 2 lines
?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
How long will that take to boot on a 386?
Well the dumb approach to fix that would seem to be to initialise it to
cpu->family 3 -> 50MHz 4 -> 300Mhz 5-> etc...
By the way, you have a 300 MHz 486? I believe 3 -> 40, 4 -> 133, 5 -> 233 would be good? And I'm not really sure about the etc. P6 has a large range again...
Rene.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 5 lines · David P. Reed
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
0x80verrrrry 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
Ingo Molnar
Tested-by David P. ReedRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 37 lines · David P. Reed
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,
0xedis 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.
Quoted 7 lines
Analysis:
patch works fine, and default to
0xedseems 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:
if you dont mind.
Ingo
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 4 lines
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 port0xedand 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.
PATCH 1/1 x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 6 lines · H. Peter Anvin
Quoted 5 lines · Rene Herman
Quoted 2 lines · Alan Cox
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
Quoted 6 lines
Quoted 4 lines
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
0xedbased 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.
Quoted 1 line
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.
commit c83008ff40e95f89407807cb122127c5444b3bc4
Author: Rene Herman <[email protected]> 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.
Documentation/kernel-parameters.txt +7 -0
@@ -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.
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +69 -0
69 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +2 -4
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void io_delay_init (void ); +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +16 -11
@@ -35,13 +35,18 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 3 lines · Rene Herman
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 18 lines · Rene Herman
Quoted 2 lines · Alan Cox
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
0xedbased 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).
Quoted 3 lines
Ingo?
Signed-off-by Rene Herman <[email protected]>
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
Ingo Molnar
Tested-by David P. ReedRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 9 lines · H. Peter Anvin
Quoted 5 lines · Rene Herman
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 (
0xeband0xf0are 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 <[email protected]>
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.
[ [email protected]:
- 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 ]
--- 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(-)
Documentation/kernel-parameters.txt +10 -0
@@ -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.
arch/x86/Kconfig.debug +74 -0
78 lines not on this page · raw message
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +98 -0
98 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +4 -4
@@ -250,10 +250,10 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("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>
include/asm-x86/io_64.h +18 -11
@@ -35,13 +35,20 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
kernel/sysctl.c +9 -0
@@ -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 ) {
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 8 lines · Ingo Molnar
Quoted 6 lines · Rene Herman
Quoted 2 lines · Alan Cox
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.
Quoted 7 lines
Quoted 5 lines
So, really, how about just sticking in this minimal version for now? Only switches the port to
0xedbased 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 <[email protected]>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.
commit c12c7a47b9af87e8d867d5aa0ca5c6bcdd2463da
Author: Rene Herman <[email protected]> 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.
Documentation/kernel-parameters.txt +6 -0
@@ -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.
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +69 -0
69 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +2 -4
@@ -250,10 +250,8 @@ static inline void flush_write_buffers(void)#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("outb %%al,$0x80" : : :"memory" ); -} +extern void io_delay_init (void ); +extern void native_io_delay (void );#if defined(CONFIG_PARAVIRT )#include <asm/paravirt.h>
include/asm-x86/io_64.h +16 -11
@@ -35,13 +35,18 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 6 lines · H. Peter Anvin
Quoted 3 lines · Rene Herman
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 (
0xeband0xf0are 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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 10 lines · Rene Herman
Quoted 5 lines
Quoted 1 line
Signed-off-by Rene Herman <[email protected]>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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 8 lines · Ingo Molnar
Quoted 3 lines · Rene Herman
Quoted 2 lines
Quoted 1 line
Signed-off-by Rene Herman <[email protected]>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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
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/[email protected]/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.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 6 lines · H. Peter Anvin
Quoted 3 lines
?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
How long will that take to boot on a 386?
Load it up in bochs and have look at the wallclock. I think that is a good estimate when you have no real 386 nearby.
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Alan CoxQuoted 6 lines · Alan Cox
Quoted 3 lines
My understanding is that the linux starts in real mode, and uses the BIOS for such things as reading the very first image.
Not always. We may enter from 32bit in some cases, and we may also not have a PC BIOS in the first place.
Computers without a PC BIOS (I'm trying to think of something, e.g. the typical SUN sparc64 box) should have other means of accessing a clocksource, no?
H. Peter Anvin
reviewerRe: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 8 lines · Jan Engelhardt
Quoted 3 lines · Alan Cox
Quoted 1 line
My understanding is that the linux starts in real mode, and uses the BIOS for such things as reading the very first image.
Not always. We may enter from 32bit in some cases, and we may also not have a PC BIOS in the first place.
Computers without a PC BIOS (I'm trying to think of something, e.g. the typical SUN sparc64 box) should have other means of accessing a clocksource, no?
We were talking about x86 here, though.
Even on x86 we sometimes run from the 32-bit entrypoint.
-hpa
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to Rene HermanQuoted 11 lines · Rene Herman
Quoted 5 lines · Alan Cox
Quoted 3 lines
Quoted 2 lines
?? Just initialize bogomips to 6GHz equivalent... and we are fine until 6GHz cpus come out.
How long will that take to boot on a 386?
Well the dumb approach to fix that would seem to be to initialise it to
cpu->family 3 -> 50MHz 4 -> 300Mhz 5-> etc...By the way, you have a 300 MHz 486? I believe 3 -> 40, 4 -> 133, 5 -> 233 would be good? And I'm not really sure about the etc. P6 has a large range again...
Some nexgen 5x86 boxes were pretty fast, still could not do 486... so family 3 iirc.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 6 lines
Quoted 3 lines
By the way, you have a 300 MHz 486? I believe 3 -> 40, 4 -> 133, 5 -> 233 would be good? And I'm not really sure about the etc. P6 has a large range again...
Some nexgen 5x86 boxes were pretty fast, still could not do 486... so family 3 iirc.
300MHz 486 -> Nat Semi Geode.
NextGen as you say are 386 - 586 depending on the BIOS hypercode but I believe lack WP even in > 386 mode.
Alan
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
Quoted 4 lines · Alan Cox
300MHz 486 -> Nat Semi Geode.
NextGen as you say are 386 - 586 depending on the BIOS hypercode but I believe lack WP even in > 386 mode.
Geode identifies itself as family 5 though. It may prefer 486 code but it's still family 5. Well Geode GX, SCx200 and LX that is. I imagine the Geode NX would be family 6.
--
Len Sorensen
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to David P. ReedQuoted 5 lines · David P. Reed
Quoted 4 lines · Avi Kivity
kvm will forward a virtual machine's writes to port
0x80to the real port. The reason is that the write is much faster than exiting and emulating it; the difference is measurable when compiling kernels.
Quoted 8 lines
Quoted 5 lines
Now if the cause is simply writing to port
0x80, then we must stop doing that. But if the reason is the back-to-back writes, when we can keep it, since the other writes will be trapped by kvm and emulated. Do you which is the case?As for kvm, I don't have enough info to know anything about that. Is there a test you'd like me to try?
I have a test, but I see that it is broken for mainline. I'll update it eventually, but...
Quoted 8 lines
I think you are also asking if the crash on these laptops is caused only by back-to-back writes. Actually, it doesn't seem to matter if they are back to back. I can cause the crash if the writes to 80 are very much spread out in time - it seems only to matter how many of them get executed - almost as if there is a buffer overflow. (And of course if you do back to back writes to other ports that are apparently fully unused, such as
0xEDon my machine, no crash occurs).
Quoted 4 lines
I believe (though no one seems to have confirming documentation from the chipset or motherboard vendor) that port 80 is actually functional
for some unknown function on these machines. (They do respond to
"in" instructions faster than a bus cycle abort does - more evidence).
That seems to be sufficient evidence for me to remove port 0x80 pass-through from kvm and emulate it instead. Given that port 80 writes take 1 microsecond, and that an in-kernel exit handler takes a similar amount of time, there won't be any significant performance loss.
Signature · 9 lines
error compiling committee.c: too many arguments to function ------------------------------------------------------------------------- SF.Net email is sponsored by: Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
Re: [PATCH] x86_64: fix problems due to use of "outb" to port 80 on some AMD64x2 laptops, etc.
In reply to H. Peter AnvinQuoted 15 lines · H. Peter Anvin
Quoted 14 lines · Pavel Machek
Hi!
Quoted 13 lines
The process of safely making delicate changes here is beyond my responsibility as just a user - believe me, I'm not suggesting that a
risky fix be put in .24. I can patch my own kernels, and I can even
share an unofficial patch with others for now, or suggest that Fedora and Ubuntu add it to their downstream.May I make a small suggestion, though. If the decision is a DMI-keyed
switch from out-80 to udelay(2) gets put in, perhaps there should also be a way for people to test their own configuration for the underlying
problem made available as a script. Though it is a "hack", all you need
to freeze a problem system is to run a loop doing about 1000 "cat/dev/nvram>/dev/null" commands. If that leads to a freeze, one might ask to have the motherboard added to the DMI-key list.
Quoted 5 lines
Quoted 3 lines
Can you freeze it by catting
/dev/rtc, too? That may be significant, because that is readable for group audio (at least on some systems)... which would smell like "small security hole" to me.Heck, on my system (Fedora 7), it's mode 644...
Ok, time to CC security team, I'd say.
Problem is, that some AMD64x2 nVidia laptops crash on port 0x80 access... which is easily user-triggerable by using /dev/rtc. If it is 644 on Fedora, I guess we have a problem.
Otoh, it is "only" a denial of service, and it can probably be attributed to "buggy hardware". Is that still relevant for security team?
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 11 lines · Alan Cox
Quoted 2 lines
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 port0xedand 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
0x80port. 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan Cox[attached the DSDT.dsl file fyi]
Quoted 11 lines · Alan Cox
Quoted 2 lines
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 port0xedand 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
0x80port. 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
/*
* 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)2,026 lines not shown · raw message
Part of this message is not shown here. View the raw message.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 6 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedHi!
Quoted 9 lines
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?
Quoted 10 lines
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?
Quoted 11 lines
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:
Quoted 7 lines
1. buffer overflow in such a device.
2. there is some "meaning" to certain byte values being written (the
_PTSand_WAKuse 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
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 6 lines · Alan Cox
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
0x80using 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 8 lines · On Tue, 1 Jan 2008 17:43:38 +0100 Ingo Molnar <[email protected]> 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
_exactsame_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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 4 lines · Alan Cox
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
0x80to 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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Pavel MachekQuoted 7 lines · Pavel Machek
Quoted 6 lines
2. there is some "meaning" to certain byte values being written (the
_PTSand_WAKuse 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
Quoted 5 lines
There's nothing easier than always writing 0 to the
0x80to 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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 2 lines
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.
Quoted 7 lines
_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
_exactsame_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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 4 lines
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.
Quoted 2 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 1 line · Christer Weinigel
What I'm afraid is that udelay will be significantly slower, [...]
why should it be significantly slower?
Ingo
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 7 lines · Alan Cox
Quoted 3 lines
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.
Quoted 2 lines
#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.
Quoted 2 lines
#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.
Quoted 10 lines
Quoted 7 lines
_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
_exactsame_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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 6 lines · On Tue, 1 Jan 2008 19:46:59 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 1 line · Christer Weinigel
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 14 lines · Christer Weinigel
Quoted 4 lines · On Tue, 1 Jan 2008 19:46:59 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 1 line · Christer Weinigel
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.
Quoted 4 lines
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.
Quoted 7 lines
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.
Quoted 9 lines
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_pto work reliably. So ifoutb_pbecomes 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_pto 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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 7 lines · On Tue, 1 Jan 2008 19:45:24 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 4 lines · Alan Cox
Quoted 3 lines
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?
Quoted 8 lines
Quoted 3 lines
#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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 9 lines · On Tue, 01 Jan 2008 20:59:20 +0100 Rene Herman <[email protected]> wrote:
Quoted 4 lines · Christer Weinigel
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.
Quoted 10 lines
Quoted 3 lines
I'm not sure what Alan meant with his comments about locking, but if changing
outb_pto 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:
Quoted 2 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 8 lines · Christer Weinigel
Quoted 5 lines · On Tue, 1 Jan 2008 19:46:59 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 1 line · Christer Weinigel
What I'm afraid is that udelay will be significantly slower, [...]
Quoted 7 lines
Quoted 1 line
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.)
Quoted 2 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 8 lines
Quoted 3 lines
#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.
Quoted 4 lines
Quoted 2 lines
#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.
Quoted 2 lines
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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to David P. ReedQuoted 8 lines · David P. Reed
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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 11 lines · Alan Cox
Quoted 6 lines
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 onThat 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
0x80to another delay approach.
Quoted 6 lines
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
0x80using 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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 7 lines · Christer Weinigel
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 2 lines
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
Quoted 3 lines
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.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 6 lines · Christer Weinigel
Quoted 3 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 2 lines
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.
Quoted 2 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 1 line · H. Peter Anvin
I have mentioned this before... I think writing zero to port
0xf0would 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 to0x80.
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.
/* 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;
}Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 6 lines · On Tue, 1 Jan 2008 22:01:43 +0100 Ingo Molnar <[email protected]> wrote:
Quoted 5 lines
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.
Quoted 6 lines
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.
Quoted 5 lines
Quoted 2 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 9 lines · Christer Weinigel
The data sheet for the Intel M8259A says:
End of /RD to Next Command: 300 ns
End of /WR to Next Command: 370 nsOn 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.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 12 lines · Rene Herman
Quoted 1 line · H. Peter Anvin
I have mentioned this before... I think writing zero to port
0xf0would 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 to0x80.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
Quoted 8 lines
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
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 7 lines · Christer Weinigel
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 15 lines · H. Peter Anvin
Quoted 14 lines · Rene Herman
Quoted 1 line · H. Peter Anvin
I have mentioned this before... I think writing zero to port
0xf0would 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 to0x80.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 cyclesThe Intel PIIX/PIIX3 datasheet specifically mentions that both reads and writes at
0xf0"flow through to the ISA bus".
Quoted 8 lines
Quoted 6 lines
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
0x80or0xED-- 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.
/* 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;
}H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 7 lines · Rene Herman
Quoted 2 lines
Yes, we do. It's exactly this side effect which makes this safer than either
0x80or0xED-- 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
Quoted 9 lines
===
/*
* 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 8 lines · On Tue, 01 Jan 2008 13:21:47 -0800 "H. Peter Anvin" <[email protected]> wrote:
Quoted 6 lines · Christer Weinigel
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.
Quoted 4 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 13 lines · H. Peter Anvin
Quoted 13 lines
Quoted 1 line
Yes, we do. It's exactly this side effect which makes this safer than either
0x80or0xED-- 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.
*/
===
Quoted 3 lines
Quoted 1 line
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 4 lines
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 ?
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 8 lines · On Tue, 1 Jan 2008 23:12:50 +0000 Alan Cox <[email protected]> wrote:
Quoted 4 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 19 lines · Rene Herman
Quoted 13 lines · H. Peter Anvin
Quoted 13 lines
Quoted 1 line
Yes, we do. It's exactly this side effect which makes this safer than either
0x80or0xED-- 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.
*/
===Quoted 3 lines
Quoted 1 line
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.
Quoted 7 lines
Well, on the PIIX it is and I guess on anything where it's _not_ fully internal an
0xf0write wouldn't have any effect on IRQ13...When you earlier mentioned this it seemed
0xedswitched on DMI would be good enough, but well.Alan, do you have an opinion on the port
0xf0write? 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+387We 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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Rene HermanQuoted 11 lines · On Wed, 02 Jan 2008 00:11:54 +0100 Rene Herman <[email protected]> wrote:
Well, on the PIIX it is and I guess on anything where it's _not_ fully internal an
0xf0write wouldn't have any effect on IRQ13...When you earlier mentioned this it seemed
0xedswitched on DMI would be good enough, but well.Alan, do you have an opinion on the port
0xf0write? 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 21 lines · Christer Weinigel
Quoted 11 lines · On Wed, 02 Jan 2008 00:11:54 +0100 Rene Herman <[email protected]> wrote:
Well, on the PIIX it is and I guess on anything where it's _not_ fully internal an
0xf0write wouldn't have any effect on IRQ13...When you earlier mentioned this it seemed
0xedswitched on DMI would be good enough, but well.Alan, do you have an opinion on the port
0xf0write? 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+387Both
0xedand0xf0are 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.
Quoted 5 lines
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
0x80messed 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.
H. Peter Anvin
reviewerRe: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Christer WeinigelQuoted 7 lines · Christer Weinigel
Both
0xedand0xf0are 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.
Quoted 6 lines
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
0x80messed 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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Alan CoxQuoted 9 lines · Alan Cox
Quoted 4 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 9 lines · H. Peter Anvin
Quoted 7 lines · Christer Weinigel
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.
Quoted 4 lines
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
Re: [linux-kernel] Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarFYI - another quirky Quanta motherboard from HP, with DMI readings reported to me.
-------- Original Message --------
Date: Wed, 2 Jan 2008 16:23:27 +1030
From: Joel Stanley <[email protected]>
To: David P. Reed <[email protected]>
Subject: Re: [PATCH] Option to disable AMD C1E (allows dynticks to work)
Quoted 3 lines · David P. Reed
I have also attached a c program that only touches port 80. Compile it for 32-bit mode (see comment), run it as root, and after two or three runs, it will hang a system that has the port 80 bug.
Using port80.c, I could hard lock a HP Pavilion tx1000 laptop on the first go. This was with ubuntu hardy's stock kernel (a 2.6.24-rc)
Quoted 2 lines
dmidecode -s baseboard-manufacturer
dmidecode -s baseboard-product-name
Quanta
30BF
Tonight, I will try compiling a kernel with these values added to your patch.
Some history, feel free to ignore if it's not relevant: ubuntu feisty's 2.6.22 based kernel worked fine, irc. We were having issues with sound, so tried fedora8's .23 based kernel, but this would sporadically hard lock. Ubuntu hardy's 2.6.24 appeared fine, for the 2 hours or so I used it last night, until using the port80.c program, obviously.
Cheers,
Joel
Re: [linux-kernel] Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 11 lines · David P. Reed
FYI - another quirky Quanta motherboard from HP, with DMI readings reported to me.
Using
port80.c, I could hard lock a HP Pavilion tx1000 laptop on the first go. This was with ubuntu hardy's stock kernel (a 2.6.24-rc)Quoted 2 lines
dmidecode -s baseboard-manufacturer
dmidecode -s baseboard-product-nameQuanta
30BF
thanks, i've updated the patches in x86.git with this:
+ .callback = dmi_io_delay_0xed_port,
+ .ident = "HP Pavilion tx1000",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Quanta"),
+ DMI_MATCH(DMI_BOARD_NAME, "30BF")
+ }
Find combo patch below.
Ingo
--------------->
Documentation/kernel-parameters.txt +10 -0
@@ -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.
arch/x86/Kconfig.debug +74 -0
78 lines not on this page · raw message
arch/x86/boot/compressed/misc_32.c +4 -4
@@ -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)
arch/x86/boot/compressed/misc_64.c +4 -4
@@ -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)
arch/x86/kernel/Makefile_32 +1 -1
@@ -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/
arch/x86/kernel/Makefile_64 +1 -1
@@ -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/
arch/x86/kernel/io_delay.c new file +114 -0
114 lines not on this page · raw message
arch/x86/kernel/setup_32.c +2 -0
@@ -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
arch/x86/kernel/setup_64.c +2 -0
@@ -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;
include/asm-x86/io_32.h +4 -4
@@ -250,10 +250,10 @@ static inline void flush_write_buffers(v#endif /* __KERNEL__ */ -static inline void native_io_delay (void ) -{ - asmvolatile ("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>
include/asm-x86/io_64.h +18 -11
@@ -35,13 +35,20 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#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) \
kernel/sysctl.c +9 -0
@@ -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 ) {
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to Ingo MolnarQuoted 5 lines
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.
Quoted 4 lines
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_ISAwould likely achieve that purpose.
Agreed - will see if EISA/VLB cases come up but thats trivial.
Quoted 3 lines
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
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 4 lines · Alan Cox
Quoted 1 line
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.
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
Quoted 18 lines · Rene Herman
Quoted 9 lines · Alan Cox
Quoted 6 lines
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();
Quoted 8 lines
and then just leave out the
slow_down_io()call in the non-ISA spots.slow_down_io()could be renamedisa_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 plainoutb()as well.
Would just need this bit of io.h arch unification from the orignal patch and that's it:
include/asm-x86/io_64.h +18 -11
@@ -35,13 +35,20 @@* - Arnaldo Carvalho de Melo <[email protected]> */ -#define __SLOW_DOWN_IO "\noutb %%al,$0x80" +static inline void native_io_delay (void ) +{ + asmvolatile ("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) \
Re: [PATCH] x86: provide a DMI based port 0x80 I/O delay override.
In reply to H. Peter AnvinQuoted 7 lines · H. Peter Anvin
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
0x80on 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