From owner-p4-projects@FreeBSD.ORG Thu Jun 13 12:15:38 2013 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 82F9A9F9; Thu, 13 Jun 2013 12:15:38 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 425919F7 for ; Thu, 13 Jun 2013 12:15:38 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from skunkworks.freebsd.org (skunkworks6.freebsd.org [IPv6:2001:1900:2254:2068::682:0]) by mx1.freebsd.org (Postfix) with ESMTP id 2205919CD for ; Thu, 13 Jun 2013 12:15:38 +0000 (UTC) Received: from skunkworks.freebsd.org ([127.0.1.74]) by skunkworks.freebsd.org (8.14.7/8.14.7) with ESMTP id r5DCFcqp011353 for ; Thu, 13 Jun 2013 12:15:38 GMT (envelope-from jhb@freebsd.org) Received: (from perforce@localhost) by skunkworks.freebsd.org (8.14.7/8.14.6/Submit) id r5DCFbj2011350 for perforce@freebsd.org; Thu, 13 Jun 2013 12:15:37 GMT (envelope-from jhb@freebsd.org) Date: Thu, 13 Jun 2013 12:15:37 GMT Message-Id: <201306131215.r5DCFbj2011350@skunkworks.freebsd.org> X-Authentication-Warning: skunkworks.freebsd.org: perforce set sender to jhb@freebsd.org using -f From: John Baldwin Subject: PERFORCE change 229658 for review To: Perforce Change Reviews Precedence: bulk X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.14 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 13 Jun 2013 12:15:38 -0000 http://p4web.freebsd.org/@@229658?ac=10 Change 229658 by jhb@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)