Here is a new version of the diff to make sure we respect the access
size of pci config space reads and writes in acpi code that was backed
out. This version adds some code to make sure those reads and writes
are properly aligned. This should prevent the panic that some people
saw with the previous diff. Apparently some AML writers think it
makes perfect sense to have a region that is only 16-bit aligned but
demand 32-bit access to it.
Giovanni, can you try this on that "bigio" machine?
Index: acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.291
diff -u -p -r1.291 acpi.c
--- acpi.c 4 Aug 2015 15:21:59 -0000 1.291
+++ acpi.c 18 Aug 2015 21:11:05 -0000
@@ -218,6 +218,50 @@ struct acpi_softc *acpi_softc;
#define acpi_bus_space_map _bus_space_map
#define acpi_bus_space_unmap _bus_space_unmap
+uint8_t
+acpi_pci_conf_read_1(pci_chipset_tag_t pc, pcitag_t tag, int reg)
+{
+ uint32_t val = pci_conf_read(pc, tag, reg & ~0x3);
+ return (val >> ((reg & 0x3) << 3));
+}
+
+uint16_t
+acpi_pci_conf_read_2(pci_chipset_tag_t pc, pcitag_t tag, int reg)
+{
+ uint32_t val = pci_conf_read(pc, tag, reg & ~0x2);
+ return (val >> ((reg & 0x2) << 3));
+}
+
+uint32_t
+acpi_pci_conf_read_4(pci_chipset_tag_t pc, pcitag_t tag, int reg)
+{
+ return pci_conf_read(pc, tag, reg);
+}
+
+void
+acpi_pci_conf_write_1(pci_chipset_tag_t pc, pcitag_t tag, int reg, uint8_t val)
+{
+ uint32_t tmp = pci_conf_read(pc, tag, reg & ~0x3);
+ tmp &= ~(0xff << ((reg & 0x3) << 3));
+ tmp |= (val << ((reg & 0x3) << 3));
+ pci_conf_write(pc, tag, reg & ~0x3, tmp);
+}
+
+void
+acpi_pci_conf_write_2(pci_chipset_tag_t pc, pcitag_t tag, int reg, uint16_t
val)
+{
+ uint32_t tmp = pci_conf_read(pc, tag, reg & ~0x2);
+ tmp &= ~(0xffff << ((reg & 0x2) << 3));
+ tmp |= (val << ((reg & 0x2) << 3));
+ pci_conf_write(pc, tag, reg & ~0x2, tmp);
+}
+
+void
+acpi_pci_conf_write_4(pci_chipset_tag_t pc, pcitag_t tag, int reg, uint32_t
val)
+{
+ pci_conf_write(pc, tag, reg, val);
+}
+
int
acpi_gasio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address,
int access_size, int len, void *buffer)
@@ -227,7 +271,7 @@ acpi_gasio(struct acpi_softc *sc, int io
bus_space_handle_t ioh;
pci_chipset_tag_t pc;
pcitag_t tag;
- int reg, idx, ival, sval;
+ int reg, idx;
dnprintf(50, "gasio: %.2x 0x%.8llx %s\n",
iospace, address, (iodir == ACPI_IOWRITE) ? "write" : "read");
@@ -326,19 +370,47 @@ acpi_gasio(struct acpi_softc *sc, int io
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);
+ for (idx = 0; idx < len; idx += access_size) {
if (iodir == ACPI_IOREAD) {
- *pb = ival >> (8 * (idx & 0x3));
+ switch (access_size) {
+ case 1:
+ *(uint8_t *)(pb + idx) =
+ acpi_pci_conf_read_1(pc, tag, reg +
idx);
+ break;
+ case 2:
+ *(uint16_t *)(pb + idx) =
+ acpi_pci_conf_read_2(pc, tag, reg +
idx);
+ break;
+ case 4:
+ *(uint32_t *)(pb + idx) =
+ acpi_pci_conf_read_4(pc, tag, reg +
idx);
+ break;
+ default:
+ printf("%s: rdcfg: invalid size %d\n",
+ DEVNAME(sc), access_size);
+ return (-1);
+ }
} else {
- sval = *pb;
- ival &= ~(0xFF << (8* (idx & 0x3)));
- ival |= sval << (8* (idx & 0x3));
- pci_conf_write(pc, tag, idx & ~0x3, ival);
+ switch (access_size) {
+ case 1:
+ acpi_pci_conf_write_1(pc, tag, reg +
idx,
+ *(uint8_t *)(pb + idx));
+ break;
+ case 2:
+ acpi_pci_conf_write_2(pc, tag, reg +
idx,
+ *(uint16_t *)(pb + idx));
+ break;
+ case 4:
+ acpi_pci_conf_write_4(pc, tag, reg +
idx,
+ *(uint32_t *)(pb + idx));
+ break;
+ default:
+ printf("%s: wrcfg: invalid size %d\n",
+ DEVNAME(sc), access_size);
+ return (-1);
+ }
}
- pb++;
}
break;
Index: dsdt.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
retrieving revision 1.217
diff -u -p -r1.217 dsdt.c
--- dsdt.c 4 May 2015 10:42:06 -0000 1.217
+++ dsdt.c 18 Aug 2015 21:11:05 -0000
@@ -2260,7 +2260,8 @@ aml_rwgas(struct aml_value *rgn, int bpo
break;
}
- pi.addr = rgn->v_opregion.iobase + ((bpos >> 3) & ~(sz - 1));
+ pi.addr = (rgn->v_opregion.iobase + (bpos >> 3)) & ~(sz - 1);
+ bpos += ((rgn->v_opregion.iobase & (sz - 1)) << 3);
bpos &= ((sz << 3) - 1);
if (rgn->v_opregion.iospace == GAS_PCI_CFG_SPACE) {