summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/acpi_resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/acpica/acpi_resource.c')
-rw-r--r--sys/dev/acpica/acpi_resource.c53
1 files changed, 49 insertions, 4 deletions
diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
index 669e693..51c30e5 100644
--- a/sys/dev/acpica/acpi_resource.c
+++ b/sys/dev/acpica/acpi_resource.c
@@ -504,6 +504,51 @@ struct acpi_res_context {
void *ar_parent;
};
+/*
+ * Add a resource to the device's resource list. We define our own function
+ * for this since bus_set_resource() doesn't handle duplicates of any kind.
+ *
+ * XXX This should be merged into resource_list_add() eventually.
+ */
+static int
+acpi_reslist_add(device_t dev, int type, int rid, u_long start, u_long count)
+{
+ struct resource_list_entry *rle;
+ struct resource_list *rl;
+ u_long end;
+
+ end = start + count - 1;
+ rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
+
+ /*
+ * Loop through all current resources to see if the new one overlaps
+ * any existing ones. If so, the old one always takes precedence and
+ * the new one is adjusted (or rejected). We check for three cases:
+ *
+ * 1. Tail of new resource overlaps head of old resource: truncate the
+ * new resource so it is contiguous with the start of the old.
+ * 2. New resource wholly contained within the old resource: error.
+ * 3. Head of new resource overlaps tail of old resource: truncate the
+ * new resource so it is contiguous, following the old.
+ */
+ SLIST_FOREACH(rle, rl, link) {
+ if (rle->type == type) {
+ if (start < rle->start && end >= rle->start) {
+ count = rle->start - start;
+ break;
+ } else if (start >= rle->start && start <= rle->end) {
+ if (end > rle->end) {
+ start = rle->end + 1;
+ count = end - rle->end + 1;
+ break;
+ } else
+ return (EEXIST);
+ }
+ }
+ }
+ return (bus_set_resource(dev, type, rid, start, count));
+}
+
static void
acpi_res_set_init(device_t dev, void *arg, void **context)
{
@@ -534,7 +579,7 @@ acpi_res_set_ioport(device_t dev, void *context, u_int32_t base,
if (cp == NULL)
return;
- bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
+ acpi_reslist_add(dev, SYS_RES_IOPORT, cp->ar_nio++, base, length);
}
static void
@@ -557,7 +602,7 @@ acpi_res_set_memory(device_t dev, void *context, u_int32_t base,
if (cp == NULL)
return;
- bus_set_resource(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
+ acpi_reslist_add(dev, SYS_RES_MEMORY, cp->ar_nmem++, base, length);
}
static void
@@ -584,7 +629,7 @@ acpi_res_set_irq(device_t dev, void *context, u_int32_t *irq, int count,
if (count != 1)
return;
- bus_set_resource(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
+ acpi_reslist_add(dev, SYS_RES_IRQ, cp->ar_nirq++, *irq, 1);
}
static void
@@ -599,7 +644,7 @@ acpi_res_set_drq(device_t dev, void *context, u_int32_t *drq, int count)
if (count != 1)
return;
- bus_set_resource(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
+ acpi_reslist_add(dev, SYS_RES_DRQ, cp->ar_ndrq++, *drq, 1);
}
static void
OpenPOWER on IntegriCloud