Re: Looking for system debugging tools

Harald Hoyer (Harald.Hoyer@Hot.Spotline.de)
Wed, 25 Aug 1999 21:54:25 +0200


This is a multi-part message in MIME format.
--------------57EB8EFBB0332887C980E222
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Alan Cox wrote:
>
> > Using Redhat 6.0 and the 2.2.5-22 kernel, I have a situation
> > where an IBM Netfinity system hangs a few minutes after
> > booting. However, it does not experience this hang when
>
> People have reported numerous problems with the PCI bios on the netfinity,
> where if PCI bios is used a while later the box crashes. However the RH
> kernel is built to try and do direct PCI in favour of PCI bios32 calls.
>

My problems went away aplying the multiple io-apic.patch and compiling
lilo with -DLARGE_EBDA

Harald

-- 
     _ajQQQQQQQQba                   _   _         _   
   _jQQP'     _/4QQb      _ _ ___ __| | | |_  __ _| |_ 
  aQQQQ']aaa     4QQQb   | '_/ -_) _` | | ' \/ _` |  _|
 jQQ??4/          QQQQb  |_| \___\__,_| |_||_\__,_|\__|
_Qf   )QQaaa      ]QQQQf                               
)QQb     ??Qb     '  ?QQ   Harald Hoyer - Developer
QQQQQa/               QQ
)QQQQ' ?aa          aQQP red hat Deutschland  Phone: +49 (0)711 621027 0
)'  )\/  )?QQ a_a_QQQQQ' Schloss-Strasse. 98  EMail: harald@redhat.de
            _//  jQQQQP  D-70176 Stuttgart    URL: http://www.redhat.de/
                _Q????
--------------57EB8EFBB0332887C980E222
Content-Type: text/plain; charset=us-ascii;
 name="ioapic-patch.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="ioapic-patch.txt"

