int pci_func_configure(struct pci_func *f) { uint32_t bar_width; uint32_t bar; for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += bar_width) { uint32_t oldv = pci_conf_read(f, bar); bar_width = 4; pci_conf_write(f, bar, 0xffffffff); uint32_t rv = pci_conf_read(f, bar); if (rv == 0) continue; int regnum = PCI_MAPREG_NUM(bar); uint32_t base, size; if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) { if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT) bar_width = 8; size = PCI_MAPREG_MEM_SIZE(rv); base = PCI_MAPREG_MEM_ADDR(oldv); if (!base) { /* device is not properly configured, allocate mmio address for it */ base = pci_allocate_memory(size); if (!base) return ENOMEM; oldv = base; } #ifdef SHOW_PCI_VERBOSE_INFO printf("pci: allocated mem region %d: %d bytes at 0x%x\n", regnum, size, base); #endif } else { #ifdef CONFIG_ARCH_HAS_IO_SPACE /* TODO handle IO region */ #endif } pci_conf_write(f, bar, oldv); f->reg_base[regnum] = base; f->reg_size[regnum] = size; } f->irq_line = pci_allocate_irqline(); /* FIXME */ f->irq_pin = PCI_INTERRUPT_PIN_C; pci_conf_write(f, PCI_INTERRUPT_REG, PCI_INTERRUPT_LINE(f->irq_line) | PCI_INTERRUPT_PIN(f->irq_pin)); printf("pci: function %02x:%02x.%d (%04x:%04x) configured\n", f->bus->busno, f->dev, f->func, PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id)); return 0; }
static int pci_device_openbsd_probe(struct pci_device *device) { struct pci_device_private *priv = (struct pci_device_private *)device; struct pci_mem_region *region; uint64_t reg64, size64; uint32_t bar, reg, size; int domain, bus, dev, func, err; domain = device->domain; bus = device->bus; dev = device->dev; func = device->func; err = pci_read(domain, bus, dev, func, PCI_BHLC_REG, ®); if (err) return err; priv->header_type = PCI_HDRTYPE_TYPE(reg); if (priv->header_type != 0) return 0; region = device->regions; for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += sizeof(uint32_t), region++) { err = pci_read(domain, bus, dev, func, bar, ®); if (err) return err; /* Probe the size of the region. */ err = pci_readmask(domain, bus, dev, func, bar, &size); if (err) return err; if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { region->is_IO = 1; region->base_addr = PCI_MAPREG_IO_ADDR(reg); region->size = PCI_MAPREG_IO_SIZE(size); } else { if (PCI_MAPREG_MEM_PREFETCHABLE(reg)) region->is_prefetchable = 1; switch(PCI_MAPREG_MEM_TYPE(reg)) { case PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_MEM_TYPE_32BIT_1M: region->base_addr = PCI_MAPREG_MEM_ADDR(reg); region->size = PCI_MAPREG_MEM_SIZE(size); break; case PCI_MAPREG_MEM_TYPE_64BIT: region->is_64 = 1; reg64 = reg; size64 = size; bar += sizeof(uint32_t); err = pci_read(domain, bus, dev, func, bar, ®); if (err) return err; reg64 |= (uint64_t)reg << 32; err = pci_readmask(domain, bus, dev, func, bar, &size); if (err) return err; size64 |= (uint64_t)size << 32; region->base_addr = PCI_MAPREG_MEM64_ADDR(reg64); region->size = PCI_MAPREG_MEM64_SIZE(size64); region++; break; } } } /* Probe expansion ROM if present */ err = pci_read(domain, bus, dev, func, PCI_ROM_REG, ®); if (err) return err; if (reg != 0) { err = pci_write(domain, bus, dev, func, PCI_ROM_REG, ~PCI_ROM_ENABLE); if (err) return err; pci_read(domain, bus, dev, func, PCI_ROM_REG, &size); pci_write(domain, bus, dev, func, PCI_ROM_REG, reg); if (PCI_ROM_ADDR(reg) != 0) { priv->rom_base = PCI_ROM_ADDR(reg); device->rom_size = PCI_ROM_SIZE(size); } } return 0; }
/* * static int cardbus_mem_find(cardbus_chipset_tag_t cc, * cardbus_function_tag_t cf, pcitag_t tag, * int reg, pcireg_t type, bus_addr_t *basep, * bus_size_t *sizep, int *flagsp) * This code is stolen from sys/dev/pci_map.c. */ static int cardbus_mem_find(cardbus_chipset_tag_t cc, cardbus_function_tag_t cf, pcitag_t tag, int reg, pcireg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp) { pcireg_t address, mask; int s; if (reg != CARDBUS_ROM_REG && (reg < PCI_MAPREG_START || reg >= PCI_MAPREG_END || (reg & 3))) { panic("cardbus_mem_find: bad request"); } /* * Section 6.2.5.1, `Address Maps', tells us that: * * 1) The builtin software should have already mapped the device in a * reasonable way. * * 2) A device which wants 2^n bytes of memory will hardwire the bottom * n bits of the address to 0. As recommended, we write all 1s and see * what we get back. */ s = splhigh(); address = cardbus_conf_read(cc, cf, tag, reg); cardbus_conf_write(cc, cf, tag, reg, 0xffffffff); mask = cardbus_conf_read(cc, cf, tag, reg); cardbus_conf_write(cc, cf, tag, reg, address); splx(s); if (reg != CARDBUS_ROM_REG) { /* memory space BAR */ if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) { printf("cardbus_mem_find: expected type mem, found i/o\n"); return 1; } if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) { printf("cardbus_mem_find: expected mem type %08x, found %08x\n", PCI_MAPREG_MEM_TYPE(type), PCI_MAPREG_MEM_TYPE(address)); return 1; } } if (PCI_MAPREG_MEM_SIZE(mask) == 0) { printf("cardbus_mem_find: void region\n"); return 1; } switch (PCI_MAPREG_MEM_TYPE(address)) { case PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_MEM_TYPE_32BIT_1M: break; case PCI_MAPREG_MEM_TYPE_64BIT: printf("cardbus_mem_find: 64-bit memory mapping register\n"); return 1; default: printf("cardbus_mem_find: reserved mapping register type\n"); return 1; } if (basep != 0) { *basep = PCI_MAPREG_MEM_ADDR(address); } if (sizep != 0) { *sizep = PCI_MAPREG_MEM_SIZE(mask); } if (flagsp != 0) { *flagsp = PCI_MAPREG_MEM_PREFETCHABLE(address) ? BUS_SPACE_MAP_PREFETCHABLE : 0; } return 0; }
void pciaddr_resource_manage(struct pcibios_softc *sc, pci_chipset_tag_t pc, pcitag_t tag, pciaddr_resource_manage_func_t func) { struct extent *ex; pcireg_t val, mask; bus_addr_t addr; bus_size_t size; int error, mapreg, type, reg_start, reg_end, width; val = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(val)) { default: printf("WARNING: unknown PCI device header 0x%x.\n", PCI_HDRTYPE_TYPE(val)); sc->nbogus++; return; case 0: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; break; case 1: /* PCI-PCI bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PPB_END; break; case 2: /* PCI-CardBus bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PCB_END; break; } error = 0; for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { /* inquire PCI device bus space requirement */ val = pci_conf_read(pc, tag, mapreg); pci_conf_write(pc, tag, mapreg, ~0); mask = pci_conf_read(pc, tag, mapreg); pci_conf_write(pc, tag, mapreg, val); type = PCI_MAPREG_TYPE(val); width = 4; if (type == PCI_MAPREG_TYPE_MEM) { if (PCI_MAPREG_MEM_TYPE(val) == PCI_MAPREG_MEM_TYPE_64BIT) { /* XXX We could examine the upper 32 bits * XXX of the BAR here, but we are totally * XXX unprepared to handle a non-zero value, * XXX either here or anywhere else in * XXX i386-land. * XXX So just arrange to not look at the * XXX upper 32 bits, lest we misinterpret * XXX it as a 32-bit BAR set to zero. */ width = 8; } addr = PCI_MAPREG_MEM_ADDR(val); size = PCI_MAPREG_MEM_SIZE(mask); ex = sc->extent_mem; } else { /* XXX some devices give 32bit value */ addr = PCI_MAPREG_IO_ADDR(val) & PCIADDR_PORT_END; size = PCI_MAPREG_IO_SIZE(mask); ex = sc->extent_port; } if (!size) /* unused register */ continue; /* reservation/allocation phase */ error += (*func) (sc, pc, tag, mapreg, ex, type, &addr, size); PCIBIOS_PRINTV(("\t%02xh %s 0x%08x 0x%08x\n", mapreg, type ? "port" : "mem ", (unsigned int)addr, (unsigned int)size)); } if (error) sc->nbogus++; PCIBIOS_PRINTV(("\t\t[%s]\n", error ? "NG" : "OK")); }
static void cac_pci_attach(device_t parent, device_t self, void *aux) { struct pci_attach_args *pa; const struct cac_pci_type *ct; struct cac_softc *sc; pci_chipset_tag_t pc; pci_intr_handle_t ih; const char *intrstr; pcireg_t reg; int memr, ior, i; char intrbuf[PCI_INTRSTR_LEN]; aprint_naive(": RAID controller\n"); sc = device_private(self); sc->sc_dev = self; pa = (struct pci_attach_args *)aux; pc = pa->pa_pc; ct = cac_pci_findtype(pa); /* * Map the PCI register window. */ memr = -1; ior = -1; for (i = 0x10; i <= 0x14; i += 4) { reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i); if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0) ior = i; } else { if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0) memr = i; } } if (memr != -1) { if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0, &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) memr = -1; else ior = -1; } if (ior != -1) if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) ior = -1; if (memr == -1 && ior == -1) { aprint_error_dev(self, "can't map i/o or memory space\n"); return; } sc->sc_dmat = pa->pa_dmat; /* Enable the device. */ reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg | PCI_COMMAND_MASTER_ENABLE); /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { aprint_error("can't map interrupt\n"); return; } intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, cac_intr, sc); if (sc->sc_ih == NULL) { aprint_error("can't establish interrupt"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); return; } aprint_normal(": Compaq %s\n", ct->ct_typestr); /* Now attach to the bus-independent code. */ memcpy(&sc->sc_cl, ct->ct_linkage, sizeof(sc->sc_cl)); cac_init(sc, intrstr, (ct->ct_flags & CT_STARTFW) != 0); }
static int pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp) { pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff; u_int64_t waddress, wmask; int s, is64bit, isrom; is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT); isrom = (reg == PCI_MAPREG_ROM); if ((!isrom) && (reg < PCI_MAPREG_START || #if 0 /* * Can't do this check; some devices have mapping registers * way out in left field. */ reg >= PCI_MAPREG_END || #endif (reg & 3))) panic("pci_mem_find: bad request"); if (is64bit && (reg + 4) >= PCI_MAPREG_END) panic("pci_mem_find: bad 64-bit request"); /* * Section 6.2.5.1, `Address Maps', tells us that: * * 1) The builtin software should have already mapped the device in a * reasonable way. * * 2) A device which wants 2^n bytes of memory will hardwire the bottom * n bits of the address to 0. As recommended, we write all 1s and see * what we get back. */ s = splhigh(); address = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, 0xffffffff); mask = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, address); if (is64bit) { address1 = pci_conf_read(pc, tag, reg + 4); pci_conf_write(pc, tag, reg + 4, 0xffffffff); mask1 = pci_conf_read(pc, tag, reg + 4); pci_conf_write(pc, tag, reg + 4, address1); } splx(s); if (!isrom) { /* * roms should have an enable bit instead of a memory * type decoder bit. For normal BARs, make sure that * the address decoder type matches what we asked for. */ if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) { printf("pci_mem_find: expected type mem, found i/o\n"); return (1); } /* XXX Allow 64bit bars for 32bit requests.*/ if (PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type) && PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE_64BIT) { printf("pci_mem_find: " "expected mem type %08x, found %08x\n", PCI_MAPREG_MEM_TYPE(type), PCI_MAPREG_MEM_TYPE(address)); return (1); } } waddress = (u_int64_t)address1 << 32UL | address; wmask = (u_int64_t)mask1 << 32UL | mask; if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) || (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) { aprint_debug("pci_mem_find: void region\n"); return (1); } switch (PCI_MAPREG_MEM_TYPE(address)) { case PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_MEM_TYPE_32BIT_1M: break; case PCI_MAPREG_MEM_TYPE_64BIT: /* * Handle the case of a 64-bit memory register on a * platform with 32-bit addressing. Make sure that * the address assigned and the device's memory size * fit in 32 bits. We implicitly assume that if * bus_addr_t is 64-bit, then so is bus_size_t. */ if (sizeof(u_int64_t) > sizeof(bus_addr_t) && (address1 != 0 || mask1 != 0xffffffff)) { printf("pci_mem_find: 64-bit memory map which is " "inaccessible on a 32-bit platform\n"); return (1); } break; default: printf("pci_mem_find: reserved mapping register type\n"); return (1); } if (sizeof(u_int64_t) > sizeof(bus_addr_t)) { if (basep != 0) *basep = PCI_MAPREG_MEM_ADDR(address); if (sizep != 0) *sizep = PCI_MAPREG_MEM_SIZE(mask); } else { if (basep != 0) *basep = PCI_MAPREG_MEM64_ADDR(waddress); if (sizep != 0) *sizep = PCI_MAPREG_MEM64_SIZE(wmask); } if (flagsp != 0) *flagsp = (isrom || PCI_MAPREG_MEM_PREFETCHABLE(address)) ? BUS_SPACE_MAP_PREFETCHABLE : 0; return (0); }
void pciaddr_resource_manage(pci_chipset_tag_t pc, pcitag_t tag, pciaddr_resource_manage_func_t func, void *ctx) { pcireg_t val, mask; bus_addr_t addr; bus_size_t size; int error, useport, usemem, mapreg, type, reg_start, reg_end, width; val = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(val)) { default: aprint_error("WARNING: unknown PCI device header."); pciaddr.nbogus++; return; case PCI_HDRTYPE_DEVICE: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; break; case PCI_HDRTYPE_PPB: /* PCI-PCI bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PPB_END; break; case PCI_HDRTYPE_PCB: /* PCI-CardBus bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PCB_END; break; } error = useport = usemem = 0; for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { /* inquire PCI device bus space requirement */ val = pci_conf_read(pc, tag, mapreg); pci_conf_write(pc, tag, mapreg, ~0); mask = pci_conf_read(pc, tag, mapreg); pci_conf_write(pc, tag, mapreg, val); type = PCI_MAPREG_TYPE(val); width = 4; if (type == PCI_MAPREG_TYPE_MEM) { if (PCI_MAPREG_MEM_TYPE(val) == PCI_MAPREG_MEM_TYPE_64BIT) { /* XXX We could examine the upper 32 bits * XXX of the BAR here, but we are totally * XXX unprepared to handle a non-zero value, * XXX either here or anywhere else in * XXX i386-land. * XXX So just arrange to not look at the * XXX upper 32 bits, lest we misinterpret * XXX it as a 32-bit BAR set to zero. */ width = 8; } size = PCI_MAPREG_MEM_SIZE(mask); } else { size = PCI_MAPREG_IO_SIZE(mask); } addr = pciaddr_ioaddr(val); if (size == 0) /* unused register */ continue; if (type == PCI_MAPREG_TYPE_MEM) ++usemem; else ++useport; /* reservation/allocation phase */ error += (*func) (pc, tag, mapreg, ctx, type, &addr, size); aprint_debug("\n\t%02xh %s 0x%08x 0x%08x", mapreg, type ? "port" : "mem ", (unsigned int)addr, (unsigned int)size); } /* enable/disable PCI device */ val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); if (error == 0) val |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE); else val &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE); pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); if (error != 0) pciaddr.nbogus++; aprint_debug("\n\t\t[%s]\n", error ? "NG" : "OK"); }
int obsd_pci_mem_find(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t type, bus_addr_t *basep, bus_size_t *sizep, int *flagsp) { pcireg_t address, mask, address1 = 0, mask1 = 0xffffffff, csr; u_int64_t waddress, wmask; int s, is64bit; is64bit = (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT); if (reg < PCI_MAPREG_START || #if 0 /* * Can't do this check; some devices have mapping registers * way out in left field. */ reg >= PCI_MAPREG_END || #endif (reg & 3)) panic("pci_mem_find: bad request"); if (is64bit && (reg + 4) >= PCI_MAPREG_END) panic("pci_mem_find: bad 64-bit request"); /* * Section 6.2.5.1, `Address Maps', tells us that: * * 1) The builtin software should have already mapped the device in a * reasonable way. * * 2) A device which wants 2^n bytes of memory will hardwire the bottom * n bits of the address to 0. As recommended, we write all 1s while * the device is disabled and see what we get back. */ s = splhigh(); csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); if (csr & PCI_COMMAND_MEM_ENABLE) pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr & ~PCI_COMMAND_MEM_ENABLE); address = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, 0xffffffff); mask = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, address); if (is64bit) { address1 = pci_conf_read(pc, tag, reg + 4); pci_conf_write(pc, tag, reg + 4, 0xffffffff); mask1 = pci_conf_read(pc, tag, reg + 4); pci_conf_write(pc, tag, reg + 4, address1); } if (csr & PCI_COMMAND_MEM_ENABLE) pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); splx(s); if (PCI_MAPREG_TYPE(address) != PCI_MAPREG_TYPE_MEM) { #ifdef DEBUG printf("pci_mem_find: expected type mem, found i/o\n"); #endif return (EINVAL); } if (type != -1 && PCI_MAPREG_MEM_TYPE(address) != PCI_MAPREG_MEM_TYPE(type)) { #ifdef DEBUG printf("pci_mem_find: expected mem type %08x, found %08x\n", PCI_MAPREG_MEM_TYPE(type), PCI_MAPREG_MEM_TYPE(address)); #endif return (EINVAL); } waddress = (u_int64_t)address1 << 32UL | address; wmask = (u_int64_t)mask1 << 32UL | mask; if ((is64bit && PCI_MAPREG_MEM64_SIZE(wmask) == 0) || (!is64bit && PCI_MAPREG_MEM_SIZE(mask) == 0)) { #ifdef DEBUG printf("pci_mem_find: void region\n"); #endif return (ENOENT); } switch (PCI_MAPREG_MEM_TYPE(address)) { case PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_MEM_TYPE_32BIT_1M: break; case PCI_MAPREG_MEM_TYPE_64BIT: /* * Handle the case of a 64-bit memory register on a * platform with 32-bit addressing. Make sure that * the address assigned and the device's memory size * fit in 32 bits. We implicitly assume that if * bus_addr_t is 64-bit, then so is bus_size_t. */ if (sizeof(u_int64_t) > sizeof(bus_addr_t) && (address1 != 0 || mask1 != 0xffffffff)) { #ifdef DEBUG printf("pci_mem_find: 64-bit memory map which is " "inaccessible on a 32-bit platform\n"); #endif return (EINVAL); } break; default: #ifdef DEBUG printf("pci_mem_find: reserved mapping register type\n"); #endif return (EINVAL); } if (sizeof(u_int64_t) > sizeof(bus_addr_t)) { if (basep != 0) *basep = PCI_MAPREG_MEM_ADDR(address); if (sizep != 0) *sizep = PCI_MAPREG_MEM_SIZE(mask); } else { if (basep != 0) *basep = PCI_MAPREG_MEM64_ADDR(waddress); if (sizep != 0) *sizep = PCI_MAPREG_MEM64_SIZE(wmask); } if (flagsp != 0) *flagsp = #ifdef BUS_SPACE_MAP_PREFETCHABLE PCI_MAPREG_MEM_PREFETCHABLE(address) ? BUS_SPACE_MAP_PREFETCHABLE : #endif 0; return (0); }
/* * Enable memory and I/O on pci devices. Care about already enabled devices * (probabaly by the console driver). * * The idea behind the following code is: * We build a by sizes sorted list of the requirements of the different * pci devices. After that we choose the start addresses of that areas * in such a way that they are placed as closed as possible together. */ static void enable_pci_devices(void) { PCI_MEMREG memlist; PCI_MEMREG iolist; struct pci_memreg *p, *q; int dev, reg, id, class; pcitag_t tag; pcireg_t csr, address, mask; pci_chipset_tag_t pc; int sizecnt, membase_1m; pc = 0; csr = 0; tag = 0; LIST_INIT(&memlist); LIST_INIT(&iolist); /* * first step: go through all devices and gather memory and I/O * sizes */ for (dev = 0; dev < pci_bus_maxdevs(pc,0); dev++) { tag = pci_make_tag(pc, 0, dev, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); if (id == 0 || id == 0xffffffff) continue; csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); /* * special case: if a display card is found and memory is enabled * preserve 128k at 0xa0000 as vga memory. * XXX: if a display card is found without being enabled, leave * it alone! You will usually only create conflicts by enabeling * it. */ class = pci_conf_read(pc, tag, PCI_CLASS_REG); switch (PCI_CLASS(class)) { case PCI_CLASS_PREHISTORIC: case PCI_CLASS_DISPLAY: if (csr & (PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE)) { p = (struct pci_memreg *)malloc(sizeof(struct pci_memreg), M_TEMP, M_WAITOK); memset(p, '\0', sizeof(struct pci_memreg)); p->dev = dev; p->csr = csr; p->tag = tag; p->reg = 0; /* there is no register about this */ p->size = 0x20000; /* 128kByte */ p->mask = 0xfffe0000; p->address = 0xa0000; insert_into_list(&memlist, p); } else continue; } for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) { address = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, 0xffffffff); mask = pci_conf_read(pc, tag, reg); pci_conf_write(pc, tag, reg, address); if (mask == 0) continue; /* Register unused */ p = (struct pci_memreg *)malloc(sizeof(struct pci_memreg), M_TEMP, M_WAITOK); memset(p, '\0', sizeof(struct pci_memreg)); p->dev = dev; p->csr = csr; p->tag = tag; p->reg = reg; p->mask = mask; p->address = 0; if (mask & PCI_MAPREG_TYPE_IO) { p->size = PCI_MAPREG_IO_SIZE(mask); /* * Align IO if necessary */ if (p->size < PCI_MAPREG_IO_SIZE(PCI_MACHDEP_IO_ALIGN_MASK)) { p->mask = PCI_MACHDEP_IO_ALIGN_MASK; p->size = PCI_MAPREG_IO_SIZE(p->mask); } /* * if I/O is already enabled (probably by the console driver) * save the address in order to take care about it later. */ if (csr & PCI_COMMAND_IO_ENABLE) p->address = address; insert_into_list(&iolist, p); } else { p->size = PCI_MAPREG_MEM_SIZE(mask); /* * Align memory if necessary */ if (p->size < PCI_MAPREG_IO_SIZE(PCI_MACHDEP_MEM_ALIGN_MASK)) { p->mask = PCI_MACHDEP_MEM_ALIGN_MASK; p->size = PCI_MAPREG_MEM_SIZE(p->mask); } /* * if memory is already enabled (probably by the console driver) * save the address in order to take care about it later. */ if (csr & PCI_COMMAND_MEM_ENABLE) p->address = address; insert_into_list(&memlist, p); if (PCI_MAPREG_MEM_TYPE(mask) == PCI_MAPREG_MEM_TYPE_64BIT) reg++; } } #if defined(_ATARIHW_) /* * Both interrupt pin & line are set to the device (== slot) * number. This makes sense on the atari Hades because the * individual slots are hard-wired to a specific MFP-pin. */ csr = (DEV2SLOT(dev) << PCI_INTERRUPT_PIN_SHIFT); csr |= (DEV2SLOT(dev) << PCI_INTERRUPT_LINE_SHIFT); pci_conf_write(pc, tag, PCI_INTERRUPT_REG, csr); #else /* * On the Milan, we accept the BIOS's choice. */ #endif } /* * second step: calculate the memory and I/O addresses beginning from * PCI_MEM_START and PCI_IO_START. Care about already mapped areas. * * begin with memory list */ address = PCI_MEM_START; sizecnt = 0; membase_1m = 0; p = LIST_FIRST(&memlist); while (p != NULL) { if (!(p->csr & PCI_COMMAND_MEM_ENABLE)) { if (PCI_MAPREG_MEM_TYPE(p->mask) == PCI_MAPREG_MEM_TYPE_32BIT_1M) { if (p->size > membase_1m) membase_1m = p->size; do { p->address = membase_1m; membase_1m += p->size; } while (overlap_pci_areas(LIST_FIRST(&memlist), p, p->address, p->size, PCI_COMMAND_MEM_ENABLE)); if (membase_1m > 0x00100000) { /* * Should we panic here? */ printf("\npcibus0: dev %d reg %d: memory not configured", p->dev, p->reg); p->reg = 0; } } else { if (sizecnt && (p->size > sizecnt)) sizecnt = ((p->size + sizecnt) & p->mask) & PCI_MAPREG_MEM_ADDR_MASK; if (sizecnt > address) { address = sizecnt; sizecnt = 0; } do { p->address = address + sizecnt; sizecnt += p->size; } while (overlap_pci_areas(LIST_FIRST(&memlist), p, p->address, p->size, PCI_COMMAND_MEM_ENABLE)); if ((address + sizecnt) > PCI_MEM_END) { /* * Should we panic here? */ printf("\npcibus0: dev %d reg %d: memory not configured", p->dev, p->reg); p->reg = 0; } } if (p->reg > 0) { pci_conf_write(pc, p->tag, p->reg, p->address); csr = pci_conf_read(pc, p->tag, PCI_COMMAND_STATUS_REG); csr |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE; pci_conf_write(pc, p->tag, PCI_COMMAND_STATUS_REG, csr); p->csr = csr; } } p = LIST_NEXT(p, link); } /* * now the I/O list */ address = PCI_IO_START; sizecnt = 0; p = LIST_FIRST(&iolist); while (p != NULL) { if (!(p->csr & PCI_COMMAND_IO_ENABLE)) { if (sizecnt && (p->size > sizecnt)) sizecnt = ((p->size + sizecnt) & p->mask) & PCI_MAPREG_IO_ADDR_MASK; if (sizecnt > address) { address = sizecnt; sizecnt = 0; } do { p->address = address + sizecnt; sizecnt += p->size; } while (overlap_pci_areas(LIST_FIRST(&iolist), p, p->address, p->size, PCI_COMMAND_IO_ENABLE)); if ((address + sizecnt) > PCI_IO_END) { /* * Should we panic here? */ printf("\npcibus0: dev %d reg %d: io not configured", p->dev, p->reg); } else { pci_conf_write(pc, p->tag, p->reg, p->address); csr = pci_conf_read(pc, p->tag, PCI_COMMAND_STATUS_REG); csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE; pci_conf_write(pc, p->tag, PCI_COMMAND_STATUS_REG, csr); p->csr = csr; } } p = LIST_NEXT(p, link); } #ifdef DEBUG_PCI_MACHDEP printf("\nI/O List:\n"); p = LIST_FIRST(&iolist); while (p != NULL) { printf("\ndev: %d, reg: 0x%02x, size: 0x%08x, addr: 0x%08x", p->dev, p->reg, p->size, p->address); p = LIST_NEXT(p, link); } printf("\nMemlist:"); p = LIST_FIRST(&memlist); while (p != NULL) { printf("\ndev: %d, reg: 0x%02x, size: 0x%08x, addr: 0x%08x", p->dev, p->reg, p->size, p->address); p = LIST_NEXT(p, link); } #endif /* * Free the lists */ p = LIST_FIRST(&iolist); while (p != NULL) { q = p; LIST_REMOVE(q, link); free(p, M_WAITOK); p = LIST_FIRST(&iolist); } p = LIST_FIRST(&memlist); while (p != NULL) { q = p; LIST_REMOVE(q, link); free(p, M_WAITOK); p = LIST_FIRST(&memlist); } }