Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Jun 2004 15:31:09 -0400
From:      John Baldwin <jhb@FreeBSD.org>
To:        acpi@FreeBSD.org
Cc:        marcel@FreeBSD.org
Subject:   Patch: Defer bus_config_intr() until bus_alloc_resource()..
Message-ID:  <200406011531.09077.jhb@FreeBSD.org>

next in thread | raw e-mail | index | archive | help
I need the patch below in order to turn on bus_config_intr() when using the 
I/O APICs.  The original problem is that the _CRS of link devices is 
configured which is the PIC IRQ and thus screws up intpins when using the 
APIC.  It basically takes bus_config_intr() out of the resource parsing code 
and does the config when an IRQ is allocated via bus_alloc_resource() for 
normal devices, and when a PCI IRQ is routed for PCI link devices.

--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi.c	2004/05/06 01:05:39
+++ //depot/user/jhb/acpipci/dev/acpica/acpi.c	2004/05/28 10:02:20
@@ -849,15 +849,82 @@
     return (0);
 }
 
+static void
+acpi_config_intr(device_t dev, u_int irq, int trig, int pol)
+{
+
+    BUS_CONFIG_INTR(dev, irq, (trig == ACPI_EDGE_SENSITIVE) ?
+	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
+	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
+}
+
 static struct resource *
 acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
 		    u_long start, u_long end, u_long count, u_int flags)
 {
     struct acpi_device *ad = device_get_ivars(child);
     struct resource_list *rl = &ad->ad_rl;
+    struct resource *res;
+    ACPI_RESOURCE *ares;
+    ACPI_BUFFER buf;
+    char *curr, *last;
+    int i;
 
-    return (resource_list_alloc(rl, bus, child, type, rid, start, end, count,
-	    flags));
+    res = resource_list_alloc(rl, bus, child, type, rid, start, end, count,
+	flags);
+    if (res == NULL || device_get_parent(child) != bus)
+	    return (res);
+    switch (type) {
+    case SYS_RES_IRQ:
+	    buf.Length = ACPI_ALLOCATE_BUFFER;
+	    if (ACPI_FAILURE((AcpiGetCurrentResources(ad->ad_handle, &buf))))
+		    break;
+	    i = 0;
+	    curr = buf.Pointer;
+	    last = (char *)buf.Pointer + buf.Length;
+	    while (curr < last) {
+		    ares = (ACPI_RESOURCE *)curr;
+		    curr += ares->Length;
+		    switch (ares->Id) {
+		    case ACPI_RSTYPE_END_TAG:
+			    curr = last;
+			    break;
+		    case ACPI_RSTYPE_IRQ:
+			    if (ares->Data.Irq.NumberOfInterrupts != 1)
+				    break;
+			    if (i != *rid) {
+				    i++;
+				    break;
+			    }
+			    KASSERT(ares->Data.Irq.Interrupts[0] ==
+				rman_get_start(res),
+				("IRQ resources do not match"));
+			    acpi_config_intr(child,
+				ares->Data.Irq.Interrupts[0],
+				ares->Data.Irq.EdgeLevel,
+				ares->Data.Irq.ActiveHighLow);
+			    break;
+		    case ACPI_RSTYPE_EXT_IRQ:
+			    if (ares->Data.ExtendedIrq.NumberOfInterrupts != 1)
+				    break;
+			    if (i != *rid) {
+				    i++;
+				    break;
+			    }
+			    KASSERT(ares->Data.ExtendedIrq.Interrupts[0] ==
+				rman_get_start(res),
+				("IRQ resources do not match"));
+			    acpi_config_intr(child,
+				ares->Data.ExtendedIrq.Interrupts[0],
+				ares->Data.ExtendedIrq.EdgeLevel,
+				ares->Data.ExtendedIrq.ActiveHighLow);
+			    break;
+		    }
+	    }
+	    AcpiOsFree(buf.Pointer);
+	    break;
+    }
+    return (res);
 }
 
 static int
--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib.c	2004/05/05 19:22:26
+++ //depot/user/jhb/acpipci/dev/acpica/acpi_pcib.c	2004/05/28 06:38:57
@@ -121,10 +121,11 @@
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
     
+    crsres = NULL;
     buf.Pointer = NULL;
     crsbuf.Pointer = NULL;
     prsbuf.Pointer = NULL;
-    interrupt = 255;
+    interrupt = PCI_INVALID_IRQ;
 
     /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */
     pin--;
@@ -348,6 +349,7 @@
 
     /* XXX Data.Irq and Data.ExtendedIrq are implicitly structure-copied. */
     crsbuf.Pointer = NULL;
+    crsres = NULL;
     if (prsres->Id == ACPI_RSTYPE_IRQ) {
 	resbuf.Id = ACPI_RSTYPE_IRQ;
 	resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
@@ -378,6 +380,7 @@
 		      AcpiFormatException(status));
 	goto out;
     }
+    crsres = &resbuf;
     
     /* Return the interrupt we just routed. */
     device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 
@@ -386,6 +389,20 @@
     interrupt = Interrupts[0];
 
 out:
+    if (PCI_INTERRUPT_VALID(interrupt) && crsres != NULL) {
+	int trig, pol;
+
+	if (crsres->Id == ACPI_RSTYPE_IRQ) {
+	    trig = crsres->Data.Irq.EdgeLevel;
+	    pol = crsres->Data.Irq.ActiveHighLow;
+	} else {
+	    trig = crsres->Data.ExtendedIrq.EdgeLevel;
+	    pol = crsres->Data.ExtendedIrq.ActiveHighLow;
+	}
+	BUS_CONFIG_INTR(dev, interrupt, (trig == ACPI_EDGE_SENSITIVE) ?
+	    INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
+	    INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
+    }
     if (crsbuf.Pointer != NULL)
 	AcpiOsFree(crsbuf.Pointer);
     if (prsbuf.Pointer != NULL)
@@ -393,6 +410,5 @@
     if (buf.Pointer != NULL)
 	AcpiOsFree(buf.Pointer);
 
-    /* XXX APIC_IO interrupt mapping? */
     return_VALUE (interrupt);
 }
--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_resource.c	2004/04/09 
11:15:38
+++ //depot/user/jhb/acpipci/dev/acpica/acpi_resource.c	2004/05/28 10:02:20
@@ -495,9 +495,6 @@
 	return;
 
     bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
-    BUS_CONFIG_INTR(dev, *irq, (trig == ACPI_EDGE_SENSITIVE) ?
-	INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL, (pol == ACPI_ACTIVE_HIGH) ?
-	INTR_POLARITY_HIGH : INTR_POLARITY_LOW);
 }
 
 static void

-- 
John Baldwin <jhb@FreeBSD.org>  <><  http://www.FreeBSD.org/~jhb/
"Power Users Use the Power to Serve"  =  http://www.FreeBSD.org



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200406011531.09077.jhb>