u_int8_t * acpi_scan(struct acpi_mem_map *handle, paddr_t pa, size_t len) { size_t i; u_int8_t *ptr; struct acpi_rsdp1 *rsdp; if (acpi_map(pa, len, handle)) return (NULL); for (ptr = handle->va, i = 0; i < len; ptr += 16, i += 16) { /* is there a valid signature? */ if (memcmp(ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1)) continue; /* is the checksum valid? */ if (acpi_checksum(ptr, sizeof(struct acpi_rsdp1)) != 0) continue; /* check the extended checksum as needed */ rsdp = (struct acpi_rsdp1 *)ptr; if (rsdp->revision == 0) return (ptr); else if (rsdp->revision >= 2 && rsdp->revision <= 4) if (acpi_checksum(ptr, sizeof(struct acpi_rsdp)) == 0) return (ptr); } acpi_unmap(handle); return (NULL); }
u_int8_t * acpi_scan(struct acpi_mem_map *handle, paddr_t pa, size_t len) { size_t i; u_int8_t *ptr; struct acpi_rsdp1 *rsdp; if (acpi_map(pa, len, handle)) return (NULL); for (ptr = handle->va, i = 0; i < len; ptr += 16, i += 16) if (memcmp(ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0) { rsdp = (struct acpi_rsdp1 *)ptr; /* * Only checksum whichever portion of the * RSDP that is actually present */ if (rsdp->revision == 0 && acpi_checksum(ptr, sizeof(struct acpi_rsdp1)) == 0) return (ptr); else if (rsdp->revision >= 2 && rsdp->revision <= 4 && acpi_checksum(ptr, sizeof(struct acpi_rsdp)) == 0) return (ptr); } acpi_unmap(handle); return (NULL); }
void __iomem *__init_refok acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { struct acpi_ioremap *map; void __iomem *virt; acpi_physical_address pg_off; acpi_size pg_sz; if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); return NULL; } if (!acpi_gbl_permanent_mmap) return __acpi_map_table((unsigned long)phys, size); mutex_lock(&acpi_ioremap_lock); /* Check if there's a suitable mapping already. */ map = acpi_map_lookup(phys, size); if (map) { map->refcount++; goto out; } map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) { mutex_unlock(&acpi_ioremap_lock); return NULL; } pg_off = round_down(phys, PAGE_SIZE); pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; virt = acpi_map(pg_off, pg_sz); if (!virt) { mutex_unlock(&acpi_ioremap_lock); kfree(map); return NULL; } INIT_LIST_HEAD(&map->list); map->virt = virt; map->phys = pg_off; map->size = pg_sz; map->refcount = 1; list_add_tail_rcu(&map->list, &acpi_ioremaps); out: mutex_unlock(&acpi_ioremap_lock); return map->virt + (phys - map->phys); }
int acpi_probe(struct device *parent, struct cfdata *match, struct bios_attach_args *ba) { struct acpi_mem_map handle; u_int8_t *ptr; paddr_t ebda; /* * First try to find ACPI table entries in the EBDA */ if (acpi_map(0, NBPG, &handle)) printf("acpi: failed to map BIOS data area\n"); else { ebda = *(const u_int16_t *)(&handle.va[0x40e]); ebda <<= 4; acpi_unmap(&handle); if (ebda && ebda < IOM_BEGIN) { if ((ptr = acpi_scan(&handle, ebda, 1024))) goto havebase; } } /* * Next try to find the ACPI table entries in the * BIOS memory */ if ((ptr = acpi_scan(&handle, ACPI_BIOS_RSDP_WINDOW_BASE, ACPI_BIOS_RSDP_WINDOW_SIZE))) goto havebase; return (0); havebase: ba->ba_acpipbase = ptr - handle.va + handle.pa; acpi_unmap(&handle); return (1); }
int acpi_gasio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address, int access_size, int len, void *buffer) { u_int8_t *pb; bus_space_handle_t ioh; struct acpi_mem_map mh; pci_chipset_tag_t pc; pcitag_t tag; bus_addr_t ioaddr; int reg, idx, ival, sval; dnprintf(50, "gasio: %.2x 0x%.8llx %s\n", iospace, address, (iodir == ACPI_IOWRITE) ? "write" : "read"); pb = (u_int8_t *)buffer; switch (iospace) { case GAS_SYSTEM_MEMORY: /* copy to/from system memory */ acpi_map(address, len, &mh); if (iodir == ACPI_IOREAD) memcpy(buffer, mh.va, len); else memcpy(mh.va, buffer, len); acpi_unmap(&mh); break; case GAS_SYSTEM_IOSPACE: /* read/write from I/O registers */ ioaddr = address; if (acpi_bus_space_map(sc->sc_iot, ioaddr, len, 0, &ioh) != 0) { printf("unable to map iospace\n"); return (-1); } for (reg = 0; reg < len; reg += access_size) { if (iodir == ACPI_IOREAD) { switch (access_size) { case 1: *(uint8_t *)(pb+reg) = bus_space_read_1( sc->sc_iot, ioh, reg); dnprintf(80, "os_in8(%llx) = %x\n", reg+address, *(uint8_t *)(pb+reg)); break; case 2: *(uint16_t *)(pb+reg) = bus_space_read_2( sc->sc_iot, ioh, reg); dnprintf(80, "os_in16(%llx) = %x\n", reg+address, *(uint16_t *)(pb+reg)); break; case 4: *(uint32_t *)(pb+reg) = bus_space_read_4( sc->sc_iot, ioh, reg); break; default: printf("rdio: invalid size %d\n", access_size); break; } } else { switch (access_size) { case 1: bus_space_write_1(sc->sc_iot, ioh, reg, *(uint8_t *)(pb+reg)); dnprintf(80, "os_out8(%llx,%x)\n", reg+address, *(uint8_t *)(pb+reg)); break; case 2: bus_space_write_2(sc->sc_iot, ioh, reg, *(uint16_t *)(pb+reg)); dnprintf(80, "os_out16(%llx,%x)\n", reg+address, *(uint16_t *)(pb+reg)); break; case 4: bus_space_write_4(sc->sc_iot, ioh, reg, *(uint32_t *)(pb+reg)); break; default: printf("wrio: invalid size %d\n", access_size); break; } } /* During autoconf some devices are still gathering * information. Delay here to give them an opportunity * to finish. During runtime we simply need to ignore * transient values. */ if (cold) delay(10000); } acpi_bus_space_unmap(sc->sc_iot, ioh, len, &ioaddr); break; case GAS_PCI_CFG_SPACE: /* format of address: * bits 00..15 = register * bits 16..31 = function * bits 32..47 = device * bits 48..63 = bus */ pc = NULL; tag = pci_make_tag(pc, ACPI_PCI_BUS(address), ACPI_PCI_DEV(address), ACPI_PCI_FN(address)); /* XXX: This is ugly. read-modify-write does a byte at a time */ reg = ACPI_PCI_REG(address); for (idx = reg; idx < reg+len; idx++) { ival = pci_conf_read(pc, tag, idx & ~0x3); if (iodir == ACPI_IOREAD) { *pb = ival >> (8 * (idx & 0x3)); } else { sval = *pb; ival &= ~(0xFF << (8* (idx & 0x3))); ival |= sval << (8* (idx & 0x3)); pci_conf_write(pc, tag, idx & ~0x3, ival); } pb++; }