Annotation of sys/arch/sh/dev/pci_addr_fixup.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pci_addr_fixup.c,v 1.2 2006/10/19 22:42:53 drahn Exp $ */
! 2: /* $NetBSD: pci_addr_fixup.c,v 1.7 2000/08/03 20:10:45 nathanw Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000 UCHIYAMA Yasushi. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. The name of the author may not be used to endorse or promote products
! 16: * derived from this software without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: #include <sys/param.h>
! 31: #include <sys/systm.h>
! 32: #include <sys/malloc.h>
! 33: #include <sys/kernel.h>
! 34: #include <sys/device.h>
! 35: #include <sys/extent.h>
! 36:
! 37: #include <uvm/uvm_param.h>
! 38: #include <machine/bus.h>
! 39:
! 40: #include <dev/pci/pcireg.h>
! 41: #include <dev/pci/pcivar.h>
! 42: #include <dev/pci/pcidevs.h>
! 43:
! 44: #include <sh/dev/shpcicvar.h>
! 45:
! 46: typedef int (*pciaddr_resource_manage_func_t)(struct shpcic_softc *,
! 47: pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *,
! 48: bus_size_t);
! 49: void pciaddr_resource_manage(struct shpcic_softc *,
! 50: pci_chipset_tag_t, pcitag_t, pciaddr_resource_manage_func_t);
! 51: void pciaddr_resource_reserve(struct shpcic_softc *,
! 52: pci_chipset_tag_t, pcitag_t);
! 53: void pciaddr_resource_reserve_disabled(struct shpcic_softc *,
! 54: pci_chipset_tag_t, pcitag_t);
! 55: int pciaddr_do_resource_reserve(struct shpcic_softc *,
! 56: pci_chipset_tag_t, pcitag_t, int, struct extent *, int,
! 57: bus_addr_t *, bus_size_t);
! 58: int pciaddr_do_resource_reserve_disabled(struct shpcic_softc *,
! 59: pci_chipset_tag_t, pcitag_t, int, struct extent *, int,
! 60: bus_addr_t *, bus_size_t);
! 61: void pciaddr_resource_allocate(struct shpcic_softc *,
! 62: pci_chipset_tag_t, pcitag_t);
! 63: int pciaddr_do_resource_allocate(struct shpcic_softc *,
! 64: pci_chipset_tag_t, pcitag_t, int, struct extent *, int, bus_addr_t *,
! 65: bus_size_t);
! 66: bus_addr_t pciaddr_ioaddr(u_int32_t);
! 67: void pciaddr_print_devid(pci_chipset_tag_t, pcitag_t);
! 68:
! 69: int pciaddr_device_is_agp(pci_chipset_tag_t, pcitag_t);
! 70:
! 71: void pci_device_foreach(struct shpcic_softc *sc, pci_chipset_tag_t pc,
! 72: int maxbus,
! 73: void (*func)(struct shpcic_softc *, pci_chipset_tag_t, pcitag_t));
! 74:
! 75: #define PCIADDR_MEM_START 0x0
! 76: #define PCIADDR_MEM_END 0xffffffff
! 77: #define PCIADDR_PORT_START 0x0
! 78: #define PCIADDR_PORT_END 0xffff
! 79:
! 80: #define PCIBR_VERBOSE 1
! 81: int pcibr_flags = 0;
! 82:
! 83: #define PCIBIOS_PRINTV(x) if (pcibr_flags & PCIBR_VERBOSE) \
! 84: printf x
! 85:
! 86: void
! 87: pci_addr_fixup(void *v, int maxbus)
! 88: {
! 89: struct shpcic_softc *sc = v;
! 90:
! 91: const char *verbose_header =
! 92: "[%s]-----------------------\n"
! 93: " device vendor product\n"
! 94: " register space address size\n"
! 95: "--------------------------------------------\n";
! 96: const char *verbose_footer =
! 97: "--------------------------[%3d devices bogus]\n";
! 98:
! 99: sc->extent_mem = extent_create("PCI I/O memory space",
! 100: sc->sc_membus_space.bus_base,
! 101: sc->sc_membus_space.bus_base + sc->sc_membus_space.bus_size,
! 102: M_DEVBUF, 0, 0, EX_NOWAIT);
! 103: KASSERT(sc->extent_mem);
! 104: sc->extent_port = extent_create("PCI I/O port space",
! 105: sc->sc_iobus_space.bus_base,
! 106: sc->sc_iobus_space.bus_base + sc->sc_iobus_space.bus_size,
! 107: M_DEVBUF, 0, 0, EX_NOWAIT);
! 108: KASSERT(sc->extent_port);
! 109:
! 110: /*
! 111: * 1. check & reserve system BIOS setting.
! 112: */
! 113: PCIBIOS_PRINTV((verbose_header, "System BIOS Setting"));
! 114: pci_device_foreach(sc, &sc->sc_pci_chipset, maxbus,
! 115: pciaddr_resource_reserve);
! 116: pci_device_foreach(sc, &sc->sc_pci_chipset, maxbus,
! 117: pciaddr_resource_reserve_disabled);
! 118: PCIBIOS_PRINTV((verbose_footer, sc->nbogus));
! 119:
! 120: {
! 121: struct extent_region *rp;
! 122: struct extent *ex = sc->extent_mem;
! 123: for (rp = LIST_FIRST(&ex->ex_regions);
! 124: rp; rp = LIST_NEXT(rp, er_link)) {
! 125: }
! 126: }
! 127: {
! 128: struct extent_region *rp;
! 129: struct extent *ex = sc->extent_port;
! 130: for (rp = LIST_FIRST(&ex->ex_regions);
! 131: rp; rp = LIST_NEXT(rp, er_link)) {
! 132: }
! 133: }
! 134:
! 135: /*
! 136: * 4. do fixup
! 137: */
! 138: PCIBIOS_PRINTV((verbose_header, "PCIBIOS fixup stage"));
! 139: sc->nbogus = 0;
! 140: pci_device_foreach(sc, &sc->sc_pci_chipset, maxbus,
! 141: pciaddr_resource_allocate);
! 142: PCIBIOS_PRINTV((verbose_footer, sc->nbogus));
! 143:
! 144: }
! 145:
! 146: void
! 147: pciaddr_resource_reserve(struct shpcic_softc *sc, pci_chipset_tag_t pc,
! 148: pcitag_t tag)
! 149: {
! 150: if (pcibr_flags & PCIBR_VERBOSE)
! 151: pciaddr_print_devid(pc, tag);
! 152: pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_reserve);
! 153: }
! 154: void
! 155: pciaddr_resource_reserve_disabled(struct shpcic_softc *sc,
! 156: pci_chipset_tag_t pc, pcitag_t tag)
! 157: {
! 158: if (pcibr_flags & PCIBR_VERBOSE)
! 159: pciaddr_print_devid(pc, tag);
! 160: pciaddr_resource_manage(sc, pc, tag,
! 161: pciaddr_do_resource_reserve_disabled);
! 162: }
! 163:
! 164:
! 165: void
! 166: pciaddr_resource_allocate(struct shpcic_softc *sc, pci_chipset_tag_t pc,
! 167: pcitag_t tag)
! 168: {
! 169: if (pcibr_flags & PCIBR_VERBOSE)
! 170: pciaddr_print_devid(pc, tag);
! 171: pciaddr_resource_manage(sc, pc, tag, pciaddr_do_resource_allocate);
! 172: }
! 173:
! 174: void
! 175: pciaddr_resource_manage(struct shpcic_softc *sc, pci_chipset_tag_t pc,
! 176: pcitag_t tag, pciaddr_resource_manage_func_t func)
! 177: {
! 178: struct extent *ex;
! 179: pcireg_t val, mask;
! 180: bus_addr_t addr;
! 181: bus_size_t size;
! 182: int error, mapreg, type, reg_start, reg_end, width;
! 183:
! 184: val = pci_conf_read(pc, tag, PCI_BHLC_REG);
! 185: switch (PCI_HDRTYPE_TYPE(val)) {
! 186: default:
! 187: printf("WARNING: unknown PCI device header.\n");
! 188: sc->nbogus++;
! 189: return;
! 190: case 0:
! 191: reg_start = PCI_MAPREG_START;
! 192: reg_end = PCI_MAPREG_END;
! 193: break;
! 194: case 1: /* PCI-PCI bridge */
! 195: reg_start = PCI_MAPREG_START;
! 196: reg_end = PCI_MAPREG_PPB_END;
! 197: break;
! 198: case 2: /* PCI-CardBus bridge */
! 199: reg_start = PCI_MAPREG_START;
! 200: reg_end = PCI_MAPREG_PCB_END;
! 201: break;
! 202: }
! 203: error = 0;
! 204:
! 205: for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
! 206: /* inquire PCI device bus space requirement */
! 207: val = pci_conf_read(pc, tag, mapreg);
! 208: pci_conf_write(pc, tag, mapreg, ~0);
! 209:
! 210: mask = pci_conf_read(pc, tag, mapreg);
! 211: pci_conf_write(pc, tag, mapreg, val);
! 212:
! 213: type = PCI_MAPREG_TYPE(val);
! 214: width = 4;
! 215: if (type == PCI_MAPREG_TYPE_MEM) {
! 216: if (PCI_MAPREG_MEM_TYPE(val) ==
! 217: PCI_MAPREG_MEM_TYPE_64BIT) {
! 218: /* XXX We could examine the upper 32 bits
! 219: * XXX of the BAR here, but we are totally
! 220: * XXX unprepared to handle a non-zero value,
! 221: * XXX either here or anywhere else in
! 222: * XXX i386-land.
! 223: * XXX So just arrange to not look at the
! 224: * XXX upper 32 bits, lest we misinterpret
! 225: * XXX it as a 32-bit BAR set to zero.
! 226: */
! 227: width = 8;
! 228: }
! 229: addr = PCI_MAPREG_MEM_ADDR(val);
! 230: size = PCI_MAPREG_MEM_SIZE(mask);
! 231: ex = sc->extent_mem;
! 232: /* XXX */
! 233: /*
! 234: * sh-IPL allocates a low address for PCI memory
! 235: * on px-eh systems, clobber it so it gets 'remapped'
! 236: */
! 237: if (addr != 0 && addr < sc->sc_membus_space.bus_base) {
! 238: val = 0;
! 239: pci_conf_write(pc, tag, mapreg, val);
! 240: }
! 241: } else {
! 242: /* XXX some devices give 32bit value */
! 243: if (sc->sc_iobus_space.bus_base != PCIADDR_PORT_START) {
! 244: /*
! 245: * if the bus base is not 0 skew all addresses
! 246: */
! 247: val &= PCIADDR_PORT_END;
! 248: val |= sc->sc_iobus_space.bus_base;
! 249: pci_conf_write(pc, tag, mapreg, val);
! 250: }
! 251: addr = PCI_MAPREG_IO_ADDR(val);
! 252: size = PCI_MAPREG_IO_SIZE(mask);
! 253: ex = sc->extent_port;
! 254: }
! 255:
! 256: if (!size) /* unused register */
! 257: continue;
! 258:
! 259: /* reservation/allocation phase */
! 260: error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size);
! 261:
! 262: PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n",
! 263: mapreg, type ? "port" : "mem ",
! 264: (unsigned int)addr, (unsigned int)size));
! 265: }
! 266:
! 267: if (error)
! 268: sc->nbogus++;
! 269:
! 270: PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK"));
! 271: }
! 272:
! 273: int
! 274: pciaddr_do_resource_allocate(struct shpcic_softc *sc, pci_chipset_tag_t pc,
! 275: pcitag_t tag, int mapreg, struct extent *ex, int type, bus_addr_t *addr,
! 276: bus_size_t size)
! 277: {
! 278: bus_addr_t start;
! 279: int error;
! 280:
! 281: if (type == PCI_MAPREG_TYPE_IO) {
! 282: if ((*addr & PCIADDR_PORT_END) != 0)
! 283: return (0);
! 284: } else if (*addr) /* no need to allocate */
! 285: return (0);
! 286:
! 287: /* XXX Don't allocate if device is AGP device to avoid conflict. */
! 288: if (pciaddr_device_is_agp(pc, tag))
! 289: return (0);
! 290:
! 291: start = (type == PCI_MAPREG_TYPE_MEM ? sc->sc_membus_space.bus_base
! 292: : sc->sc_iobus_space.bus_base);
! 293: if (start < ex->ex_start || start + size - 1 >= ex->ex_end) {
! 294: PCIBIOS_PRINTV(("No available resources. fixup failed\n"));
! 295: return (1);
! 296: }
! 297: error = extent_alloc_subregion(ex, start, ex->ex_end, size, size, 0, 0,
! 298: EX_FAST|EX_NOWAIT|EX_MALLOCOK, addr);
! 299: if (error) {
! 300: PCIBIOS_PRINTV(("No available resources. fixup failed\n"));
! 301: return (1);
! 302: }
! 303:
! 304: /* write new address to PCI device configuration header */
! 305: pci_conf_write(pc, tag, mapreg, *addr);
! 306: /* check */
! 307: if (pcibr_flags & PCIBR_VERBOSE) {
! 308: printf("pci_addr_fixup: ");
! 309: pciaddr_print_devid(pc, tag);
! 310: }
! 311:
! 312: if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) {
! 313: pci_conf_write(pc, tag, mapreg, 0); /* clear */
! 314: printf("fixup failed. (new address=%#lx)\n", *addr);
! 315: return (1);
! 316: }
! 317: if (pcibr_flags & PCIBR_VERBOSE)
! 318: printf("new address 0x%08lx\n", *addr);
! 319:
! 320: return (0);
! 321: }
! 322:
! 323: int
! 324: pciaddr_do_resource_reserve(struct shpcic_softc *sc, pci_chipset_tag_t pc,
! 325: pcitag_t tag, int mapreg, struct extent *ex, int type, bus_addr_t *addr,
! 326: bus_size_t size)
! 327: {
! 328: pcireg_t val;
! 329: int error;
! 330:
! 331: if ((type == PCI_MAPREG_TYPE_IO) && ((*addr & PCIADDR_PORT_END) == 0))
! 332: return (0);
! 333: if (*addr == 0)
! 334: return (0);
! 335:
! 336: val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
! 337: if (type == PCI_MAPREG_TYPE_MEM &&
! 338: (val & PCI_COMMAND_MEM_ENABLE) != PCI_COMMAND_MEM_ENABLE)
! 339: return (0);
! 340: if (type == PCI_MAPREG_TYPE_IO &&
! 341: (val & PCI_COMMAND_IO_ENABLE) != PCI_COMMAND_IO_ENABLE)
! 342: return (0);
! 343:
! 344: error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK);
! 345: if (error) {
! 346: PCIBIOS_PRINTV(("Resource conflict.\n"));
! 347: pci_conf_write(pc, tag, mapreg, 0); /* clear */
! 348: return (1);
! 349: }
! 350:
! 351: return (0);
! 352: }
! 353:
! 354: int
! 355: pciaddr_do_resource_reserve_disabled(struct shpcic_softc *sc,
! 356: pci_chipset_tag_t pc, pcitag_t tag, int mapreg, struct extent *ex,
! 357: int type, bus_addr_t *addr, bus_size_t size)
! 358: {
! 359: pcireg_t val;
! 360: int error;
! 361:
! 362: if ((type == PCI_MAPREG_TYPE_IO) && ((*addr & PCIADDR_PORT_END) == 0))
! 363: return (0);
! 364: if (*addr == 0)
! 365: return (0);
! 366:
! 367: val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
! 368: if (type == PCI_MAPREG_TYPE_MEM &&
! 369: (val & PCI_COMMAND_MEM_ENABLE) == PCI_COMMAND_MEM_ENABLE)
! 370: return (0);
! 371: if (type == PCI_MAPREG_TYPE_IO &&
! 372: (val & PCI_COMMAND_IO_ENABLE) == PCI_COMMAND_IO_ENABLE)
! 373: return (0);
! 374:
! 375: error = extent_alloc_region(ex, *addr, size, EX_NOWAIT | EX_MALLOCOK);
! 376: if (error) {
! 377: PCIBIOS_PRINTV(("Resource conflict.\n"));
! 378: pci_conf_write(pc, tag, mapreg, 0); /* clear */
! 379: return (1);
! 380: }
! 381:
! 382: return (0);
! 383: }
! 384:
! 385: bus_addr_t
! 386: pciaddr_ioaddr(u_int32_t val)
! 387: {
! 388: return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM)
! 389: ? PCI_MAPREG_MEM_ADDR(val)
! 390: : (PCI_MAPREG_IO_ADDR(val)));
! 391: }
! 392:
! 393: void
! 394: pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
! 395: {
! 396: int bus, device, function;
! 397: pcireg_t id;
! 398:
! 399: id = pci_conf_read(pc, tag, PCI_ID_REG);
! 400: pci_decompose_tag(pc, tag, &bus, &device, &function);
! 401: printf("%03d:%02d:%d %04x:%04x\n", bus, device, function,
! 402: PCI_VENDOR(id), PCI_PRODUCT(id));
! 403: }
! 404:
! 405: int
! 406: pciaddr_device_is_agp(pci_chipset_tag_t pc, pcitag_t tag)
! 407: {
! 408: pcireg_t class, status, rval;
! 409: int off;
! 410:
! 411: /* Check AGP device. */
! 412: class = pci_conf_read(pc, tag, PCI_CLASS_REG);
! 413: if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
! 414: status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
! 415: if (status & PCI_STATUS_CAPLIST_SUPPORT) {
! 416: rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG);
! 417: for (off = PCI_CAPLIST_PTR(rval);
! 418: off != 0;
! 419: off = PCI_CAPLIST_NEXT(rval) ) {
! 420: rval = pci_conf_read(pc, tag, off);
! 421: if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP)
! 422: return (1);
! 423: }
! 424: }
! 425: }
! 426: return (0);
! 427: }
! 428:
! 429: void
! 430: pci_device_foreach(struct shpcic_softc *sc, pci_chipset_tag_t pc, int maxbus,
! 431: void (*func)(struct shpcic_softc *, pci_chipset_tag_t, pcitag_t))
! 432: {
! 433: const struct pci_quirkdata *qd;
! 434: int bus, device, function, maxdevs, nfuncs;
! 435: pcireg_t id, bhlcr;
! 436: pcitag_t tag;
! 437:
! 438: for (bus = 0; bus <= maxbus; bus++) {
! 439: maxdevs = pci_bus_maxdevs(pc, bus);
! 440: for (device = 0; device < maxdevs; device++) {
! 441: tag = pci_make_tag(pc, bus, device, 0);
! 442: id = pci_conf_read(pc, tag, PCI_ID_REG);
! 443:
! 444: /* Invalid vendor ID value? */
! 445: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
! 446: continue;
! 447: /* XXX Not invalid, but we've done this ~forever. */
! 448: if (PCI_VENDOR(id) == 0)
! 449: continue;
! 450:
! 451: qd = pci_lookup_quirkdata(PCI_VENDOR(id),
! 452: PCI_PRODUCT(id));
! 453:
! 454: bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
! 455: if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
! 456: (qd != NULL &&
! 457: (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
! 458: nfuncs = 8;
! 459: else
! 460: nfuncs = 1;
! 461:
! 462: for (function = 0; function < nfuncs; function++) {
! 463: tag = pci_make_tag(pc, bus, device, function);
! 464: id = pci_conf_read(pc, tag, PCI_ID_REG);
! 465:
! 466: /* Invalid vendor ID value? */
! 467: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
! 468: continue;
! 469: /*
! 470: * XXX Not invalid, but we've done this
! 471: * ~forever.
! 472: */
! 473: if (PCI_VENDOR(id) == 0)
! 474: continue;
! 475: (*func)(sc, pc, tag);
! 476: }
! 477: }
! 478: }
! 479: }
CVSweb