summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2004-08-20 16:52:44 +0000
committernjl <njl@FreeBSD.org>2004-08-20 16:52:44 +0000
commit45ab45f5d121b3ce80de4d470e56268c5130388e (patch)
tree9f3799b5122e94f9b33561c10d1551f5f5863719 /sys/dev/acpica
parent15ee0f253b7dc88cd2f9879c4a473105d778a670 (diff)
downloadFreeBSD-src-45ab45f5d121b3ce80de4d470e56268c5130388e.zip
FreeBSD-src-45ab45f5d121b3ce80de4d470e56268c5130388e.tar.gz
Correctly handle BIOS resources that are duplicated (!). There are many
systems that have overlapping regions specified in their sysresource objects. This patch fixes ATA DMA and acpi_timer allocation for such sysctems. It should eventually be moved to resource_list_add() if it is a valid generalized approach. The minimal approach for 5.3 is: "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." Tested by: Radek Kozlowski <radek_at_raadradd.com> Discussed with: imp MFC after: 4 days
Diffstat (limited to 'sys/dev/acpica')
-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