static bool radeon_read_bios(struct radeon_device *rdev) { uint8_t __iomem *bios; bus_size_t size; pcireg_t address, mask; bus_space_handle_t romh; int rc; rdev->bios = NULL; /* XXX: some cards may return 0 for rom size? ddx has a workaround */ address = pci_conf_read(rdev->pc, rdev->pa_tag, PCI_ROM_REG); pci_conf_write(rdev->pc, rdev->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE); mask = pci_conf_read(rdev->pc, rdev->pa_tag, PCI_ROM_REG); address |= PCI_ROM_ENABLE; pci_conf_write(rdev->pc, rdev->pa_tag, PCI_ROM_REG, address); size = PCI_ROM_SIZE(mask); if (size == 0) return false; rc = bus_space_map(rdev->memt, PCI_ROM_ADDR(address), size, BUS_SPACE_MAP_LINEAR, &romh); if (rc != 0) { printf(": can't map PCI ROM (%d)\n", rc); return false; } bios = (uint8_t *)bus_space_vaddr(rdev->memt, romh); if (!bios) { printf(": bus_space_vaddr failed\n"); return false; } if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) goto fail; rdev->bios = kmalloc(size, GFP_KERNEL); memcpy(rdev->bios, bios, size); bus_space_unmap(rdev->memt, romh, size); return true; fail: bus_space_unmap(rdev->memt, romh, size); return false; }
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; }
int cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa) { struct pci_vpd_largeres *res; struct pci_vpd *vpd; bus_space_handle_t romh; bus_space_tag_t romt; bus_size_t romsize; u_int8_t buf[32], *desc; pcireg_t address, mask; int dataoff, vpdoff, len; int rv = -1; address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe); mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address |= PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); romt = pa->pa_memt; romsize = PCI_ROM_SIZE(mask); if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) { romsize = 0; goto fail; } bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf)); if (bcmp(buf, cas_promhdr, sizeof(cas_promhdr))) goto fail; dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8); if (dataoff < 0x1c) goto fail; bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf)); if (bcmp(buf, cas_promdat, sizeof(cas_promdat)) || bcmp(buf + PROMDATA_DATA2, cas_promdat2, sizeof(cas_promdat2))) goto fail; vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8); if (vpdoff < 0x1c) goto fail; next: bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); if (!PCI_VPDRES_ISLARGE(buf[0])) goto fail; res = (struct pci_vpd_largeres *)buf; vpdoff += sizeof(*res); len = ((res->vpdres_len_msb << 8) + res->vpdres_len_lsb); switch(PCI_VPDRES_LARGE_NAME(res->vpdres_byte0)) { case PCI_VPDRES_TYPE_IDENTIFIER_STRING: /* Skip identifier string. */ vpdoff += len; goto next; case PCI_VPDRES_TYPE_VPD: while (len > 0) { bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); vpd = (struct pci_vpd *)buf; vpdoff += sizeof(*vpd) + vpd->vpd_len; len -= sizeof(*vpd) + vpd->vpd_len; /* * We're looking for an "Enhanced" VPD... */ if (vpd->vpd_key0 != 'Z') continue; desc = buf + sizeof(*vpd); /* * ...which is an instance property... */ if (desc[0] != 'I') continue; desc += 3; /* * ...that's a byte array with the proper * length for a MAC address... */ if (desc[0] != 'B' || desc[1] != ETHER_ADDR_LEN) continue; desc += 2; /* * ...named "local-mac-address". */ if (strcmp(desc, "local-mac-address") != 0) continue; desc += strlen("local-mac-address") + 1; bcopy(desc, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); rv = 0; } break; default: goto fail; } fail: if (romsize != 0) bus_space_unmap(romt, romh, romsize); address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address &= ~PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); return (rv); }
int gem_pci_enaddr(struct gem_softc *sc, struct pci_attach_args *pa) { struct pci_vpd *vpd; bus_space_handle_t romh; bus_space_tag_t romt; bus_size_t romsize; u_int8_t buf[32]; pcireg_t address, mask; int dataoff, vpdoff; int rv = -1; address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe); mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address |= PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); romt = pa->pa_memt; romsize = PCI_ROM_SIZE(mask); if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) { romsize = 0; goto fail; } bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf)); if (bcmp(buf, gem_promhdr, sizeof(gem_promhdr))) goto fail; dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8); if (dataoff < 0x1c) goto fail; bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf)); if (bcmp(buf, gem_promdat, sizeof(gem_promdat)) || bcmp(buf + PROMDATA_DATA2, gem_promdat2, sizeof(gem_promdat2))) goto fail; vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8); if (vpdoff < 0x1c) goto fail; bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); /* * The VPD of gem is not in PCI 2.2 standard format. The length * in the resource header is in big endian. */ vpd = (struct pci_vpd *)(buf + 3); if (!PCI_VPDRES_ISLARGE(buf[0]) || PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD) goto fail; if (vpd->vpd_key0 != 'N' || vpd->vpd_key1 != 'A') goto fail; bcopy(buf + 6, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); rv = 0; fail: if (romsize != 0) bus_space_unmap(romt, romh, romsize); address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address &= ~PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); return (rv); }
/* * Grovel the STI ROM image. */ int sti_check_rom(struct sti_pci_softc *spc, struct pci_attach_args *pa) { struct sti_softc *sc = &spc->sc_base; pcireg_t address, mask; bus_space_handle_t romh; bus_size_t romsize, subsize, stiromsize; bus_addr_t selected, offs, suboffs; u_int32_t tmp; int i; int rc; /* sort of inline sti_pci_enable_rom(sc) */ address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE); mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address |= PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); sc->sc_flags |= STI_ROM_ENABLED; /* * Map the complete ROM for now. */ romsize = PCI_ROM_SIZE(mask); rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address), romsize, 0, &romh); sti_pci_disable_rom(sc); if (rc != 0) { printf("%s: can't map PCI ROM (%d)\n", sc->sc_dev.dv_xname, rc); goto fail2; } /* * Iterate over the ROM images, pick the best candidate. */ selected = (bus_addr_t)-1; for (offs = 0; offs < romsize; offs += subsize) { sti_pci_enable_rom(sc); /* * Check for a valid ROM header. */ tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0); tmp = letoh32(tmp); if (tmp != 0x55aa0000) { sti_pci_disable_rom(sc); if (offs == 0) { printf("%s: invalid PCI ROM header signature" " (%08x)\n", sc->sc_dev.dv_xname, tmp); rc = EINVAL; } break; } /* * Check ROM type. */ tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4); tmp = letoh32(tmp); if (tmp != 0x00000001) { /* 1 == STI ROM */ sti_pci_disable_rom(sc); if (offs == 0) { printf("%s: invalid PCI ROM type (%08x)\n", sc->sc_dev.dv_xname, tmp); rc = EINVAL; } break; } subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, offs + 0x0c); subsize <<= 9; #ifdef STIDEBUG sti_pci_disable_rom(sc); printf("ROM offset %08lx size %08lx type %08x", offs, subsize, tmp); sti_pci_enable_rom(sc); #endif /* * Check for a valid ROM data structure. * We do not need it except to know what architecture the ROM * code is for. */ suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh, offs + 0x18); tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0); tmp = letoh32(tmp); if (tmp != 0x50434952) { /* PCIR */ sti_pci_disable_rom(sc); if (offs == 0) { printf("%s: invalid PCI data signature" " (%08x)\n", sc->sc_dev.dv_xname, tmp); rc = EINVAL; } else { #ifdef STIDEBUG printf(" invalid PCI data signature %08x\n", tmp); #endif continue; } } tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14); sti_pci_disable_rom(sc); #ifdef STIDEBUG printf(" code %02x", tmp); #endif switch (tmp) { #ifdef __hppa__ case 0x10: if (selected == (bus_addr_t)-1) selected = offs; break; #endif #ifdef __i386__ case 0x00: if (selected == (bus_addr_t)-1) selected = offs; break; #endif default: #ifdef STIDEBUG printf(" (wrong architecture)"); #endif break; } #ifdef STIDEBUG if (selected == offs) printf(" -> SELECTED"); printf("\n"); #endif } if (selected == (bus_addr_t)-1) { if (rc == 0) { printf("%s: found no ROM with correct microcode" " architecture\n", sc->sc_dev.dv_xname); rc = ENOEXEC; } goto fail; } /* * Read the STI region BAR assignments. */ sti_pci_enable_rom(sc); offs = selected + (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e); for (i = 0; i < STI_REGION_MAX; i++) { rc = sti_readbar(sc, pa, i, bus_space_read_1(pa->pa_memt, romh, offs + i)); if (rc != 0) goto fail; } /* * Find out where the STI ROM itself lies, and its size. */ offs = selected + (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08); stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, offs + 0x18); stiromsize = letoh32(stiromsize); sti_pci_disable_rom(sc); /* * Replace our mapping with a smaller mapping of only the area * we are interested in. */ bus_space_unmap(pa->pa_memt, romh, romsize); rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address) + offs, stiromsize, 0, &spc->sc_romh); if (rc != 0) { printf("%s: can't map STI ROM (%d)\n", sc->sc_dev.dv_xname, rc); goto fail2; } return (0); fail: bus_space_unmap(pa->pa_memt, romh, romsize); fail2: sti_pci_disable_rom(sc); return (rc); }