diff -urN linux.orig/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- linux.orig/arch/i386/kernel/bios32.c Mon Mar 22 00:24:54 1999 +++ linux/arch/i386/kernel/bios32.c Fri Apr 23 20:57:06 1999 @@ -1095,6 +1095,7 @@ * for buggy PCI BIOS'es :-[). */ +extern int skip_ioapic_setup; /* defined in arch/i386/kernel/smp.c */ static void __init pcibios_fixup_devices(void) { struct pci_dev *dev; @@ -1147,6 +1148,7 @@ /* * Recalculate IRQ numbers if we use the I/O APIC */ + if (!skip_ioapic_setup) { int irq; unsigned char pin; diff -urN linux.orig/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- linux.orig/arch/i386/kernel/io_apic.c Fri Apr 16 00:59:42 1999 +++ linux/arch/i386/kernel/io_apic.c Fri Apr 23 20:57:13 1999 @@ -19,7 +19,7 @@ * volatile is justified in this case, IO-APIC register contents * might change spontaneously, GCC should not cache it */ -#define IO_APIC_BASE ((volatile int *)fix_to_virt(FIX_IO_APIC_BASE)) +#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx)) /* * The structure of the IO-APIC: @@ -47,7 +47,7 @@ /* * # of IRQ routing registers */ -int nr_ioapic_registers = 0; +int nr_ioapic_registers[MAX_IO_APICS]; enum ioapic_irq_destination_types { dest_Fixed = 0, @@ -94,6 +94,8 @@ mp_ExtINT = 3 }; +int mp_apic_entries = 0; /* # of I/O APIC entries */ +struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */ int mp_irq_entries = 0; /* # of MP IRQ source entries */ struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* MP IRQ source entries */ @@ -108,34 +110,34 @@ * between pins and IRQs. */ -static inline unsigned int io_apic_read(unsigned int reg) +static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) { - *IO_APIC_BASE = reg; - return *(IO_APIC_BASE+4); + *IO_APIC_BASE(apic) = reg; + return *(IO_APIC_BASE(apic)+4); } -static inline void io_apic_write(unsigned int reg, unsigned int value) +static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) { - *IO_APIC_BASE = reg; - *(IO_APIC_BASE+4) = value; + *IO_APIC_BASE(apic) = reg; + *(IO_APIC_BASE(apic)+4) = value; } /* * Re-write a value: to be used for read-modify-write * cycles where the read already set up the index register. */ -static inline void io_apic_modify(unsigned int value) +static inline void io_apic_modify(unsigned int apic, unsigned int value) { - *(IO_APIC_BASE+4) = value; + *(IO_APIC_BASE(apic)+4) = value; } /* * Synchronize the IO-APIC and the CPU by doing * a dummy read from the IO-APIC */ -static inline void io_apic_sync(void) +static inline void io_apic_sync(unsigned int apic) { - (void) *(IO_APIC_BASE+4); + (void) *(IO_APIC_BASE(apic)+4); } /* @@ -146,7 +148,7 @@ #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) static struct irq_pin_list { - int pin, next; + int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; /* @@ -154,7 +156,7 @@ * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void add_pin_to_irq(unsigned int irq, int pin) +static void add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -168,6 +170,7 @@ if (++first_free_entry >= PIN_MAP_SIZE) panic("io_apic.c: whoops"); } + entry->apic = apic; entry->pin = pin; } @@ -183,9 +186,9 @@ pin = entry->pin; \ if (pin == -1) \ break; \ - reg = io_apic_read(0x10 + R + pin*2); \ + reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ reg ACTION; \ - io_apic_modify(reg); \ + io_apic_modify(entry->apic, reg); \ if (!entry->next) \ break; \ entry = irq_2_pin + entry->next; \ @@ -197,12 +200,12 @@ * We disable IO-APIC IRQs by setting their 'destination CPU mask' to * zero. Trick by Ramesh Nalluri. */ -DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync()) /* destination = 0x00 */ +DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */ DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */ -DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync()) /* mask = 1 */ +DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ -static void clear_IO_APIC_pin(unsigned int pin) +static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -211,16 +214,17 @@ */ memset(&entry, 0, sizeof(entry)); entry.mask = 1; - io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0)); - io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1)); + io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); + io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); } static void clear_IO_APIC (void) { - int pin; + int apic, pin; - for (pin = 0; pin < nr_ioapic_registers; pin++) - clear_IO_APIC_pin(pin); + for (apic = 0; apic < mp_apic_entries; apic++) + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) + clear_IO_APIC_pin(apic, pin); } /* @@ -270,12 +274,13 @@ /* * Find the IRQ entry number of a certain pin. */ -static int __init find_irq_entry(int pin, int type) +static int __init find_irq_entry(int apic, int pin, int type) { int i; for (i = 0; i < mp_irq_entries; i++) if ( (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) && (mp_irqs[i].mpc_dstirq == pin)) return i; @@ -307,21 +312,26 @@ * Find a specific PCI IRQ entry. * Not an initfunc, possibly needed by modules */ +static int __init pin_2_irq(int idx, int apic, int pin); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) { - int i; + int apic, i; for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; - if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) && + for (apic = 0; apic < mp_apic_entries; apic++) + if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) + break; + + if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) && (mp_bus_id_to_type[lbus] == MP_BUS_PCI) && !mp_irqs[i].mpc_irqtype && (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) && (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) && (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))) - return mp_irqs[i].mpc_dstirq; + return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); } return -1; } @@ -491,9 +501,9 @@ return MPBIOS_trigger(idx); } -static int __init pin_2_irq(int idx, int pin) +static int __init pin_2_irq(int idx, int apic, int pin) { - int irq; + int irq, i; int bus = mp_irqs[idx].mpc_srcbus; /* @@ -513,9 +523,12 @@ case MP_BUS_PCI: /* PCI pin */ { /* - * PCI IRQs are 'directly mapped' + * PCI IRQs are mapped in order */ - irq = pin; + i = irq = 0; + while (i < apic) + irq += nr_ioapic_registers[i++]; + irq += pin; break; } default: @@ -545,12 +558,14 @@ static inline int IO_APIC_irq_trigger(int irq) { - int idx, pin; + int apic, idx, pin; - for (pin = 0; pin < nr_ioapic_registers; pin++) { - idx = find_irq_entry(pin,mp_INT); - if ((idx != -1) && (irq == pin_2_irq(idx,pin))) - return irq_trigger(idx); + for (apic = 0; apic < mp_apic_entries; apic++) { + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { + idx = find_irq_entry(apic,pin,mp_INT); + if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) + return irq_trigger(idx); + } } /* * nonexistent IRQs are edge default @@ -582,11 +597,12 @@ void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; - int pin, idx, bus, irq, first_notcon = 1; + int apic, pin, idx, irq, first_notcon = 1; printk("init IO_APIC IRQs\n"); - for (pin = 0; pin < nr_ioapic_registers; pin++) { + for (apic = 0; apic < mp_apic_entries; apic++) { + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { /* * add it to the IO-APIC irq-routing table: @@ -598,13 +614,13 @@ entry.mask = 0; /* enable IRQ */ entry.dest.logical.logical_dest = 0; /* but no route */ - idx = find_irq_entry(pin,mp_INT); + idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(" IO-APIC pin %d", pin); + printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin); first_notcon = 0; } else - printk(", %d", pin); + printk(", %d-%d", mp_apics[apic].mpc_apicid, pin); continue; } @@ -617,18 +633,17 @@ entry.dest.logical.logical_dest = 0xff; } - irq = pin_2_irq(idx,pin); - add_pin_to_irq(irq, pin); + irq = pin_2_irq(idx,apic,pin); + add_pin_to_irq(irq, apic, pin); - if (!IO_APIC_IRQ(irq)) + if (!apic && !IO_APIC_IRQ(irq)) continue; entry.vector = assign_irq_vector(irq); - bus = mp_irqs[idx].mpc_srcbus; - - io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); - io_apic_write(0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + } } if (!first_notcon) @@ -638,7 +653,7 @@ /* * Set up a certain pin as ExtINT delivered interrupt */ -void __init setup_ExtINT_pin(unsigned int pin, int irq) +void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq) { struct IO_APIC_route_entry entry; @@ -662,8 +677,8 @@ entry.polarity = 0; entry.trigger = 0; - io_apic_write(0x10+2*pin, *(((int *)&entry)+0)); - io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); } void __init UNEXPECTED_IO_APIC(void) @@ -674,17 +689,14 @@ void __init print_IO_APIC(void) { - int i; + int apic, i; struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; printk("number of MP IRQ sources: %d.\n", mp_irq_entries); - printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers); - - *(int *)&reg_00 = io_apic_read(0); - *(int *)&reg_01 = io_apic_read(1); - *(int *)&reg_02 = io_apic_read(2); + for (i = 0; i < mp_apic_entries; i++) + printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]); /* * We are a bit conservative about what we expect. We have to @@ -692,6 +704,12 @@ */ printk("testing the IO APIC.......................\n"); + for (apic = 0; apic < mp_apic_entries; apic++) { + + *(int *)&reg_00 = io_apic_read(apic, 0); + *(int *)&reg_01 = io_apic_read(apic, 1); + *(int *)&reg_02 = io_apic_read(apic, 2); + printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid); printk(".... register #00: %08X\n", *(int *)&reg_00); printk("....... : physical APIC id: %02X\n", reg_00.ID); if (reg_00.__reserved_1 || reg_00.__reserved_2) @@ -706,8 +724,6 @@ (reg_01.entries != 0x3F) /* bigger Xeon boards */ ) UNEXPECTED_IO_APIC(); - if (reg_01.entries == 0x0f) - printk("....... [IO-APIC cannot route PCI PIRQ 0-3]\n"); printk("....... : IO APIC version: %04X\n", reg_01.version); if ( (reg_01.version != 0x10) && /* oldest IO-APICs */ @@ -731,8 +747,8 @@ for (i = 0; i <= reg_01.entries; i++) { struct IO_APIC_route_entry entry; - *(((int *)&entry)+0) = io_apic_read(0x10+i*2); - *(((int *)&entry)+1) = io_apic_read(0x11+i*2); + *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); + *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); printk(" %02x %03X %02X ", i, @@ -751,7 +767,7 @@ entry.vector ); } - + } printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; @@ -796,9 +812,12 @@ */ { struct IO_APIC_reg_01 reg_01; + int i; - *(int *)&reg_01 = io_apic_read(1); - nr_ioapic_registers = reg_01.entries+1; + for (i = 0; i < mp_apic_entries; i++) { + *(int *)&reg_01 = io_apic_read(i, 1); + nr_ioapic_registers[i] = reg_01.entries+1; + } } /* @@ -897,15 +916,15 @@ /* * Set the ID */ - *(int *)&reg_00 = io_apic_read(0); + *(int *)&reg_00 = io_apic_read(0, 0); printk("...changing IO-APIC physical APIC ID to 2...\n"); reg_00.ID = 0x2; - io_apic_write(0, *(int *)&reg_00); + io_apic_write(0, 0, *(int *)&reg_00); /* * Sanity check */ - *(int *)&reg_00 = io_apic_read(0); + *(int *)&reg_00 = io_apic_read(0, 0); if (reg_00.ID != 0x2) panic("could not set ID"); } @@ -1225,7 +1244,10 @@ if (pin2 != -1) { printk(".. (found pin %d) ...", pin2); - setup_ExtINT_pin(pin2, 0); + /* + * legacy devices should be connected to IO APIC #0 + */ + setup_ExtINT_pin(0, pin2, 0); make_8259A_irq(0); } @@ -1236,9 +1258,9 @@ * Just in case ... */ if (pin1 != -1) - clear_IO_APIC_pin(pin1); + clear_IO_APIC_pin(0, pin1); if (pin2 != -1) - clear_IO_APIC_pin(pin2); + clear_IO_APIC_pin(0, pin2); make_8259A_irq(0); @@ -1280,7 +1302,8 @@ * - those for which the user has specified a pirq= parameter */ if ( ioapic_whitelisted() || - (nr_ioapic_registers == 16) || + (mp_apic_entries == 1 && nr_ioapic_registers[0] == 16) || + (mp_apic_entries > 1) || pirqs_enabled) { printk("ENABLING IO-APIC IRQs\n"); diff -urN linux.orig/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- linux.orig/arch/i386/kernel/irq.h Sat Apr 17 06:29:23 1999 +++ linux/arch/i386/kernel/irq.h Fri Apr 23 20:57:16 1999 @@ -111,6 +111,11 @@ extern char _stext, _etext; +/* + * IF YOU CHANGE THIS, PLEASE ALSO CHANGE + * FIX_IO_APIC_BASE_* in fixmap.h + */ +#define MAX_IO_APICS 4 #define MAX_IRQ_SOURCES 128 #define MAX_MP_BUSSES 32 enum mp_bustype { diff -urN linux.orig/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- linux.orig/arch/i386/kernel/smp.c Tue Mar 30 04:14:50 1999 +++ linux/arch/i386/kernel/smp.c Fri Apr 23 20:57:18 1999 @@ -125,6 +125,8 @@ const char lk_lockmsg[] = "lock from interrupt context at %p\n"; int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; +extern int mp_apic_entries; +extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS]; extern int mp_irq_entries; extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; extern int mpc_default_type; @@ -373,11 +375,9 @@ printk("I/O APIC #%d Version %d at 0x%lX.\n", m->mpc_apicid,m->mpc_apicver, m->mpc_apicaddr); - /* - * we use the first one only currently - */ - if (ioapics == 1) - mp_ioapic_addr = m->mpc_apicaddr; + mp_apics [mp_apic_entries] = *m; + if (++mp_apic_entries > MAX_IO_APICS) + --mp_apic_entries; } mpt+=sizeof(*m); count+=sizeof(*m); @@ -409,9 +409,9 @@ } } } - if (ioapics > 1) + if (ioapics > MAX_IO_APICS) { - printk("Warning: Multiple IO-APICs not yet supported.\n"); + printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics); printk("Warning: switching to non APIC mode.\n"); skip_ioapic_setup=1; } @@ -777,18 +777,22 @@ #ifdef CONFIG_X86_IO_APIC { - unsigned long ioapic_phys; + unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; + int i; - if (smp_found_config) { - ioapic_phys = mp_ioapic_addr; - } else { - ioapic_phys = __pa(memory_start); - memset((void *)memory_start, 0, PAGE_SIZE); - memory_start += PAGE_SIZE; + for (i = 0; i < mp_apic_entries; i++) { + if (smp_found_config) { + ioapic_phys = mp_apics[i].mpc_apicaddr; + } else { + ioapic_phys = __pa(memory_start); + memset((void *)memory_start, 0, PAGE_SIZE); + memory_start += PAGE_SIZE; + } + set_fixmap(idx,ioapic_phys); + printk("mapped IOAPIC to %08lx (%08lx)\n", + __fix_to_virt(idx), ioapic_phys); + idx++; } - set_fixmap(FIX_IO_APIC_BASE,ioapic_phys); - printk("mapped IOAPIC to %08lx (%08lx)\n", - fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys); } #endif diff -urN linux.orig/include/asm-i386/fixmap.h linux/include/asm-i386/fixmap.h --- linux.orig/include/asm-i386/fixmap.h Sat Apr 17 06:28:07 1999 +++ linux/include/asm-i386/fixmap.h Fri Apr 23 20:57:56 1999 @@ -45,7 +45,10 @@ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ #endif #ifdef CONFIG_X86_IO_APIC - FIX_IO_APIC_BASE, + FIX_IO_APIC_BASE_0, /* IF YOU CHANGE THIS, PLEASE ALSO CHANGE */ + FIX_IO_APIC_BASE_1, /* MAX_IO_APICS in arch/i386/irq.h */ + FIX_IO_APIC_BASE_2, + FIX_IO_APIC_BASE_3, #endif #ifdef CONFIG_X86_VISWS_APIC FIX_CO_CPU, /* Cobalt timer */

--------------57EB8EFBB0332887C980E222--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/