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++; }
map->ioapic_ih = APIC_INT_VIA_APIC | ((apic->sc_apicid << APIC_INT_APIC_SHIFT) | (map->ioapic_pin << APIC_INT_PIN_SHIFT)); apic->sc_pins[map->ioapic_pin].ip_map = map; map->next = mp_busses[sc->sc_bus].mb_intrs; mp_busses[sc->sc_bus].mb_intrs = map; return; } #endif bus = sc->sc_bus; dev = ACPI_PCI_DEV(addr << 16); tag = pci_make_tag(pc, bus, dev, 0); reg = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(reg)) nfuncs = 8; else nfuncs = 1; for (func = 0; func < nfuncs; func++) { tag = pci_make_tag(pc, bus, dev, func); reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); if (PCI_INTERRUPT_PIN(reg) == pin + 1) { reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); reg |= irq << PCI_INTERRUPT_LINE_SHIFT; pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);