diff options
-rw-r--r-- | sys/amd64/amd64/nexus.c | 14 | ||||
-rw-r--r-- | sys/i386/i386/nexus.c | 14 | ||||
-rw-r--r-- | sys/kern/subr_rman.c | 44 |
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); |