It is currently Sat, 24 Oct 2020 09:28:54 GMT



 
Author Message
 unexpected IO-APIC update

Hi,

Recently there has been a rash of Unexpected IO APIC reports on
the linux-smp mailing list.  Most of the most recent ones are due
to some newer Intel chipsets (865, 875).

The IO APIC Version register doesn't indicate the differences in
these IO APICs.

I have an patch that addresses these chipsets.  It has been
tested by a few people with good results and has been blessed
by Maciej Rozycki.

Other than conditionally decoding IO APIC registers 2 and 3,
we could alternately ignore them since Linux doesn't use the values
for anything other than printing them.

This patch ignores IO APIC register 2 if it's the same value as IO APIC
register 1.  It also reads IO APIC register 3 if the IO APIC
version is >= 0x20, but some chipsets don't support this
register, so it is also ignored if its value if the same as IO APIC
register 1 or 2.

Another possible(?) alternative is to read the PID/VID of the
device to determine which registers it supports.  However,
PCI devices have not been scanned at this point in init, so it
would require scanning PCI config space directly and I don't
yet see the point of doing that.

Oh, and the UNEXPECTED_IO_APIC() function doesn't print anything
in 2.5.current and I didn't change that.

Patch for 2.5.73 is below.  Please apply.

--
~Randy
~ http://www.**-**.com/ ~ http://www.**-**.com/ ~

patch_name:     ioapic_update_2573.patch
patch_version:  2003-06-24.15:43:44
author:         Randy.Dunlap <rddun...@osdl.org>
description:    support newer Intel chipset IO APICs;
product:        Linux
product_versions: linux-2573
maintainer:     Maciej W. Rozycki <ma...@ds2.pg.gda.pl>
diffstat:       =
 arch/i386/kernel/io_apic.c |   26 +++++++++++++++++++++++++-
 include/asm-i386/io_apic.h |    5 +++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff -Naur ./include/asm-i386/io_apic.h~ioap ./include/asm-i386/io_apic.h
--- ./include/asm-i386/io_apic.h~ioap   2003-06-14 12:18:25.000000000 -0700
+++ ./include/asm-i386/io_apic.h        2003-06-14 20:17:44.000000000 -0700
@@ -44,6 +44,11 @@
                __reserved_1    :  4;
 } __attribute__ ((packed));

+struct IO_APIC_reg_03 {
+       __u32   boot_DT         :  1,
+               __reserved_1    : 31;
+} __attribute__ ((packed));
+
 /*
  * # of IO-APICs and # of IRQ routing registers
  */
diff -Naur ./arch/i386/kernel/io_apic.c~ioap ./arch/i386/kernel/io_apic.c
--- ./arch/i386/kernel/io_apic.c~ioap   2003-06-14 12:18:06.000000000 -0700
+++ ./arch/i386/kernel/io_apic.c        2003-06-14 20:43:19.000000000 -0700
@@ -1275,6 +1278,7 @@
        struct IO_APIC_reg_00 reg_00;
        struct IO_APIC_reg_01 reg_01;
        struct IO_APIC_reg_02 reg_02;
+       struct IO_APIC_reg_03 reg_03;
        unsigned long flags;

        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
@@ -1295,6 +1299,8 @@
        *(int *)&reg_01 = io_apic_read(apic, 1);
        if (reg_01.version >= 0x10)
                *(int *)&reg_02 = io_apic_read(apic, 2);
+       if (reg_01.version >= 0x20)
+               *(int *)&reg_03 = io_apic_read(apic, 3);
        spin_unlock_irqrestore(&ioapic_lock, flags);

        printk("\n");
@@ -1332,13 +1336,31 @@
        if (reg_01.__reserved_1 || reg_01.__reserved_2)
                UNEXPECTED_IO_APIC();

