NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/47648: NetBSD 6.1_RC1 ACPI interupt routing problem + other ACPI lossage



On Mon, Mar 18, 2013 at 10:09:33PM +0100, Reinoud Zandijk wrote:
> On Mon, Mar 18, 2013 at 10:10:02AM -0700, Chuck Silvers wrote:
> > actually I thought of a simpler hack than I was thinking of before,
> > please try the attached patch.
> > 
> > if that works then there's other hacky code (from before I got involved)
> > that can be removed too.
> 
> The patch workes and fixes the problem! I get a neat 100 interrupts/sec and my
> impression is that it is smoother than before, but thats most likely my
> imagination :)

the previous patch had several problems, please try the new one that's attached.
I dug through all my x86 boxes and finally found one with an "interesting"
ACPI setup, and this latest patch works on that one too.
could all the folks who have had trouble with my ACPI changes please
retest with this latest patch to make sure I haven't broken any of those
systems that I fixed previously?  this patch applies to either -current or 
netbsd-6.

-Chuck
Index: src/sys/arch/x86/x86/mpacpi.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/arch/x86/x86/mpacpi.c,v
retrieving revision 1.96
diff -u -p -r1.96 mpacpi.c
--- src/sys/arch/x86/x86/mpacpi.c       3 Oct 2012 17:04:25 -0000       1.96
+++ src/sys/arch/x86/x86/mpacpi.c       23 Mar 2013 14:37:46 -0000
@@ -133,8 +133,6 @@ static int mpacpi_maxpci;
 static int mpacpi_npciroots;
 #endif
 
-struct mp_intr_map *mpacpi_sci_override;
-
 static int mpacpi_intr_index;
 static paddr_t mpacpi_lapic_base = LAPIC_BASE;
 
