2006-02-28 21:19:42

by Chuck Ebbert

[permalink] [raw]
Subject: [patch] i386: port ATI timer fix from x86_64 to i386

Disable timer routing over 8254 when an ATI chipset is detected
(autodetect is only implemented for ACPI, but these are new systems
and should be using ACPI anyway.) Adds boot options for manually
disabling and enabling this feature. Also adds a note to the timer
error message caused by this change explaining that this error
is expected on ATI chipsets.

Signed-off-by: Chuck Ebbert <[email protected]>

---

This would be nice for 2.6.16 but I don't recommend it because of the
diversity of i386 hardware.

Documentation/kernel-parameters.txt | 33 ++++++++++++++++++++++-----------
arch/i386/kernel/acpi/earlyquirk.c | 12 ++++++++++++
arch/i386/kernel/io_apic.c | 21 +++++++++++++++++++--
include/asm-i386/acpi.h | 1 +
4 files changed, 54 insertions(+), 13 deletions(-)

--- 2.6.16-rc5-d2.orig/Documentation/kernel-parameters.txt
+++ 2.6.16-rc5-d2/Documentation/kernel-parameters.txt
@@ -80,6 +80,7 @@ restrictions referred to are that the re
VT Virtual terminal support is enabled.
WDT Watchdog support is enabled.
XT IBM PC/XT MFM hard disk support is enabled.
+ X86 Either X86-64 or IA-32 (i386) is enabled
X86-64 X86-64 architecture is enabled.
More X86-64 boot options can be found in
Documentation/x86_64/boot-options.txt .
@@ -167,16 +168,6 @@ running once the system is up.
override platform specific driver.
See also Documentation/acpi-hotkey.txt.

- enable_timer_pin_1 [i386,x86-64]
- Enable PIN 1 of APIC timer
- Can be useful to work around chipset bugs
- (in particular on some ATI chipsets).
- The kernel tries to set a reasonable default.
-
- disable_timer_pin_1 [i386,x86-64]
- Disable PIN 1 of APIC timer
- Can be useful to work around chipset bugs.
-
ad1816= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2>
See also Documentation/sound/oss/AD1816.
@@ -226,7 +217,7 @@ running once the system is up.
not play well with APC CPU idle - disable it if you have
APC and your system crashes randomly.

- apic= [APIC,i386] Change the output verbosity whilst booting
+ apic= [APIC,X86] Change the output verbosity whilst booting
Format: { quiet (default) | verbose | debug }
Change the amount of debugging information output
when initialising the APIC and IO-APIC components.
@@ -423,6 +414,16 @@ running once the system is up.
See drivers/char/README.epca and
Documentation/digiepca.txt.