-       if (reg_01.version >= 0x10) {
+       /*
+        * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
+        * but the value of reg_02 is read as the previous read register
+        * value, so ignore it if reg_02 == reg_01.
+        */
+       if (reg_01.version >= 0x10 && *(int *)&reg_02 != *(int *)&reg_01) {
                printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)&reg_02);
                printk(KERN_DEBUG ".......     : arbitration: %02X\n", reg_02.arbitration);
                if (reg_02.__reserved_1 || reg_02.__reserved_2)
                        UNEXPECTED_IO_APIC();
        }

+       /*
+        * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02
+        * or reg_03, but the value of reg_0[23] is read as the previous read
+        * register value, so ignore it if reg_03 == reg_0[12].
+        */
+       if (reg_01.version >= 0x20 && *(int *)&reg_03 != *(int *)&reg_02 &&
+           *(int *)&reg_03 != *(int *)&reg_01) {
+               printk(KERN_DEBUG ".... register #03: %08X\n", *(int *)&reg_03);
+               printk(KERN_DEBUG ".......     : Boot DT    : %X\n", reg_03.boot_DT);
+               if (reg_03.__reserved_1)
+                       UNEXPECTED_IO_APIC();
+       }
+
        printk(KERN_DEBUG ".... IRQ redirection table:\n");

        printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at   http://www.**-**.com/
Please read the FAQ at   http://www.**-**.com/



 Sun, 11 Dec 2005 00:20:12 GMT   
 unexpected IO-APIC update

There's a lot of these

        *(int *)&reg_03

kinds of things there, and the fact is, gcc's alias analysis doesn't like
them, _and_ they are ugly.

The alias analysis I could care less about, since a good alias analysis
would take static address information into account, and gcc at least last
time I looked wasn't. So we don't even bother using it for now.

We may want to reconsider that eventually, though, since more recent
versions of gcc at least try to make their alias analysis useful with
things like "attribute((may_alias))"  or whatever the syntax was.

But the ugliness part I care about, and I wonder if it wouldn't be better
in this case to just make the register definition a "union", and have
something like

        union reg_03 {
                u32 value;
                struct {
                        u32 boot_DT:1,
                            reserved:31;
                } bits;
        };

and then you can avoid the ugly dereference/cast/address-of thing, and
just say

        reg_03.value

or

        reg_03.bits.boot_DT

which looks a lot cleaner.

This is what unions are _designed_ for.

                Linus

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



 Sun, 11 Dec 2005 02:40:09 GMT   
 unexpected IO-APIC update
On Tue, 24 Jun 2003 18:31:12 -0700 (PDT) Linus Torvalds <torva...@transmeta.com> wrote:

|
| On Tue, 24 Jun 2003, Randy.Dunlap wrote:
| >
| > +        if (reg_01.version >= 0x20)
| > +                *(int *)&reg_03 = io_apic_read(apic, 3);
|
| There's a lot of these
|
|       *(int *)&reg_03
|
| kinds of things there, and the fact is, gcc's alias analysis doesn't like
| them, _and_ they are ugly.
|
[snippage]
|
| But the ugliness part I care about, and I wonder if it wouldn't be better
| in this case to just make the register definition a "union", and have
| something like
|
|       union reg_03 {
|               u32 value;
|               struct {
|                       u32 boot_DT:1,
|                           reserved:31;
|               } bits;
|       };
|
| and then you can avoid the ugly dereference/cast/address-of thing, and
| just say
|
|       reg_03.value
|
| or
|
|       reg_03.bits.boot_DT
|
| which looks a lot cleaner.
|
| This is what unions are _designed_ for.

Sure, I'll do that.

--
~Randy
~ http://developer.osdl.org/rddunlap/ ~ http://www.xenotime.net/linux/ ~
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



 Sun, 11 Dec 2005 17:10:06 GMT   
 unexpected IO-APIC update

 Perhaps using "raw" instead of "value" would be prettier and certainly we
would save two characters per reference. ;-)  Anyway, it's indeed a good
opportunity to do a clean-up while fiddling with these bits.

--
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: ma...@ds2.pg.gda.pl, PGP key available        +

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



 Sun, 11 Dec 2005 17:20:08 GMT   
 unexpected IO-APIC update
