From owner-acpi-jp@jp.FreeBSD.org Wed Mar 31 15:37:10 2004
Received: (from daemon@localhost)
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) id i2V6bAN19216;
	Wed, 31 Mar 2004 15:37:10 +0900 (JST)
	(envelope-from owner-acpi-jp@jp.FreeBSD.org)
Received: from root.org (root.org [67.118.192.226])
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) with SMTP/inet id i2V6b8d19211
	for <acpi-jp@jp.FreeBSD.org>; Wed, 31 Mar 2004 15:37:08 +0900 (JST)
	(envelope-from nate@root.org)
Received: (qmail 85308 invoked by uid 1000); 31 Mar 2004 06:37:03 -0000
From: Nate Lawson <nate@root.org>
To: "M. Warner Losh" <imp@bsdimp.com>
cc: acpi-jp@jp.FreeBSD.org
In-Reply-To: <20040330.161234.88818967.imp@bsdimp.com>
Message-ID: <20040330223018.S85289@root.org>
References: <20040330.134534.82839532.imp@bsdimp.com> <20040330.145814.04787623.imp@bsdimp.com>
 <20040330144040.R83277@root.org> <20040330.161234.88818967.imp@bsdimp.com>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Reply-To: acpi-jp@jp.FreeBSD.org
Precedence: list
Date: Tue, 30 Mar 2004 22:37:03 -0800
X-Sequence: acpi-jp 3177
Subject: [acpi-jp 3177] Re: hot after resume
Sender: owner-acpi-jp@jp.FreeBSD.org
X-Originator: nate@root.org
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+040307

On Tue, 30 Mar 2004, M. Warner Losh wrote:
> In message: <20040330144040.R83277@root.org>
>             Nate Lawson <nate@root.org> writes:
> : If you can give me some guidance on the changes I need to make for acpi
> : rman, you can just copy the approach I took.  There are sticky problems
> : that show up in implementing it that indicate no one has worked on actual
> : child rman pools that map a subset of the space (not 0-inf as nexus does).
> : For instance, acpi gets a resource from nexus with BUS_ALLOC_RESOURCE and
> : adds it to the local rman (rman_manage_region), but it then needs to be
> : partially released before doing the rman_reserve_resource, otherwise it's
> : allocated to both acpi and the child and you get a panic.  There's no
> : current way to tell nexus that acpi owns a region but it's not currently
> : allocated as a resource.  We probably need a BUS_MANAGE_REGION to pull a
> : region out of the parent without allocating a resource for it.  Or there
> : needs to be a way to take a resource received via BUS_ALLOC_RESOURCE and
> : free the resource data while leaving the region reserved on the parent.
>
> Yes there is a way.  You allocate it.  But you don't activate the
> resource.  That what the pci patches that I post do: it allocates the
> resource and has it owned by the pci bus.  When the driver wants it,
> it transfers ownership to the driver.  Then activation happens
> normally.  On release, the ownership is returned to the bus (that's
> the part that isn't happening at the moment).

Here's a cut of what I have so far.  As we parse system resource objects,
we call acpi_res_set_new().  It reserves resources for ACPI.  Note that we
only care about memory and IO port resources since that's all you get from
PNP0C01 and PNP0C02.  IRQs, etc. go up to the parent (nexus).

This is not working code but I just want to see if I have the right
approach.  Using both rman* and resource_list* together is confusing.  For
one, I leak the rv in acpi_alloc_resource since I'm unsure where to store
it (must be rl since there's no place to put it in rman).

-Nate

Index: acpi.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpica/acpi.c,v
retrieving revision 1.128
diff -u -r1.128 acpi.c
--- acpi.c	19 Mar 2004 07:05:01 -0000	1.128
+++ acpi.c	31 Mar 2004 05:31:00 -0000
@@ -86,6 +87,8 @@
 struct mtx	acpi_mutex;
 #endif

+static struct rman port_rman, mem_rman;
+
 struct acpi_quirks {
     char	*OemId;
     uint32_t	OemRevision;
@@ -364,6 +367,17 @@
 	error = 0;
     }
     ACPI_UNLOCK;
+
+    /* Initialize resource manager. */
+    port_rman.rm_type = RMAN_ARRAY;
+    port_rman.rm_descr = "ACPI I/O ports";
+    if (rman_init(&port_rman) != 0)
+	panic("rman_init ports");
+    mem_rman.rm_type = RMAN_ARRAY;
+    mem_rman.rm_descr = "ACPI Memory";
+    if (rman_init(&mem_rman) != 0)
+	panic("mem_init ports");
+
     return_VALUE(error);
 }

@@ -826,23 +840,61 @@
     return (t);
 }

+static struct rman *
+get_rman(int type)
+{
+    switch (type) {
+    case SYS_RES_IOPORT:
+	return (&port_rman);
+    case SYS_RES_MEMORY:
+	return (&mem_rman);
+    default:
+	printf("res: some other type requested\n");
+	return (NULL);
+    }
+}
+
+int
+acpi_set_res_new(device_t bus, device_t child, int type, int rid,
+		 u_long start, u_long count)
+{
+    struct acpi_device		*ad = device_get_ivars(child);
+    struct resource_list	*rl = &ad->ad_rl;
+    struct rman *rm;
+    struct resource *rv;
+    u_long start, end;
+
+    end = start + count - 1;
+    rm = get_rman(type);
+    if (rm != NULL) {
+	rv = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
+	    start, end, count, 0);
+	if (rv == NULL)
+	    panic("res: can't get from parent");
+	rman_manage_region(rm, start, end);
+    }
+    resource_list_add(rl, type, rid, start, end, count);
+
+    return (0);
+}
+
 /*
  * Handle child resource allocation/removal
  */
 static int
