summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/nexus.c14
-rw-r--r--sys/i386/i386/nexus.c14
-rw-r--r--sys/kern/subr_rman.c44
3 files changed, 47 insertions, 25 deletions
diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c
index f143d5e..478106c 100644
--- a/sys/amd64/amd64/nexus.c
+++ b/sys/amd64/amd64/nexus.c
@@ -140,7 +140,7 @@ DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
static int
nexus_probe(device_t dev)
{
- int irq, last;
+ int irq;
device_quiet(dev); /* suppress attach message for neatness */
@@ -173,18 +173,10 @@ nexus_probe(device_t dev)
* We search for regions of existing IRQs and add those to the IRQ
* resource manager.
*/
- last = -1;
for (irq = 0; irq < NUM_IO_INTS; irq++)
- if (intr_lookup_source(irq) != NULL) {
- if (last == -1)
- last = irq;
- } else if (last != -1) {
- if (rman_manage_region(&irq_rman, last, irq - 1) != 0)
+ if (intr_lookup_source(irq) != NULL)
+ if (rman_manage_region(&irq_rman, irq, irq) != 0)
panic("nexus_probe irq_rman add");
- last = -1;
- }
- if (last != -1 && rman_manage_region(&irq_rman, last, irq - 1) != 0)
- panic("nexus_probe irq_rman add");
/*
* ISA DMA on PCI systems is implemented in the ISA part of each
diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c
index 9def53d..6e1e281 100644
--- a/sys/i386/i386/nexus.c
+++ b/sys/i386/i386/nexus.c
@@ -144,7 +144,7 @@ DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
static int
nexus_probe(device_t dev)
{
- int irq, last;
+ int irq;
device_quiet(dev); /* suppress attach message for neatness */
@@ -177,18 +177,10 @@ nexus_probe(device_t dev)
* We search for regions of existing IRQs and add those to the IRQ
* resource manager.
*/
- last = -1;
for (irq = 0; irq < NUM_IO_INTS; irq++)
- if (intr_lookup_source(irq) != NULL) {
- if (last == -1)
- last = irq;
- } else if (last != -1) {
- if (rman_manage_region(&irq_rman, last, irq - 1) != 0)
+ if (intr_lookup_source(irq) != NULL)
+ if (rman_manage_region(&irq_rman, irq, irq) != 0)
panic("nexus_probe irq_rman add");
- last = -1;
- }
- if (last != -1 && rman_manage_region(&irq_rman, last, irq - 1) != 0)
- panic("nexus_probe irq_rman add");
/*
* ISA DMA on PCI systems is implemented in the ISA part of each
diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c
index c180eba..f59327a 100644
--- a/sys/kern/subr_rman.c
+++ b/sys/kern/subr_rman.c
@@ -155,7 +155,7 @@ rman_init(struct rman *rm)
int
rman_manage_region(struct rman *rm, u_long start, u_long end)
{
- struct resource_i *r, *s;
+ struct resource_i *r, *s, *t;
DPRINTF(("rman_manage_region: <%s> request: start %#lx, end %#lx\n",
rm->rm_descr, start, end));
@@ -167,15 +167,53 @@ rman_manage_region(struct rman *rm, u_long start, u_long end)
r->r_rm = rm;
mtx_lock(rm->rm_mtx);
+
+ /* Skip entries before us. */
for (s = TAILQ_FIRST(&rm->rm_list);
- s && s->r_end < r->r_start;
+ s && s->r_end + 1 < r->r_start;
s = TAILQ_NEXT(s, r_link))
;
+ /* If we ran off the end of the list, insert at the tail. */
if (s == NULL) {
TAILQ_INSERT_TAIL(&rm->rm_list, r, r_link);
} else {
- TAILQ_INSERT_BEFORE(s, r, r_link);
+ /* Check for any overlap with the current region. */
+ if (r->r_start <= s->r_end && r->r_end >= s->r_start)
+ return EBUSY;
+
+ /* Check for any overlap with the next region. */
+ t = TAILQ_NEXT(s, r_link);
+ if (t && r->r_start <= t->r_end && r->r_end >= t->r_start)
+ return EBUSY;
+
+ /*
+ * See if this region can be merged with the next region. If
+ * not, clear the pointer.
+ */
+ if (t && (r->r_end + 1 != t->r_start || t->r_flags != 0))
+ t = NULL;
+
+ /* See if we can merge with the current region. */
+ if (s->r_end + 1 == r->r_start && s->r_flags == 0) {
+ /* Can we merge all 3 regions? */
+ if (t != NULL) {
+ s->r_end = t->r_end;
+ TAILQ_REMOVE(&rm->rm_list, t, r_link);
+ free(r, M_RMAN);
+ free(t, M_RMAN);
+ } else {
+ s->r_end = r->r_end;
+ free(r, M_RMAN);
+ }
+ } else {
+ /* Can we merge with just the next region? */
+ if (t != NULL) {
+ t->r_start = r->r_start;
+ free(r, M_RMAN);
+ } else
+ TAILQ_INSERT_BEFORE(s, r, r_link);
+ }
}
mtx_unlock(rm->rm_mtx);
OpenPOWER on IntegriCloud