On Wed, 25 Jun 2003 18:11:06 +0200 (MET DST) "Maciej W. Rozycki" <ma...@ds2.pg.gda.pl> wrote:

| On Wed, 25 Jun 2003, Randy.Dunlap wrote:
|
| > | But the ugliness part I care about, and I wonder if it wouldn't be better
| > | in this case to just make the register definition a "union", and have
| > | something like
| > |
| > |        union reg_03 {
| > |                u32 value;
| > |                struct {
| > |                        u32 boot_DT:1,
| > |                            reserved:31;
| > |                } bits;
| > |        };
| [...]
| > Sure, I'll do that.
|
|  Perhaps using "raw" instead of "value" would be prettier and certainly we
| would save two characters per reference. ;-)  Anyway, it's indeed a good
| opportunity to do a clean-up while fiddling with these bits.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I prefer that name also.  Patch is below.

Linus, this patch is on top of yesterday's patch (or on top of
today's -bk3 snapshot).  Please apply.  Builds and boots.

--
~Randy
~ http://developer.osdl.org/rddunlap/ ~ http://www.xenotime.net/linux/ ~

patch_name:     ioapic_union.patch
patch_version:  2003-06-25.10:52:07
author:         Randy.Dunlap <rddun...@osdl.org>
description:    use unions in IO APIC data structs;
product:        Linux
product_versions: linux-2.5.73
maintainer:     Maciej W. Rozycki <ma...@ds2.pg.gda.pl>
diffstat:       =
 arch/i386/kernel/io_apic.c |  138 ++++++++++++++++++++++-----------------------
 include/asm-i386/io_apic.h |   58 +++++++++++-------
 2 files changed, 104 insertions(+), 92 deletions(-)

diff -Naur ./arch/i386/kernel/io_apic.c~union ./arch/i386/kernel/io_apic.c
--- ./arch/i386/kernel/io_apic.c~union  2003-06-25 10:51:59.000000000 -0700
+++ ./arch/i386/kernel/io_apic.c        2003-06-25 10:50:00.000000000 -0700
@@ -1272,10 +1272,10 @@
 void __init print_IO_APIC(void)
 {
        int apic, i;
-       struct IO_APIC_reg_00 reg_00;
-       struct IO_APIC_reg_01 reg_01;
-       struct IO_APIC_reg_02 reg_02;
-       struct IO_APIC_reg_03 reg_03;
+       union IO_APIC_reg_00 reg_00;
+       union IO_APIC_reg_01 reg_01;
+       union IO_APIC_reg_02 reg_02;
+       union IO_APIC_reg_03 reg_03;
        unsigned long flags;

        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
@@ -1292,47 +1292,47 @@
        for (apic = 0; apic < nr_ioapics; apic++) {

        spin_lock_irqsave(&ioapic_lock, flags);
-       *(int *)&reg_00 = io_apic_read(apic, 0);
-       *(int *)&reg_01 = io_apic_read(apic, 1);
-       if (reg_01.version >= 0x10)
-               *(int *)&reg_02 = io_apic_read(apic, 2);
-       if (reg_01.version >= 0x20)
-               *(int *)&reg_03 = io_apic_read(apic, 3);
+       reg_00.raw = io_apic_read(apic, 0);
+       reg_01.raw = io_apic_read(apic, 1);
+       if (reg_01.bits.version >= 0x10)
+               reg_02.raw = io_apic_read(apic, 2);
+       if (reg_01.bits.version >= 0x20)
+               reg_03.raw = io_apic_read(apic, 3);
        spin_unlock_irqrestore(&ioapic_lock, flags);

        printk("\n");
        printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
-       printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)&reg_00);
-       printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.ID);
-       printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.delivery_type);
-       printk(KERN_DEBUG ".......    : LTS          : %X\n", reg_00.LTS);
-       if (reg_00.ID >= APIC_BROADCAST_ID)
+       printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
+       printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
+       printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.bits.delivery_type);
+       printk(KERN_DEBUG ".......    : LTS          : %X\n", reg_00.bits.LTS);
+       if (reg_00.bits.ID >= APIC_BROADCAST_ID)
                UNEXPECTED_IO_APIC();