+ disable_8254_timer [X86]
+ Disable interrupt 0 timer routing over the 8254
+ in addition to over the IO-APIC. The kernel tries
+ to set a sensible default.
+
+ disable_timer_pin_1 [X86]
+ Disable PIN 1 of APIC timer
+ Can be useful to work around chipset bugs
+ (in particular on some ATI chipsets).
+
dmascc= [HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA
support available.
Format: <io_dev0>[,<io_dev1>[,..<io_dev32>]]
@@ -486,6 +487,16 @@ running once the system is up.
pass this option to capture kernel.
See Documentation/kdump/kdump.txt for details.

+ enable_8254_timer [X86]
+ Enable interrupt 0 timer routing over the 8254
+ in addition to over the IO-APIC. The kernel tries
+ to set a sensible default.
+
+ enable_timer_pin_1 [X86]
+ Enable PIN 1 of APIC timer
+ Can be useful to work around chipset bugs
+ (in particular on some ATI chipsets).
+
enforcing [SELINUX] Set initial enforcing status.
Format: {"0" | "1"}
See security/selinux/Kconfig help text.
--- 2.6.16-rc5-d2.orig/arch/i386/kernel/acpi/earlyquirk.c
+++ 2.6.16-rc5-d2/arch/i386/kernel/acpi/earlyquirk.c
@@ -15,6 +15,18 @@ static int __init check_bridge(int vendo
if (vendor == PCI_VENDOR_ID_NVIDIA) {
acpi_skip_timer_override = 1;
}
+#ifdef CONFIG_X86_IO_APIC
+ /* Many ATI boards have timer problems. This fix should
+ * be harmless even on non-ATI boards, but play it safe.
+ */
+ if (vendor == PCI_VENDOR_ID_ATI) {
+ if (timer_over_8254 == 1) {
+ timer_over_8254 = 0;
+ printk(KERN_INFO "ATI board detected. "
+ "Disabling timer routing over 8254.\n"
+ }
+ }
+#endif
return 0;
}

--- 2.6.16-rc5-d2.orig/arch/i386/kernel/io_apic.c
+++ 2.6.16-rc5-d2/arch/i386/kernel/io_apic.c
@@ -64,6 +64,22 @@ int nr_ioapic_registers[MAX_IO_APICS];

int disable_timer_pin_1 __initdata;

+int timer_over_8254 __initdata = 1;
+
+static int __init setup_disable_8254_timer(char *s)
+{
+ timer_over_8254 = -1;
+ return 1;
+}
+__setup("disable_8254_timer", setup_disable_8254_timer);
+
+static int __init setup_enable_8254_timer(char *s)
+{
+ timer_over_8254 = 2;
+ return 1;
+}
+__setup("enable_8254_timer", setup_enable_8254_timer);
+
/*
* Rough estimation of how many shared IRQs there are, can
* be changed anytime.
@@ -2267,7 +2283,8 @@ static inline void check_timer(void)
apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
init_8259A(1);
timer_ack = 1;
- enable_8259A_irq(0);
+ if (timer_over_8254 > 0)
+ enable_8259A_irq(0);

pin1 = find_isa_irq_pin(0, mp_INT);
apic1 = find_isa_irq_apic(0, mp_INT);
@@ -2294,7 +2311,7 @@ static inline void check_timer(void)
}
clear_IO_APIC_pin(apic1, pin1);
printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to "
- "IO-APIC\n");
+ "IO-APIC (expected on ATI chipsets)\n");
}

printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
--- 2.6.16-rc5-d2.orig/include/asm-i386/acpi.h
+++ 2.6.16-rc5-d2/include/asm-i386/acpi.h
@@ -127,6 +127,7 @@ extern int acpi_gsi_to_irq(u32 gsi, unsi
#ifdef CONFIG_X86_IO_APIC
extern int skip_ioapic_setup;
extern int acpi_skip_timer_override;
+extern int timer_over_8254;

extern void check_acpi_pci(void);

--
Chuck
"Equations are the Devil's sentences." --Stephen Colbert


2006-02-28 23:22:34

by Andrew Morton

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

Chuck Ebbert <[email protected]> wrote:
>
> Disable timer routing over 8254 when an ATI chipset is detected
> (autodetect is only implemented for ACPI, but these are new systems
> and should be using ACPI anyway.) Adds boot options for manually
> disabling and enabling this feature. Also adds a note to the timer
> error message caused by this change explaining that this error
> is expected on ATI chipsets.

umm, why did you write this patch? Presumably it's fixing something, but
what?

2006-03-01 00:06:18

by Chuck Ebbert

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

In-Reply-To: <[email protected]>

On Tue, 28 Feb 2006 15:21:24, Andrew Morton wrote:

> Chuck Ebbert <[email protected]> wrote:
> >
> > Disable timer routing over 8254 when an ATI chipset is detected
> > (autodetect is only implemented for ACPI, but these are new systems
> > and should be using ACPI anyway.) Adds boot options for manually
> > disabling and enabling this feature. Also adds a note to the timer
> > error message caused by this change explaining that this error
> > is expected on ATI chipsets.
>
> umm, why did you write this patch? Presumably it's fixing something, but
> what?

Oops... I'm here in the middle of the forest and all I can see are trees.

This fixes the "timer runs too fast" bug on ATI chipsets (bugzilla #3927).


--
Chuck
"Equations are the Devil's sentences." --Stephen Colbert

2006-03-01 00:16:28

by Andrew Morton

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

Chuck Ebbert <[email protected]> wrote:
>
> This fixes the "timer runs too fast" bug on ATI chipsets (bugzilla #3927).

Wonderful, thanks. What's the relationship (if any) between this and the
recently-merged x86_64 fix?

2006-03-01 01:18:27

by Parag Warudkar

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386


-------------- Original message ----------------------
From: Andrew Morton <[email protected]>
> Chuck Ebbert <[email protected]> wrote:
> >
> > This fixes the "timer runs too fast" bug on ATI chipsets (bugzilla #3927).
>

At least HP has released a BIOS update[*] to cure this - It states something to the tune of "Fix system time issues when running under Linux OS". Not sure which one is the workaround and whether one is needed if other is present!
Time runs correctly for me without this fix and with the BIOS update.

Parag

[*] http://h10025.www1.hp.com/ewfrf/wc/softwareDownloadIndex?dlc=en&lc=en&os=228&product=461746&lang=en&cc=us&softwareitem=ob-36843-1

2006-03-01 02:25:45

by Chuck Ebbert

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

In-Reply-To: <[email protected]>

On Tue, 28 Feb 2006 16:15:12, andrew Morton wrote:

> >
> > This fixes the "timer runs too fast" bug on ATI chipsets (bugzilla #3927).
>
> Wonderful, thanks. What's the relationship (if any) between this and the
> recently-merged x86_64 fix?

This is the same fix ported to i386 for people with Sempron processors
or running i386 kernels on x86_64 systems.

The problems with the earlier disable_timer_pin_1 fix don't seem to happen with
this one; I even booted an old i386 SMP machine with the new boot option
'disable_8254_timer' and it worked fine.

--
Chuck
"Equations are the Devil's sentences." --Stephen Colbert

2006-03-01 10:40:06

by Andi Kleen

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

Andrew Morton <[email protected]> writes:

> Chuck Ebbert <[email protected]> wrote:
> >
> > This fixes the "timer runs too fast" bug on ATI chipsets (bugzilla #3927).
>
> Wonderful, thanks. What's the relationship (if any) between this and the
> recently-merged x86_64 fix?

He just ported the x86-64 change over without any original authorship
attribution :/

And some less functionality (only works for ACPI now) and some totally
unrelated Documentation cleanup and a few random printk changes.

The ACPI only thing is probably mostly ok because the timing won't work
at least on the dual cores without ACPI anyways because PMtimer is needed.
On single cores it would be useful even without ACPI
(for that earlyquirk.c just would need to be moved up to run independently
of ACPI)

Still it's probably a good idea for 2.6.16.

-Andi

2006-03-01 10:53:46

by Andrew Morton

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386


(Cc: fixed. Please send me a copy of your MUA so I can ritually disembowel
it).

Andi Kleen <[email protected]> wrote:
>
> Andrew Morton <[email protected]> writes:
>
> > Chuck Ebbert <[email protected]> wrote:
> > >
> > > This fixes the "timer runs too fast" bug on ATI chipsets (bugzilla #3927).
> >
> > Wonderful, thanks. What's the relationship (if any) between this and the
> > recently-merged x86_64 fix?
>
> He just ported the x86-64 change over without any original authorship
> attribution :/

Yup. And he proved that I am incapable of understanding a simple email
Subject:

> And some less functionality (only works for ACPI now) and some totally
> unrelated Documentation cleanup and a few random printk changes.
>
> The ACPI only thing is probably mostly ok because the timing won't work
> at least on the dual cores without ACPI anyways because PMtimer is needed.
> On single cores it would be useful even without ACPI
> (for that earlyquirk.c just would need to be moved up to run independently
> of ACPI)
>
> Still it's probably a good idea for 2.6.16.
>

Well.. the patch had a flagrant won't-compile if CONFIG_X86_IO_APIC=y, so
I'd consider it a bit green.

2006-03-01 11:07:27

by Andi Kleen

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

On Wednesday 01 March 2006 11:52, Andrew Morton wrote:
>
> (Cc: fixed. Please send me a copy of your MUA so I can ritually disembowel
> it).

Well it's an MNA really in this case - i read l-k using gated news with gnus.

> Well.. the patch had a flagrant won't-compile if CONFIG_X86_IO_APIC=y, so
> I'd consider it a bit green.

Ok - i guess it would be better to redo it anyways to handle the non ACPI case
too. I can do that.

-Andi

2006-03-01 14:25:56

by Alistair John Strachan

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

On Tuesday 28 February 2006 21:17, Chuck Ebbert wrote:
> Disable timer routing over 8254 when an ATI chipset is detected
> (autodetect is only implemented for ACPI, but these are new systems
> and should be using ACPI anyway.) Adds boot options for manually
> disabling and enabling this feature. Also adds a note to the timer
> error message caused by this change explaining that this error
> is expected on ATI chipsets.
[snip]
>
> pin1 = find_isa_irq_pin(0, mp_INT);
> apic1 = find_isa_irq_apic(0, mp_INT);
> @@ -2294,7 +2311,7 @@ static inline void check_timer(void)
> }
> clear_IO_APIC_pin(apic1, pin1);
> printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to "
> - "IO-APIC\n");
> + "IO-APIC (expected on ATI chipsets)\n");
> }
>

This hunk looks bogus. My understanding is that this is a BIOS bug that some
vendors have started to correct. We shouldn't acknowledge vendor BIOS bugs as
"expected", imo..

I had this message for years with my nForce2/nForce3 boards and eventually it
was repaired.

--
Cheers,
Alistair.

'No sense being pessimistic, it probably wouldn't work anyway.'
Third year Computer Science undergraduate.
1F2 55 South Clerk Street, Edinburgh, UK.

2006-03-01 15:54:31

by Chuck Ebbert

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

In-Reply-To: <[email protected]>

On Wed, 1 Mar 2006 02:52:19, Andrew Morton wrote:

> >
> > Still it's probably a good idea for 2.6.16.
> >
>
> Well.. the patch had a flagrant won't-compile if CONFIG_X86_IO_APIC=y, so
> I'd consider it a bit green.

Aargh... I hit that and fixed it, but forgot to refresh before sending.

The only thing I didn't test was whether the boot options worked, and
I just did that -- 'enable_8254_timer' makes the clock run too fast as
expected.

And credit to Andi was implicit in the "port from x86_64" but it should
have been explicit.


--
Chuck
"The sleet in Crete falls neatly in the street."

2006-03-01 17:13:59

by Chuck Ebbert

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386

In-Reply-To: <[email protected]>

On 01 Mar 2006 11:40:00, Andi Kleen wrote:

> > Wonderful, thanks. What's the relationship (if any) between this and the
> > recently-merged x86_64 fix?
>
> He just ported the x86-64 change over without any original authorship
> attribution :/

Oops, sorry about that. Since I wrote "ported from x86_64" I assumed
credit was implicit.

> And some less functionality (only works for ACPI now)

I documented that. Without ACPI there wasn't infrastructure to do the early
PCI scan.

> and some totally unrelated Documentation cleanup

I added the two new boot options. While doing that I noticed the *timer_pin_1
docs weren't in alphabetical order so I moved them.

> and a few random printk changes

One printk change. The other was an exact port of the message from x86_64.
And the change I made wasn't random. It might have been a bad idea but
it wasn't random.


--
Chuck
"The sleet in Crete falls neatly in the street."

2006-03-02 05:03:12

by Andi Kleen

[permalink] [raw]
Subject: Re: [patch] i386: port ATI timer fix from x86_64 to i386 II

On Wednesday 01 March 2006 11:52, Andrew Morton wrote:

> Well.. the patch had a flagrant won't-compile if CONFIG_X86_IO_APIC=y, so
> I'd consider it a bit green.

I did my own version of it then. Tested it a bit in various configurations
and it works for me.

I would consider it a 2.6.16 candidate because it fixes an important bug.


Port the x86-64 ATI timer fix over to i386

ATI chipsets tend to generate double timer interrupts for the local
APIC timer when both the 8254 and the IO-APIC timer pins are enabled.
This is because they route it to both and the result is anded
together and the CPU ends up processing it twice.

This patch changes check_timer to disable the 8254 routing
for interruopt 0.

I think it would be safe on all chipsets actually (i tested it on
a couple and it worked everywhere) and Windows seems to do
it in a similar way, but to be conservative this patch only
enables this mode on ATI (and adds options to enable/disable too)

Ported over from a similar x86-64 change.

I reused the ACPI earlyquirk infrastructure for the ATI bridge check, but
tweaked it a bit to work even without ACPI.

Inspired by a patch from Chuck Ebbert, but redone.

Cc: Chuck Ebbert <[email protected]>
Cc: [email protected]

Signed-off-by: Andi Kleen <[email protected]>

Index: linux/arch/i386/kernel/Makefile
===================================================================
--- linux.orig/arch/i386/kernel/Makefile
+++ linux/arch/i386/kernel/Makefile
@@ -11,7 +11,7 @@ obj-y := process.o semaphore.o signal.o

obj-y += cpu/
obj-y += timers/
-obj-$(CONFIG_ACPI) += acpi/
+obj-y += acpi/
obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
obj-$(CONFIG_MCA) += mca.o
obj-$(CONFIG_X86_MSR) += msr.o
Index: linux/arch/i386/kernel/acpi/Makefile
===================================================================
--- linux.orig/arch/i386/kernel/acpi/Makefile
+++ linux/arch/i386/kernel/acpi/Makefile
@@ -1,4 +1,4 @@
-obj-y := boot.o
+obj-$(CONFIG_ACPI) += boot.o
obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o

Index: linux/arch/i386/kernel/acpi/earlyquirk.c
===================================================================
--- linux.orig/arch/i386/kernel/acpi/earlyquirk.c
+++ linux/arch/i386/kernel/acpi/earlyquirk.c
@@ -7,14 +7,22 @@
#include <linux/pci.h>
#include <asm/pci-direct.h>
#include <asm/acpi.h>
+#include <asm/apic.h>

static int __init check_bridge(int vendor, int device)
{
+#ifdef CONFIG_ACPI
/* According to Nvidia all timer overrides are bogus. Just ignore
them all. */
if (vendor == PCI_VENDOR_ID_NVIDIA) {
acpi_skip_timer_override = 1;
}
+#endif
+ if (vendor == PCI_VENDOR_ID_ATI && timer_over_8254 == 1) {
+ timer_over_8254 = 0;
+ printk(KERN_INFO
+ "ATI board detected. Disabling timer routing over 8254.\n");
+ }
return 0;
}

Index: linux/arch/i386/kernel/io_apic.c
===================================================================
--- linux.orig/arch/i386/kernel/io_apic.c
+++ linux/arch/i386/kernel/io_apic.c
@@ -51,6 +51,8 @@ static struct { int pin, apic; } ioapic_

static DEFINE_SPINLOCK(ioapic_lock);

+int timer_over_8254 __initdata = 1;
+
/*
* Is the SiS APIC rmw bug present ?
* -1 = don't know, 0 = no, 1 = yes
@@ -2267,7 +2269,8 @@ static inline void check_timer(void)
apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
init_8259A(1);
timer_ack = 1;
- enable_8259A_irq(0);
+ if (timer_over_8254 > 0)
+ enable_8259A_irq(0);

pin1 = find_isa_irq_pin(0, mp_INT);
apic1 = find_isa_irq_apic(0, mp_INT);
@@ -2392,6 +2395,20 @@ void __init setup_IO_APIC(void)
print_IO_APIC();
}

+static int __init setup_disable_8254_timer(char *s)
+{
+ timer_over_8254 = -1;
+ return 1;
+}
+static int __init setup_enable_8254_timer(char *s)
+{
+ timer_over_8254 = 2;
+ return 1;
+}
+
+__setup("disable_8254_timer", setup_disable_8254_timer);
+__setup("enable_8254_timer", setup_enable_8254_timer);
+
/*
* Called after all the initialization is done. If we didnt find any
* APIC bugs then we can allow the modify fast path
Index: linux/include/asm-i386/apic.h
===================================================================
--- linux.orig/include/asm-i386/apic.h
+++ linux/include/asm-i386/apic.h
@@ -137,6 +137,8 @@ void switch_APIC_timer_to_ipi(void *cpum
void switch_ipi_to_APIC_timer(void *cpumask);
#define ARCH_APICTIMER_STOPS_ON_C3 1

+extern int timer_over_8254;
+
#else /* !CONFIG_X86_LOCAL_APIC */
static inline void lapic_shutdown(void) { }

Index: linux/Documentation/i386/boot-options.txt
===================================================================
--- /dev/null
+++ linux/Documentation/i386/boot-options.txt
@@ -0,0 +1,8 @@
+
+Some i386 specific boot options
+
+ disable_8254_timer / enable_8254_timer
+ Enable interrupt 0 timer routing over the 8254 in addition to
+ over the IO-APIC. The kernel tries to set a sensible default.
+
+
Index: linux/arch/i386/kernel/acpi/boot.c
===================================================================
--- linux.orig/arch/i386/kernel/acpi/boot.c
+++ linux/arch/i386/kernel/acpi/boot.c
@@ -1111,9 +1111,6 @@ int __init acpi_boot_table_init(void)
disable_acpi();
return error;
}
-#ifdef __i386__
- check_acpi_pci();
-#endif

acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);

Index: linux/arch/i386/kernel/setup.c
===================================================================
--- linux.orig/arch/i386/kernel/setup.c
+++ linux/arch/i386/kernel/setup.c
@@ -1599,6 +1599,10 @@ void __init setup_arch(char **cmdline_p)
if (efi_enabled)
efi_map_memmap();

+#ifdef CONFIG_X86_IO_APIC
+ check_acpi_pci(); /* Checks more than just ACPI actually */
+#endif
+
#ifdef CONFIG_ACPI
/*
* Parse the ACPI tables for possible boot-time SMP configuration.