-acpi_set_resource(device_t dev, device_t child, int type, int rid,
+acpi_set_resource(device_t bus, device_t child, int type, int rid,
 		  u_long start, u_long count)
 {
     struct acpi_device		*ad = device_get_ivars(child);
     struct resource_list	*rl = &ad->ad_rl;

-    resource_list_add(rl, type, rid, start, start + count -1, count);
+    resource_list_add(rl, type, rid, start, start + count - 1, count);

-    return(0);
+    return (0);
 }

 static int
-acpi_get_resource(device_t dev, device_t child, int type, int rid,
+acpi_get_resource(device_t bus, device_t child, int type, int rid,
 		  u_long *startp, u_long *countp)
 {
     struct acpi_device		*ad = device_get_ivars(child);
@@ -867,18 +919,82 @@
 {
     struct acpi_device *ad = device_get_ivars(child);
     struct resource_list *rl = &ad->ad_rl;
+    struct resource_list_entry *rle;
+    struct resource *rv;
+    struct rman *rm;
+    int needactivate;
+
+    needactivate = flags & RF_ACTIVE;
+    flags &= ~RF_ACTIVE;
+
+    /*
+     * If the user requested the default range for a given RID and we know
+     * about this resource, use its start/count values.  If we don't know
+     * about it, see if our parent does.
+     */
+    printf("* begin alloc %d start %ld end %ld\n", type, start, end);
+    rm = get_rman(type);
+    if (start == 0ul && end == ~0ul && count == 1) {
+	rle = resource_list_find(rl, type, *rid);
+	if (rle != NULL) {
+	    start = rle->start;
+	    end = rle->end;
+	    count = rle->count;
+	    printf("* from local %d start %ld end %ld\n", type, start, end);
+	} else {
+	    /* Try to get a resource from the parent. */
+	    rv = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
+			start, end, count, flags);
+	    if (rv == NULL)
+		return (NULL);
+	    if (rm != NULL) {
+		start = rman_get_start(rv);
+		end = rman_get_end(rv);
+		rman_manage_region(rm, start, end);
+	    }
+	    printf("* from parent %d start %ld end %ld\n", type,
+		rman_get_start(rv), rman_get_end(rv));
+	}
+    }

-    return (resource_list_alloc(rl, bus, child, type, rid, start, end, count,
-	    flags));
+if (rm != NULL) {
+    rv = rman_reserve_resource(rm, start, end, count, flags, child);
+    if (rv == NULL) {
+	printf("resource not in rman pool?\n");
+	return (NULL);
+    }
+
+    if (type == SYS_RES_MEMORY) {
+	rman_set_bustag(rv, I386_BUS_SPACE_MEM);
+    } else if (type == SYS_RES_IOPORT) {
+	rman_set_bustag(rv, I386_BUS_SPACE_IO);
+	rman_set_bushandle(rv, rv->r_start);
+    }
+}
+
+    if (needactivate) {
+	if (bus_activate_resource(bus, child, type, *rid, rv) != 0) {
+	    rman_release_resource(rv);
+	    return (NULL);
+	}
+    }
+
+    return (rv);
 }

 static int
-acpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r)
+acpi_release_resource(device_t bus, device_t child, int type, int rid,
+		      struct resource *rv)
 {
-    struct acpi_device *ad = device_get_ivars(child);
-    struct resource_list *rl = &ad->ad_rl;
+    int error;
+
+    if (rman_get_flags(rv) & RF_ACTIVE) {
+	error = bus_deactivate_resource(bus, child, type, rid, rv);
+	if (error)
+	    return (error);
+    }

-    return (resource_list_release(rl, bus, child, type, rid, r));
+    return (rman_release_resource(rv));
 }

 /* Allocate an IO port or memory resource, given its GAS. */
@@ -906,6 +1022,21 @@
     return (bus_alloc_resource_any(dev, type, rid, RF_ACTIVE));
 }

+static int
+acpi_resource_probe()
+{
+    if (acpi_MatchHid(child, "PNP0C01"))
+	rm = mem_rman;
+    else if (acpi_MatchHid(child, "PNP0C02"))
+	rm = port_rman;
+    else
+	return;
+
+    acpi_parse_resources(bus, acpi_get_handle(bus), &acpi_res_parse_set);
+    /* XXX doesn't check for duplicate adds */
+    rman_manage_region(rm, start, count);
+}
+
 /*
  * Handle ISA-like devices probing for a PnP ID to match.
  */
@@ -1058,6 +1189,16 @@
     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
     bus_generic_probe(bus);

+    /* Pass 1: sysresource objects */
+    if (!acpi_disabled("sysresource")) {
+	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "sysresource scan\n"));
+	status = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent);
+	if (ACPI_SUCCESS(status)) {
+	    AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, acpi_resource_probe,
+			      bus, NULL);
+	}
+    }
+
     /*
      * Scan the namespace and insert placeholders for all the devices that
      * we find.