-       if (reg_00.__reserved_1 || reg_00.__reserved_2)
+       if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
                UNEXPECTED_IO_APIC();

-       printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
-       printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.entries);
-       if (    (reg_01.entries != 0x0f) && /* older (Neptune) boards */
-               (reg_01.entries != 0x17) && /* typical ISA+PCI boards */
-               (reg_01.entries != 0x1b) && /* Compaq Proliant boards */
-               (reg_01.entries != 0x1f) && /* dual Xeon boards */
-               (reg_01.entries != 0x22) && /* bigger Xeon boards */
-               (reg_01.entries != 0x2E) &&
-               (reg_01.entries != 0x3F)
+       printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw);
+       printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.bits.entries);
+       if (    (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */
+               (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */
+               (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */
+               (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */
+               (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
+               (reg_01.bits.entries != 0x2E) &&
+               (reg_01.bits.entries != 0x3F)
        )
                UNEXPECTED_IO_APIC();

-       printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.PRQ);
-       printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.version);
-       if (    (reg_01.version != 0x01) && /* 82489DX IO-APICs */
-               (reg_01.version != 0x10) && /* oldest IO-APICs */
-               (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
-               (reg_01.version != 0x13) && /* Xeon IO-APICs */
-               (reg_01.version != 0x20)    /* Intel P64H (82806 AA) */
+       printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.bits.PRQ);
+       printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.bits.version);
+       if (    (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */
+               (reg_01.bits.version != 0x10) && /* oldest IO-APICs */
+               (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
+               (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
+               (reg_01.bits.version != 0x20)    /* Intel P64H (82806 AA) */
        )
                UNEXPECTED_IO_APIC();
-       if (reg_01.__reserved_1 || reg_01.__reserved_2)
+       if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
                UNEXPECTED_IO_APIC();

        /*
@@ -1340,10 +1340,10 @@
         * but the value of reg_02 is read as the previous read register
         * value, so ignore it if reg_02 == reg_01.
         */
-       if (reg_01.version >= 0x10 && *(int *)&reg_02 != *(int *)&reg_01) {
-               printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)&reg_02);
-               printk(KERN_DEBUG ".......     : arbitration: %02X\n", reg_02.arbitration);
-               if (reg_02.__reserved_1 || reg_02.__reserved_2)
+       if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
+               printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
+               printk(KERN_DEBUG ".......     : arbitration: %02X\n", reg_02.bits.arbitration);
+               if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
                        UNEXPECTED_IO_APIC();
        }

@@ -1352,11 +1352,11 @@
         * or reg_03, but the value of reg_0[23] is read as the previous read
         * register value, so ignore it if reg_03 == reg_0[12].
         */
-       if (reg_01.version >= 0x20 && *(int *)&reg_03 != *(int *)&reg_02 &&
-           *(int *)&reg_03 != *(int *)&reg_01) {
-               printk(KERN_DEBUG ".... register #03: %08X\n", *(int *)&reg_03);
-               printk(KERN_DEBUG ".......     : Boot DT    : %X\n", reg_03.boot_DT);
-               if (reg_03.__reserved_1)
+       if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&
+           reg_03.raw != reg_01.raw) {
+               printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);
+               printk(KERN_DEBUG ".......     : Boot DT    : %X\n", reg_03.bits.boot_DT);
+               if (reg_03.bits.__reserved_1)
                        UNEXPECTED_IO_APIC();
        }

@@ -1365,7 +1365,7 @@
        printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
                          " Stat Dest Deli Vect:   \n");

-       for (i = 0; i <= reg_01.entries; i++) {
+       for (i = 0; i <= reg_01.bits.entries; i++) {
                struct IO_APIC_route_entry entry;

                spin_lock_irqsave(&ioapic_lock, flags);
@@ -1546,7 +1546,7 @@

 static void __init enable_IO_APIC(void)
 {
-       struct IO_APIC_reg_01 reg_01;
+       union IO_APIC_reg_01 reg_01;
        int i;
        unsigned long flags;

@@ -1563,9 +1563,9 @@
         */
        for (i = 0; i < nr_ioapics; i++) {
                spin_lock_irqsave(&ioapic_lock, flags);
-               *(int *)&reg_01 = io_apic_read(i, 1);
+               reg_01.raw = io_apic_read(i, 1);
                spin_unlock_irqrestore(&ioapic_lock, flags);
-               nr_ioapic_registers[i] = reg_01.entries+1;
+               nr_ioapic_registers[i] = reg_01.bits.entries+1;
        }

        /*
@@ -1597,7 +1597,7 @@
 #ifndef CONFIG_X86_NUMAQ
 static void __init setup_ioapic_ids_from_mpc(void)
 {
-       struct IO_APIC_reg_00 reg_00;
+       union IO_APIC_reg_00 reg_00;
        unsigned long phys_id_present_map;
        int apic;
        int i;
@@ -1617,7 +1617,7 @@

                /* Read the register 0 value */
                spin_lock_irqsave(&ioapic_lock, flags);
-               *(int *)&reg_00 = io_apic_read(apic, 0);
+               reg_00.raw = io_apic_read(apic, 0);
                spin_unlock_irqrestore(&ioapic_lock, flags);

                old_id = mp_ioapics[apic].mpc_apicid;
@@ -1626,8 +1626,8 @@
                        printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
                                apic, mp_ioapics[apic].mpc_apicid);
                        printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
-                               reg_00.ID);
-                       mp_ioapics[apic].mpc_apicid = reg_00.ID;
+                               reg_00.bits.ID);
+                       mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;
                }

                /*
@@ -1671,18 +1671,18 @@
                printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...",
                                        mp_ioapics[apic].mpc_apicid);

-               reg_00.ID = mp_ioapics[apic].mpc_apicid;
+               reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;
                spin_lock_irqsave(&ioapic_lock, flags);
-               io_apic_write(apic, 0, *(int *)&reg_00);
+               io_apic_write(apic, 0, reg_00.raw);
                spin_unlock_irqrestore(&ioapic_lock, flags);

                /*
                 * Sanity check
                 */
                spin_lock_irqsave(&ioapic_lock, flags);
-               *(int *)&reg_00 = io_apic_read(apic, 0);
+               reg_00.raw = io_apic_read(apic, 0);
                spin_unlock_irqrestore(&ioapic_lock, flags);
-               if (reg_00.ID != mp_ioapics[apic].mpc_apicid)
+               if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
                        panic("could not set ID!\n");
                else
                        printk(" ok.\n");
@@ -2220,7 +2220,7 @@

 int __init io_apic_get_unique_id (int ioapic, int apic_id)
 {
-       struct IO_APIC_reg_00 reg_00;
+       union IO_APIC_reg_00 reg_00;
        static unsigned long apic_id_map = 0;
        unsigned long flags;
        int i = 0;
@@ -2238,13 +2238,13 @@
                apic_id_map = phys_cpu_present_map;

        spin_lock_irqsave(&ioapic_lock, flags);
- ...

read more »



 Sun, 11 Dec 2005 19:30:20 GMT   
 unexpected IO-APIC update

 It looks OK for me -- thanks a lot for the boring work.  My system is
still down, so I'll do a run-time test later.

--
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: ma...@ds2.pg.gda.pl, PGP key available        +

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



 Mon, 12 Dec 2005 14:50:10 GMT   
 
   [ 7 post ] 

Similar Threads

1. IO-APIC says: unexpected IO-APIC was found

2. PATCH] unexpected IO-APIC update

3. update unexpected IO APIC detection

4. Unexpected IO-APIC

5. New: unexpected IO-APIC

6. unexpected IO-APIC

7. unexpected IO-APIC on IBM xSeries 440

8. WARNING: unexpected IO-APIC on 2.4.19-pre4-ac3

9. Unexpected IO-APIC messages

10. 2.4.5-ac6: IDE deadlocks/bugs + unexpected IO-APIC


 
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software