PERFORCE change 229658 for review
John Baldwin
jhb at FreeBSD.org
Thu Jun 13 12:15:38 UTC 2013
http://p4web.freebsd.org/@@229658?ac=10
Change 229658 by jhb at jhb_jhbbsd on 2013/06/13 12:15:31
First cut at ISA enable support. However, this doesn't properly
handle nested bridges. I need to go the whole hog and slice up
the allocations from the parent to make that work properly.
Affected files ...
.. //depot/projects/pci/sys/dev/pci/pci_pci.c#29 edit
Differences ...
==== //depot/projects/pci/sys/dev/pci/pci_pci.c#29 (text+ko) ====
@@ -196,7 +196,94 @@
}
}
+/*
+ * This is used to reject allocations that conflict with an ISA alias
+ * before trying to grow the window. Note that this check overrides
+ * subtractive decode.
+ */
+static int
+pcib_is_isa_range(struct pcib_softc *sc, u_long start, u_long end, u_long count)
+{
+ u_long next_alias;
+
+ if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE))
+ return (0);
+
+ /* Only check fixed ranges for overlap. */
+ if (start + count - 1 != end)
+ return (0);
+
+ /* ISA aliases are only in the lower 64KB of I/O space. */
+ if (start >= 65536)
+ return (0);
+
+ /* Check for overlap with 0x000 - 0x0ff as a special case. */
+ if (start < 0x100)
+ goto alias;
+
+ /*
+ * If the start address is an alias, the range is an alias.
+ * Otherwise, compute the start of the next alias range and
+ * check if it is beyond the end of the candidate range.
+ */
+ if ((start & 0x300) != 0)
+ goto alias;
+ next_start = (start & ~0xfful) | 0x100;
+ if (next_start <= end)
+ goto alias;
+ return (0);
+
+alias:
+ device_printf(sc->dev,
+ "I/O range %#lx-%#lx overlaps with an ISA alias\n", start,
+ end);
+ return (1);
+}
+
static void
+pcib_alloc_isa_ranges(struct pcib_softc *sc, u_long start, u_long end)
+{
+ struct resource *res;
+ u_long next_end;
+
+ if (!(sc->bridgectl & PCIB_BCR_ISA_ENABLE))
+ return (0);
+
+ /* ISA aliases are only in the lower 64KB of I/O space. */
+ if (end > 65535)
+ end = 65535;
+
+ /* XXX */
+ device_printf(sc->dev, "Reserving ISA aliases for %#lx-%#lx\n", start,
+ end);
+ while (start <= end) {
+ /*
+ * Find the first address that aliases to 0x0100 and
+ * reserve the space from that up to the alias with
+ * 0x03ff. As a special case, addresses in the range
+ * 0x000 - 0x0ff should also be reserved since those
+ * are used for various system I/O devices in ISA
+ * systems.
+ */
+ if (start >= 0x100 && (start & 0x300) == 0) {
+ start &= ~0xfful;
+ start |= 0x100;
+ }
+ next_end = MIN(start | 0x3ff, end);
+ //if (bootverbose)
+ device_printf(sc->dev,
+ "Reserving ISA alias %#lx-%#lx\n", start, next_end);
+ res = rman_reserve_resource(&sc->io.rman, start, next_end,
+ next_end - start + 1, 0, sc->dev);
+ if (res == NULL)
+ device_printf(sc->dev,
+ "Failed to reserve ISA alias %#lx-%#lx\n", start,
+ next_end);
+ start = next_end + 1;
+ }
+}
+
+static void
pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type,
int flags, pci_addr_t max_address)
{
@@ -305,6 +392,8 @@
max = 0xffff;
}
pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, max);
+ pcib_alloc_isa_ranges(sc, sc->io.base, sc->io.base +
+ sc->io.limit - 1);
}
/* Read the existing memory window. */
@@ -562,6 +651,7 @@
struct pcib_softc *sc;
struct sysctl_ctx_list *sctx;
struct sysctl_oid *soid;
+ int comma;
sc = device_get_softc(dev);
sc->dev = dev;
@@ -685,10 +775,22 @@
device_printf(dev, " prefetched decode 0x%jx-0x%jx\n",
(uintmax_t)sc->pmembase, (uintmax_t)sc->pmemlimit);
#endif
- else
- device_printf(dev, " no prefetched decode\n");
- if (sc->flags & PCIB_SUBTRACTIVE)
- device_printf(dev, " Subtractively decoded bridge.\n");
+ if (sc->bridgectl & (PCIB_BCR_ISA_ENABLE | PCIB_BCR_VGA_ENABLE) ||
+ sc->flags & PCIB_SUBTRACTIVE) {
+ device_printf(dev, " special decode ");
+ comma = 0;
+ if (sc->bridgectl & PCIB_BCR_ISA_ENABLE) {
+ printf("ISA");
+ comma = 1;
+ }
+ if (sc->bridgectl & PCIB_BCR_VGA_ENABLE) {
+ printf("%sVGA", comma ? ", " : "");
+ comma = 1;
+ }
+ if (sc->flags & PCIB_SUBTRACTIVE)
+ printf("%ssubtractive", comma ? ", " : "");
+ device_printf("\n");
+ }
}
/*
@@ -849,9 +951,15 @@
/*
* Clamp the desired resource range to the maximum address
* this window supports. Reject impossible requests.
+ *
+ * For I/O port requests behind a bridge with the ISA enable
+ * bit set, force large allocations to start above 64k.
*/
if (!w->valid)
return (EINVAL);
+ if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 &&
+ start < 65536)
+ start = 65536;
if (end > w->rman.rm_end)
end = w->rman.rm_end;
if (start + count - 1 > end || start + count < start)
@@ -1011,11 +1119,17 @@
KASSERT(w->limit == rman_get_end(w->res), ("both ends moved"));
error = rman_manage_region(&w->rman, rman_get_start(w->res),
w->base - 1);
+ if (type == SYS_RES_IOPORT)
+ pcib_alloc_isa_ranges(sc, rman_get_start(w->res),
+ w->base - 1);
} else {
KASSERT(w->limit != rman_get_end(w->res),
("neither end moved"));
error = rman_manage_region(&w->rman, w->limit + 1,
rman_get_end(w->res));
+ if (type == SYS_RES_IOPORT)
+ pcib_alloc_isa_ranges(sc, w->limit + 1,
+ rman_get_end(w->res));
}
if (error) {
if (bootverbose)
@@ -1066,7 +1180,8 @@
case SYS_RES_IOPORT:
r = pcib_suballoc_resource(sc, &sc->io, child, type, rid, start,
end, count, flags);
- if (r != NULL || (sc->flags & PCIB_SUBTRACTIVE) != 0)
+ if (r != NULL || ((sc->flags & PCIB_SUBTRACTIVE) != 0 &&
+ !pcib_is_isa_range(sc, start, end, count)))
break;
if (pcib_grow_window(sc, &sc->io, type, start, end, count,
flags) == 0)
More information about the p4-projects
mailing list