Annotation of sys/arch/sgi/pci/macepcimap.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: macepcimap.c,v 1.3 2004/09/09 22:11:39 pefo Exp $ */
! 2: /* $NetBSD: pci_mace.c,v 1.2 2004/01/19 10:28:28 sekiya Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2001,2003 Christopher Sekiya
! 6: * Copyright (c) 2000 Soren S. Jorvang
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed for the
! 20: * NetBSD Project. See http://www.NetBSD.org/ for
! 21: * information about NetBSD.
! 22: * 4. The name of the author may not be used to endorse or promote products
! 23: * derived from this software without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 27: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 28: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 29: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 30: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 31: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 32: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 33: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 34: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 35: */
! 36:
! 37: #include <sys/param.h>
! 38: #include <sys/device.h>
! 39: #include <sys/systm.h>
! 40:
! 41: #include <machine/cpu.h>
! 42: #include <machine/autoconf.h>
! 43: #include <machine/vmparam.h>
! 44: #include <machine/bus.h>
! 45:
! 46: #include <dev/pci/pcivar.h>
! 47: #include <dev/pci/pcireg.h>
! 48: #include <dev/pci/pcidevs.h>
! 49:
! 50:
! 51: void pciaddr_remap(pci_chipset_tag_t);
! 52: void pciaddr_resource_manage(pci_chipset_tag_t, pcitag_t, void *);
! 53: bus_addr_t pciaddr_ioaddr(u_int32_t);
! 54: int pciaddr_do_resource_allocate(pci_chipset_tag_t, pcitag_t, int, void *,
! 55: int, bus_addr_t *, bus_size_t);
! 56: void pciaddr_print_devid(pci_chipset_tag_t, pcitag_t);
! 57:
! 58:
! 59: #define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
! 60: #define MEG_ALIGN(x) (((x) + 0x100000 - 1) & ~(0x100000 - 1))
! 61:
! 62:
! 63: unsigned int ioaddr_base = 0x1000;
! 64: unsigned int memaddr_base = 0x80100000;
! 65:
! 66: #ifdef DEBUG
! 67: int pcibiosverbose = 1;
! 68: #endif
! 69:
! 70:
! 71: void
! 72: pciaddr_remap(pci_chipset_tag_t pc)
! 73: {
! 74: pcitag_t devtag;
! 75: int device;
! 76:
! 77: /* Must fix up all PCI devices, ahc_pci expects proper i/o mapping */
! 78: for (device = 1; device < 4; device++) {
! 79: const struct pci_quirkdata *qd;
! 80: int function, nfuncs;
! 81: pcireg_t bhlcr, id;
! 82:
! 83: devtag = pci_make_tag(pc, 0, device, 0);
! 84: id = pci_conf_read(pc, devtag, PCI_ID_REG);
! 85:
! 86: /* Invalid vendor ID value? */
! 87: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
! 88: continue;
! 89: /* XXX Not invalid, but we've done this ~forever. */
! 90: if (PCI_VENDOR(id) == 0)
! 91: continue;
! 92:
! 93: qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id));
! 94: bhlcr = pci_conf_read(pc, devtag, PCI_BHLC_REG);
! 95:
! 96: if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
! 97: (qd != NULL &&
! 98: (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
! 99: nfuncs = 8;
! 100: else
! 101: nfuncs = 1;
! 102:
! 103: for (function = 0; function < nfuncs; function++) {
! 104: devtag = pci_make_tag(pc, 0, device, function);
! 105: id = pci_conf_read(pc, devtag, PCI_ID_REG);
! 106:
! 107: /* Invalid vendor ID value? */
! 108: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
! 109: continue;
! 110: /* Not invalid, but we've done this ~forever */
! 111: if (PCI_VENDOR(id) == 0)
! 112: continue;
! 113:
! 114: pciaddr_resource_manage(pc, devtag, NULL);
! 115: }
! 116: }
! 117: }
! 118:
! 119:
! 120: void
! 121: pciaddr_resource_manage(pc, tag, ctx)
! 122: pci_chipset_tag_t pc;
! 123: pcitag_t tag;
! 124: void *ctx;
! 125: {
! 126: pcireg_t val, mask;
! 127: bus_addr_t addr;
! 128: bus_size_t size;
! 129: int error, mapreg, type, reg_start, reg_end, width;
! 130:
! 131: val = pci_conf_read(pc, tag, PCI_BHLC_REG);
! 132: switch (PCI_HDRTYPE_TYPE(val)) {
! 133: default:
! 134: printf("WARNING: unknown PCI device header.");
! 135: return;
! 136: case 0:
! 137: reg_start = PCI_MAPREG_START;
! 138: reg_end = PCI_MAPREG_END;
! 139: break;
! 140: case 1: /* PCI-PCI bridge */
! 141: reg_start = PCI_MAPREG_START;
! 142: reg_end = PCI_MAPREG_PPB_END;
! 143: break;
! 144: case 2: /* PCI-CardBus bridge */
! 145: reg_start = PCI_MAPREG_START;
! 146: reg_end = PCI_MAPREG_PCB_END;
! 147: break;
! 148: }
! 149: error = 0;
! 150:
! 151: for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
! 152: /* inquire PCI device bus space requirement */
! 153: val = pci_conf_read(pc, tag, mapreg);
! 154: pci_conf_write(pc, tag, mapreg, ~0);
! 155:
! 156: mask = pci_conf_read(pc, tag, mapreg);
! 157: pci_conf_write(pc, tag, mapreg, val);
! 158:
! 159: type = PCI_MAPREG_TYPE(val);
! 160: width = 4;
! 161:
! 162: if (type == PCI_MAPREG_TYPE_MEM) {
! 163: size = PCI_MAPREG_MEM_SIZE(mask);
! 164:
! 165: /*
! 166: * XXXrkb: for MEM64 BARs, to be totally kosher
! 167: * about the requested size, need to read mask
! 168: * from top 32bits of BAR and stir that into the
! 169: * size calculation, like so:
! 170: *
! 171: * case PCI_MAPREG_MEM_TYPE_64BIT:
! 172: * bar64 = pci_conf_read(pb->pc, tag, br + 4);
! 173: * pci_conf_write(pb->pc, tag, br + 4, 0xffffffff);
! 174: * mask64 = pci_conf_read(pb->pc, tag, br + 4);
! 175: * pci_conf_write(pb->pc, tag, br + 4, bar64);
! 176: * size = (u_int64_t) PCI_MAPREG_MEM64_SIZE(
! 177: * (((u_int64_t) mask64) << 32) | mask);
! 178: * width = 8;
! 179: *
! 180: * Fortunately, anything with all-zeros mask in the
! 181: * lower 32-bits will have size no less than 1 << 32,
! 182: * which we're not prepared to deal with, so I don't
! 183: * feel bad punting on it...
! 184: */
! 185: if (PCI_MAPREG_MEM_TYPE(val) ==
! 186: PCI_MAPREG_MEM_TYPE_64BIT) {
! 187: /*
! 188: * XXX We could examine the upper 32 bits
! 189: * XXX of the BAR here, but we are totally
! 190: * XXX unprepared to handle a non-zero value,
! 191: * XXX either here or anywhere else in the
! 192: * XXX sgimips code (not sure about MI code).
! 193: * XXX
! 194: * XXX So just arrange to skip the top 32
! 195: * XXX bits of the BAR and zero then out
! 196: * XXX if the BAR is in use.
! 197: */
! 198: width = 8;
! 199:
! 200: if (size != 0)
! 201: pci_conf_write(pc, tag,
! 202: mapreg + 4, 0);
! 203: }
! 204: } else {
! 205: /*
! 206: * Upper 16 bits must be one. Devices may hardwire
! 207: * them to zero, though, per PCI 2.2, 6.2.5.1, p 203.
! 208: */
! 209: mask |= 0xffff0000;
! 210: size = PCI_MAPREG_IO_SIZE(mask);
! 211: }
! 212:
! 213: if (size == 0) /* unused register */
! 214: continue;
! 215:
! 216: addr = pciaddr_ioaddr(val);
! 217:
! 218: /* reservation/allocation phase */
! 219: error += pciaddr_do_resource_allocate(pc, tag, mapreg,
! 220: ctx, type, &addr, size);
! 221:
! 222: }
! 223:
! 224: /* enable/disable PCI device */
! 225: val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
! 226:
! 227: if (error == 0)
! 228: val |= (PCI_COMMAND_IO_ENABLE |
! 229: PCI_COMMAND_MEM_ENABLE |
! 230: PCI_COMMAND_MASTER_ENABLE |
! 231: PCI_COMMAND_SPECIAL_ENABLE |
! 232: PCI_COMMAND_INVALIDATE_ENABLE |
! 233: PCI_COMMAND_PARITY_ENABLE);
! 234: else
! 235: val &= ~(PCI_COMMAND_IO_ENABLE |
! 236: PCI_COMMAND_MEM_ENABLE |
! 237: PCI_COMMAND_MASTER_ENABLE);
! 238:
! 239: pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val);
! 240:
! 241: }
! 242:
! 243: bus_addr_t
! 244: pciaddr_ioaddr(val)
! 245: u_int32_t val;
! 246: {
! 247:
! 248: return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) ?
! 249: PCI_MAPREG_MEM_ADDR(val) : PCI_MAPREG_IO_ADDR(val));
! 250: }
! 251:
! 252: int
! 253: pciaddr_do_resource_allocate(pc, tag, mapreg, ctx, type, addr, size)
! 254: pci_chipset_tag_t pc;
! 255: pcitag_t tag;
! 256: void *ctx;
! 257: int mapreg, type;
! 258: bus_addr_t *addr;
! 259: bus_size_t size;
! 260: {
! 261:
! 262: switch (type) {
! 263: case PCI_MAPREG_TYPE_IO:
! 264: *addr = ioaddr_base;
! 265: ioaddr_base += PAGE_ALIGN(size);
! 266: break;
! 267:
! 268: case PCI_MAPREG_TYPE_MEM:
! 269: *addr = memaddr_base;
! 270: memaddr_base += MEG_ALIGN(size);
! 271: break;
! 272:
! 273: default:
! 274: printf("attempt to remap unknown region (addr 0x%lx, "
! 275: "size 0x%lx, type %d)\n", *addr, size, type);
! 276: return 0;
! 277: }
! 278:
! 279:
! 280: /* write new address to PCI device configuration header */
! 281: pci_conf_write(pc, tag, mapreg, *addr);
! 282:
! 283: /* check */
! 284: #ifdef DEBUG
! 285: if (!pcibiosverbose) {
! 286: printf("pci_addr_fixup: ");
! 287: pciaddr_print_devid(pc, tag);
! 288: }
! 289: #endif
! 290: if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) {
! 291: pci_conf_write(pc, tag, mapreg, 0); /* clear */
! 292: printf("fixup failed. (new address=%#x)\n", (unsigned)*addr);
! 293: return (1);
! 294: }
! 295: #ifdef DEBUG
! 296: if (!pcibiosverbose)
! 297: printf("new address 0x%08x (size 0x%x)\n", (unsigned)*addr,
! 298: (unsigned)size);
! 299: #endif
! 300:
! 301: return (0);
! 302: }
! 303:
! 304: void
! 305: pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
! 306: {
! 307: int bus, device, function;
! 308: pcireg_t id;
! 309:
! 310: id = pci_conf_read(pc, tag, PCI_ID_REG);
! 311: pci_decompose_tag(pc, tag, &bus, &device, &function);
! 312: printf("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function,
! 313: PCI_VENDOR(id), PCI_PRODUCT(id));
! 314: }
! 315:
CVSweb