Patch: Defer bus_config_intr() until bus_alloc_resource()..

John Baldwin jhb at FreeBSD.org
Tue Jun 1 14:42:21 PDT 2004


On Tuesday 01 June 2004 05:23 pm, Nate Lawson wrote:
> On Tue, 1 Jun 2004, John Baldwin wrote:
> > On Tuesday 01 June 2004 04:25 pm, Nate Lawson wrote:
> > > On Tue, 1 Jun 2004, John Baldwin wrote:
> > > > 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.
> > >
> > > I appreciate what you're trying to do but I don't like this approach.
> > > Deferring half the parsing to alloc time and moving it from
> > > acpi_resource.c results in a lot of unnecessary duplication and
> > > layering violation.  The real issue you're trying to work around is
> > > that you want to defer the actual config_intr until you're sure which
> > > intr you're going to use.
> >
> > Well, arguably it exposes an improper layering violation when
> > bus_config_intr() was added.  bus_config_intr() was probably added in the
> > place that it is now simply because it was easier to do so.  That doesn't
> > mean it's in the correct place.  I don't really consider having an
> > ACPI-specific routine understand ACPI-specific resources.  One
> > possibility though might be to add a wrapper function to acpi_resource.c
> > that does the bus_config_intr() on a passed-in pointer to an ACPI
> > resource.  That might reduce at least some of the duplication.
>
> I still don't like this.  Right now we have a single parse routine whose
> goal is to parse a resource object and then store the info it finds in a
> FreeBSD-compatible format, via bus_set_resource().  Just because
> bus_config_intr() doesn't stick to bus_set_resource() semantics doesn't
> mean we should hack acpi to bits to fix it.

FreeBSD has no format for this and I don't really have time to add multiple 
resource types (which is what ACPI does, and probably what we will need to do 
eventually) to struct resource.  What I have done in the current form is 
added some wrapper functions to acpi_resource.c (so all the magic about what 
rid's match up, etc. is in one file) in the patch below.

> > > Some suggestions...  Make polarity and trigger real resource types
> > > (sys/i386/include/resource.h) and do a bus_set_resource of them in the
> > > resource parsing code.  Then in the alloc code do a bus_get_resource
> > > for them and then call BUS_CONFIG_INTR.  Additionally, instead of doing
> > > the deferred BUS_CONFIG_INTR in the alloc code, it should actually be
> > > done in the MD code for bus_setup_intr().  This seems cleaner since
> > > allocating an irq resource shouldn't poke the hw until
> > > bus_setup_intr().
> >
> > *sigh*  Trigger and polarity are not resources, they are a property of
> > the IRQ resource perhaps.  Unfortunately, our rman(9) interface doesn't
> > support type-specific resource attributes and I'm really not up for
> > chainsawing rman(9) enough to get that into place.  Getting this bug
> > fixed is holding up a lot of other work.
>
> Yes, I agree they are properties of the irq resource.  I'm not asking you
> to go the full route of implementing sub-types in rman.
>
> The simplest and backwards-compatible way to fix this is to add a MD
> SYS_RES_IRQ_CFG resource and set that in the parse routine.  Then, in the
> implementation of bus_setup_intr(), look for that resource and use it for
> the intr configuration.  The only deficiency here is that it creates a
> "top-level" resource type instead of a sub-type, but since there are only
> 6 resource types in i386/include/resource.h right now, this is hardly a
> huge deviation.  With this change, bus_config_intr() can go away (or be a
> no-op for backwards API compat).
>
> This seems the simplest and cleanest approach.

No, I don't think this is clean. Note that ia64 needs bus_config_intr() too.  
In fact, that's why it was added in the first place!

--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi.c	2004/05/06 01:05:39
+++ //depot/user/jhb/acpipci/dev/acpica/acpi.c	2004/06/01 14:05:57
@@ -855,9 +855,21 @@
 {
     struct acpi_device *ad = device_get_ivars(child);
     struct resource_list *rl = &ad->ad_rl;
+    struct resource *res;
+    ACPI_RESOURCE ares;
 
-    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:
+	    if (ACPI_FAILURE(acpi_lookup_irq_resource(dev, *rid, res, &ares)))
+		    break;
+	    acpi_config_intr(dev, &ares);
+	    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/06/01 14:05: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,8 @@
     interrupt = Interrupts[0];
 
 out:
+    if (PCI_INTERRUPT_VALID(interrupt) && crsres != NULL)
+	acpi_config_intr(dev, crsres);
     if (crsbuf.Pointer != NULL)
 	AcpiOsFree(crsbuf.Pointer);
     if (prsbuf.Pointer != NULL)
@@ -393,6 +398,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/06/01 14:05:57
@@ -44,6 +44,88 @@
 #define _COMPONENT	ACPI_BUS
 ACPI_MODULE_NAME("RESOURCE")
 
+ACPI_STATUS
+acpi_lookup_irq_resource(device_t dev, int rid, struct resource *res,
+    ACPI_RESOURCE *acpi_res)
+{
+    ACPI_BUFFER buf;
+    ACPI_STATUS status;
+    ACPI_RESOURCE *ares;
+    char *curr, *last;
+    int i, found;
+
+    buf.Length = ACPI_ALLOCATE_BUFFER;
+    status = AcpiGetCurrentResources(acpi_get_handle(dev), &buf);    
+    if (ACPI_FAILURE(status))
+	    break;
+    i = 0;
+    found = 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_res = *ares;
+		    found++;
+		    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_res = *ares;
+		    found++;
+		    break;
+	    }
+    }
+    AcpiOsFree(buf.Pointer);
+    if (found == 0)
+	    return (AE_NOT_FOUND);
+    return (AE_OK);
+}
+
+void
+acpi_config_intr(device_t dev, ACPI_RESOURCE *res)
+{
+    u_int irq;
+    int pol, trig;
+
+    switch (res->Id) {
+    case ACPI_RSTYPE_IRQ:
+	irq = res->Data.Irq.Interrupts[0];
+	trig = res->Data.Irq.EdgeLevel;
+	pol = res->Data.Irq.ActiveHighLow;
+	break;
+    case ACPI_RSTYPE_EXT_IRQ:
+	irq = res->Data.ExtendedIrq.Interrupts[0];
+	trig = res->Data.ExtendedIrq.EdgeLevel;
+	pol = res->Data.ExtendedIrq.ActiveHighLow;
+	break;
+    default:
+	panic("%s: bad resource type %u", __func__, res->Id);
+    }
+    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);	
+}
+
 /*
  * Fetch a device's resources and associate them with the device.
  *
@@ -495,9 +577,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
--- //depot/vendor/freebsd/src/sys/dev/acpica/acpivar.h	2004/05/06 01:05:39
+++ //depot/user/jhb/acpipci/dev/acpica/acpivar.h	2004/06/01 14:05:57
@@ -283,6 +283,11 @@
 extern ACPI_STATUS	acpi_parse_resources(device_t dev, ACPI_HANDLE handle,
 			    struct acpi_parse_resource_set *set, void *arg);
 
+ACPI_STATUS	acpi_lookup_irq_resource(device_t dev, int rid, struct resource 
*res,
+    ACPI_RESOURCE *acpi_res);
+void		acpi_config_intr(device_t dev, ACPI_RESOURCE *res);
+
+
 /* ACPI event handling */
 extern UINT32	acpi_event_power_button_sleep(void *context);
 extern UINT32	acpi_event_power_button_wake(void *context);

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


More information about the freebsd-acpi mailing list