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) {

Reply via email to