@@ -299,9 +297,6 @@ mpacpi_nonpci_intr(ACPI_SUBTABLE_HEADER 
                if (pic->pic_type == PIC_IOAPIC)
                        pic->pic_ioapic->sc_pins[pin].ip_map = mpi;
 #endif
-               if (isa_ovr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
-                       mpacpi_sci_override = mpi;
-
                break;
 
        case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
@@ -942,13 +937,6 @@ mpacpi_find_interrupts(void *self)
                printf("mpacpi: %d PCI busses\n", mpacpi_npci);
 #endif
        mpacpi_config_irouting(acpi);
-#if NIOAPIC > 0
-       /*
-        * XXX fix up the SCI interrupt polarity.
-        * it's installed before we have parsed the MADT.
-        */
-       ioapic_reenable();
-#endif
        if (mp_verbose)
                for (i = 0; i < mp_nintr; i++)
                        mpacpi_print_intr(&mp_intrs[i]);
Index: src/sys/arch/x86/acpi/acpi_machdep.c
===================================================================
RCS file: /home/chs/netbsd/cvs/src/sys/arch/x86/acpi/acpi_machdep.c,v
retrieving revision 1.4
diff -u -p -r1.4 acpi_machdep.c
--- src/sys/arch/x86/acpi/acpi_machdep.c        23 Sep 2012 00:31:05 -0000      
1.4
+++ src/sys/arch/x86/acpi/acpi_machdep.c        23 Mar 2013 14:54:42 -0000
@@ -93,6 +93,31 @@ acpi_md_OsGetRootPointer(void)
        return PhysicalAddress;
 }
 
+struct acpi_md_override {
+       int irq;
+       int pin;
+       int flags;
+};
+
+static ACPI_STATUS
+acpi_md_findoverride(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
+{
+       ACPI_MADT_INTERRUPT_OVERRIDE *iop;
+       struct acpi_md_override *ovrp;
+
+       if (hdrp->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) {
+               return AE_OK;
+       }
+
+       iop = (void *)hdrp;
+       ovrp = aux;
+       if (iop->SourceIrq == ovrp->irq) {
+               ovrp->pin = iop->GlobalIrq;
+               ovrp->flags = iop->IntiFlags;
+       }
+       return AE_OK;
+}
+
 ACPI_STATUS
 acpi_md_OsInstallInterruptHandler(uint32_t InterruptNumber,
     ACPI_OSD_HANDLER ServiceRoutine, void *Context, void **cookiep)
@@ -101,41 +126,61 @@ acpi_md_OsInstallInterruptHandler(uint32
        struct pic *pic;
 #if NIOAPIC > 0
        struct ioapic_softc *sc;
+       struct acpi_md_override ovr;
+       struct mp_intr_map tmpmap, *mip, **mipp = NULL;
 #endif
-       int irq, pin, trigger;
+       int irq, pin, type, redir, mpflags;
+
+       /*
+        * ACPI interrupts default to level-triggered active-low.
+        */
+
+       type = IST_LEVEL;
+       mpflags = (MPS_INTTR_LEVEL << 2) | MPS_INTPO_ACTLO;
+       redir = IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO;
 
 #if NIOAPIC > 0
+
        /*
-        * Can only match on ACPI global interrupt numbers if the ACPI
-        * interrupt info was extracted, which is in the ACPI case.
+        * Apply any MADT override setting.
         */
-       if (mpacpi_sci_override != NULL) {
-               pic = mpacpi_sci_override->ioapic;
-               pin = mpacpi_sci_override->ioapic_pin;
-               if (mpacpi_sci_override->redir & IOAPIC_REDLO_LEVEL)
-                       trigger = IST_LEVEL;
-               else
-                       trigger = IST_EDGE;
-               if (pic->pic_type == PIC_IOAPIC)
-                       irq = -1;
-               else
-                       irq = (int)InterruptNumber;
-               goto sci_override;
+
+       ovr.irq = InterruptNumber;
+       ovr.pin = -1;
+       if (acpi_madt_map() == AE_OK) {
+               acpi_madt_walk(acpi_md_findoverride, &ovr);
+               acpi_madt_unmap();
+       } else {
+               aprint_debug("acpi_madt_map() failed, can't check for MADT 
override\n");
+       }
+
+       if (ovr.pin != -1) {
+               bool sci = InterruptNumber == AcpiGbl_FADT.SciInterrupt;
+               int polarity = ovr.flags & ACPI_MADT_POLARITY_MASK;
+               int trigger = ovr.flags & ACPI_MADT_TRIGGER_MASK;
+
+               InterruptNumber = ovr.pin;
+               if (polarity == ACPI_MADT_POLARITY_ACTIVE_HIGH ||
+                   (!sci && polarity == ACPI_MADT_POLARITY_CONFORMS)) {
+                       mpflags &= ~MPS_INTPO_ACTLO;
+                       redir &= ~IOAPIC_REDLO_ACTLO;
+               }
+               if (trigger == ACPI_MADT_TRIGGER_EDGE ||
+                   (!sci && trigger == ACPI_MADT_TRIGGER_CONFORMS)) {
+                       type = IST_EDGE;
+                       mpflags &= ~(MPS_INTTR_LEVEL << 2);
+                       redir &= ~IOAPIC_REDLO_LEVEL;
+               }
        }
-#endif
 
        /*
-        * There was no ACPI interrupt source override,
-        *
-        * If the interrupt is handled via IOAPIC, mark it
-        * as level-triggered, active low in the table.
+        * If the interrupt is handled via IOAPIC, update the map.
+        * If the map isn't set up yet, install a temporary one.
         */
 
-#if NIOAPIC > 0
        sc = ioapic_find_bybase(InterruptNumber);
        if (sc != NULL) {
                pic = &sc->sc_pic;
-               struct mp_intr_map *mip;
 
                if (pic->pic_type == PIC_IOAPIC) {
                        pin = (int)InterruptNumber - pic->pic_vecbase;
@@ -146,9 +191,15 @@ acpi_md_OsInstallInterruptHandler(uint32
 
                mip = sc->sc_pins[pin].ip_map;
                if (mip) {
-                       mip->flags &= ~3;
-                       mip->flags |= MPS_INTPO_ACTLO;
-                       mip->redir |= IOAPIC_REDLO_ACTLO;
+                       mip->flags &= ~0xf;
+                       mip->flags |= mpflags;
+                       mip->redir &= ~(IOAPIC_REDLO_LEVEL |
+                                       IOAPIC_REDLO_ACTLO);
+                       mip->redir |= redir;
+               } else {
+                       mipp = &sc->sc_pins[pin].ip_map;
+                       *mipp = &tmpmap;
+                       tmpmap.redir = redir;
                }
        } else
 #endif
@@ -157,18 +208,18 @@ acpi_md_OsInstallInterruptHandler(uint32
                irq = pin = (int)InterruptNumber;
        }
 
-       trigger = IST_LEVEL;
-
-#if NIOAPIC > 0
-sci_override:
-#endif
-
        /*
         * XXX probably, IPL_BIO is enough.
         */
-       ih = intr_establish(irq, pic, pin, trigger, IPL_TTY,
+       ih = intr_establish(irq, pic, pin, type, IPL_TTY,
            (int (*)(void *)) ServiceRoutine, Context, false);
 
+#if NIOAPIC > 0
+       if (mipp) {
+               *mipp = NULL;
+       }
+#endif
+
        if (ih == NULL)
                return AE_NO_MEMORY;
 


Home | Main Index | Thread Index | Old Index