summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2008-06-20 01:35:07 +0100
committerIngo Molnar <mingo@elte.hu>2008-07-08 09:13:24 +0200
commit7f0dbbc08d80df7ea15d8da4f0d78255891c8812 (patch)
tree14b876a80d9fc32574485d82ce456adfc6ddc252
parentcd08d0754ecb0cb9293c8476cb33ded1d23d0d8f (diff)
x86: fix IO APIC breakage on HP nx6325, v2
> That helped a lot, the system seems to work normally now. > > Here's the relevant snippet from dmesg: > > [ 0.108006] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1 > [ 0.108006] ..MP-BIOS bug: 8254 timer not connected to IO-APIC > [ 0.108006] ...trying to set up timer (IRQ0) through the 8259A ... <3> > [ 0.108006] ..... (found apic 0 pin 2) ...<3> failed. > [ 0.108006] ...trying to set up timer as Virtual Wire IRQ...<3> works. > > and the whole thing is at: http://www.sisk.pl/kernel/debug/20080618/dmesg-2.log Hmm, that only proved the 8259A is indeed wired to the pin #2 of the I/O APIC. > I, personally, don't have any and AMD only has SB600 documentation on its > web page (it's still marked as "AMD confidential" ;-)). Well, the IC block is most likely the same as that's not rocket science and once done there is no need to fiddle with that. That written, I am afraid there is nothing useful about the IC in the document, except that it's there and consists of an I/O APIC providing 24 inputs and the usual pair of 8259A cores. Thanks for the reference anyway. > There is an interrupt controller in there, but I'm not sure if there's any > 8259A. The northbridge is on the CPU, actually. I will praise the day someone ships an x86 machine without an 8259A core! As expressed in another mail I suspect there may actually be a direct route from the 8254 to INTIN0 in the southbridge -- this is what other bootstrap logs seen in the Internet suggest. This would mean this particular BIOS is buggy (is it the latest version?) and provides an incorrect IRQ override in its ACPI tables, for example because the responsible block has been blindly copied from a machine using a commoner wiring. This could be moderately easily fixed up with a quirk based on the PCI ID (after checking it again, we actually used to have a quirk for ATI in this area, but the way it was done suggests the issue was not understood well enough). Could you please remove the hack sent yesterday and test the patch provided below? I do hope it builds, but I have no immediate means to check it. Please report the output. The intent is to test INTIN0 directly before testing INTIN2 through the 8259A. Thanks. Aside of that, what I have gathered from your reports (please correct me if I have got it wrong) is that when the through-8259A mode is used, then after a while 8254 timer interrupts stop arriving. What's interesting, the "Virtual Wire IRQ" seems to work for you correctly (that's quite an odd setup where a local APIC input is used in the native mode -- please post /proc/interrupts for confirmation), which in turn implies the master 8259A drives its INT output as we expect. Why would the I/O APIC input have problems then? Hmm... [ mingo@elte.hu: revert the "x86: fix IO APIC breakage on HP nx6325" version. ] Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/io_apic_64.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index f06f5b4fb35f..40aa041b2987 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -360,6 +360,26 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
entry->pin = pin;
}
+/*
+ * Reroute an IRQ to a different pin.
+ */
+static void __init replace_pin_at_irq(unsigned int irq,
+ int oldapic, int oldpin,
+ int newapic, int newpin)
+{
+ struct irq_pin_list *entry = irq_2_pin + irq;
+
+ while (1) {
+ if (entry->apic == oldapic && entry->pin == oldpin) {
+ entry->apic = newapic;
+ entry->pin = newpin;
+ }
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+}
+
#define DO_ACTION(name,R,ACTION, FINAL) \
\
@@ -1680,6 +1700,11 @@ static inline void __init check_timer(void)
apic2 = apic1;
}
+ replace_pin_at_irq(0, 0, 0, apic1, pin1);
+ apic1 = 0;
+ pin1 = 0;
+ setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
+
if (pin1 != -1) {
/*
* Ok, does IRQ0 through the IOAPIC work?
@@ -1712,10 +1737,9 @@ static inline void __init check_timer(void)
/*
* legacy devices should be connected to IO APIC #0
*/
- /* replace_pin_at_irq(0, apic1, pin1, apic2, pin2); */
+ replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
unmask_IO_APIC_irq(0);
- clear_IO_APIC_pin(apic2, pin2);
enable_8259A_irq(0);
if (timer_irq_works()) {
apic_printk(APIC_VERBOSE," works.\n");