So here is another attempt to use information from ACPI to decide what
parts of the address space are usable for PCI devices. This version
attaches the PCI busses late such that the various hacks for VMs to
prevent multiple disk drivers to attach to the same disk still work.
Please test, especially on VMs and older systems.
Index: arch/amd64/amd64/mainbus.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/mainbus.c,v
retrieving revision 1.49
diff -u -p -r1.49 mainbus.c
--- arch/amd64/amd64/mainbus.c 7 Sep 2019 13:46:19 -0000 1.49
+++ arch/amd64/amd64/mainbus.c 19 Oct 2019 18:49:49 -0000
@@ -231,6 +231,13 @@ mainbus_attach(struct device *parent, st
#endif
#if NPCI > 0
+#if NACPI > 0
+ if (acpi_haspci) {
+ extern void acpipci_attach_busses(struct device *);
+
+ acpipci_attach_busses(self);
+ } else
+#endif
{
pci_init_extents();
@@ -245,9 +252,6 @@ mainbus_attach(struct device *parent, st
mba.mba_pba.pba_domain = pci_ndomains++;
mba.mba_pba.pba_bus = 0;
config_found(self, &mba.mba_pba, mainbus_print);
-#if NACPI > 0
- acpi_pciroots_attach(self, &mba.mba_pba, mainbus_print);
-#endif
}
#endif
Index: arch/amd64/conf/RAMDISK
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/RAMDISK,v
retrieving revision 1.74
diff -u -p -r1.74 RAMDISK
--- arch/amd64/conf/RAMDISK 7 Sep 2019 13:46:19 -0000 1.74
+++ arch/amd64/conf/RAMDISK 19 Oct 2019 18:49:49 -0000
@@ -29,6 +29,7 @@ acpi0 at bios?
#acpicpu* at acpi?
acpicmos* at acpi?
acpiec* at acpi?
+acpipci* at acpi?
acpiprt* at acpi?
acpimadt0 at acpi?
#acpitz* at acpi?
Index: arch/amd64/conf/RAMDISK_CD
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/RAMDISK_CD,v
retrieving revision 1.185
diff -u -p -r1.185 RAMDISK_CD
--- arch/amd64/conf/RAMDISK_CD 26 Sep 2019 03:00:30 -0000 1.185
+++ arch/amd64/conf/RAMDISK_CD 19 Oct 2019 18:49:49 -0000
@@ -37,6 +37,7 @@ acpi0 at bios?
#acpicpu* at acpi?
acpicmos* at acpi?
acpiec* at acpi?
+acpipci* at acpi?
acpiprt* at acpi?
acpimadt0 at acpi?
#acpitz* at acpi?
Index: arch/amd64/pci/acpipci.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/pci/acpipci.c,v
retrieving revision 1.3
diff -u -p -r1.3 acpipci.c
--- arch/amd64/pci/acpipci.c 7 Sep 2019 13:46:19 -0000 1.3
+++ arch/amd64/pci/acpipci.c 19 Oct 2019 18:49:49 -0000
@@ -53,6 +53,19 @@ struct acpipci_softc {
struct device sc_dev;
struct acpi_softc *sc_acpi;
struct aml_node *sc_node;
+
+ bus_space_tag_t sc_iot;
+ bus_space_tag_t sc_memt;
+ bus_dma_tag_t sc_dmat;
+
+ struct extent *sc_busex;
+ struct extent *sc_memex;
+ struct extent *sc_ioex;
+ char sc_busex_name[32];
+ char sc_ioex_name[32];
+ char sc_memex_name[32];
+ int sc_bus;
+ uint32_t sc_seg;
};
int acpipci_match(struct device *, void *, void *);
@@ -72,6 +85,11 @@ const char *acpipci_hids[] = {
NULL
};
+void acpipci_attach_deferred(struct device *);
+int acpipci_print(void *, const char *);
+int acpipci_parse_resources(int, union acpi_resource *, void *);
+void acpipci_osc(struct acpipci_softc *);
+
int
acpipci_match(struct device *parent, void *match, void *aux)
{
@@ -86,15 +104,212 @@ acpipci_attach(struct device *parent, st
{
struct acpi_attach_args *aaa = aux;
struct acpipci_softc *sc = (struct acpipci_softc *)self;
- struct aml_value args[4];
struct aml_value res;
- static uint8_t uuid[16] = ACPI_PCI_UUID;
- uint32_t buf[3];
+ uint64_t bbn = 0;
+ uint64_t seg = 0;
+
+ acpi_haspci = 1;
+
+ sc->sc_iot = aaa->aaa_iot;
+ sc->sc_memt = aaa->aaa_memt;
+ sc->sc_dmat = aaa->aaa_dmat;
sc->sc_acpi = (struct acpi_softc *)parent;
sc->sc_node = aaa->aaa_node;
printf(" %s", sc->sc_node->name);
+ acpipci_osc(sc);
+
+ aml_evalinteger(sc->sc_acpi, sc->sc_node, "_BBN", 0, NULL, &bbn);
+ sc->sc_bus = bbn;
+
+ aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg);
+ sc->sc_seg = seg;
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
+ printf(": can't find resources\n");
+
+ pci_init_extents();
+ sc->sc_busex = pcibus_ex;
+ sc->sc_ioex = pciio_ex;
+ sc->sc_memex = pcimem_ex;
+
+ return;
+ }
+
+ /* Create extents for our address spaces. */
+ snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name),
+ "%s pcibus", sc->sc_dev.dv_xname);
+ snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name),
+ "%s pciio", sc->sc_dev.dv_xname);
+ snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name),
+ "%s pcimem", sc->sc_dev.dv_xname);
+ sc->sc_busex = extent_create(sc->sc_busex_name, 0, 255,
+ M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
+ sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, 0xffffffff,
+ M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
+ sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1,
+ M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED);
+
+ aml_parse_resource(&res, acpipci_parse_resources, sc);
+
+ printf("\n");
+
+#ifdef DIAGNOSTIC
+ extent_print(sc->sc_busex);
+ extent_print(sc->sc_ioex);
+ extent_print(sc->sc_memex);
+#endif
+}
+
+void
+acpipci_attach_bus(struct device *parent, struct acpipci_softc *sc)
+{
+ struct pcibus_attach_args pba;
+ pcitag_t tag;
+ pcireg_t id, class;
+
+ memset(&pba, 0, sizeof(pba));
+ pba.pba_busname = "pci";
+ pba.pba_iot = sc->sc_iot;
+ pba.pba_memt = sc->sc_memt;
+ pba.pba_dmat = sc->sc_dmat;
+ pba.pba_busex = sc->sc_busex;
+ pba.pba_ioex = sc->sc_ioex;
+ pba.pba_memex = sc->sc_memex;
+ pba.pba_pmemex = sc->sc_memex;
+ pba.pba_domain = pci_ndomains++;
+ pba.pba_bus = sc->sc_bus;
+
+ /* Enable MSI in ACPI 2.0 and above, unless we're told not to. */
+ if (sc->sc_acpi->sc_fadt->hdr.revision >= 2 &&
+ (sc->sc_acpi->sc_fadt->iapc_boot_arch & FADT_NO_MSI) == 0)
+ pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
+
+ /*
+ * Don't enable MSI on chipsets from low-end manifacturers
+ * like VIA and SiS. We do this by looking at the host
+ * bridge, which should be device 0 function 0.
+ */
+ tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 0, 0);
+ id = pci_conf_read(pba.pba_pc, tag, PCI_ID_REG);
+ class = pci_conf_read(pba.pba_pc, tag, PCI_CLASS_REG);
+ if (PCI_CLASS(class) == PCI_CLASS_BRIDGE &&
+ PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_HOST &&
+ PCI_VENDOR(id) != PCI_VENDOR_AMD &&
+ PCI_VENDOR(id) != PCI_VENDOR_NVIDIA &&
+ PCI_VENDOR(id) != PCI_VENDOR_INTEL)
+ pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
+
+ /*
+ * Don't enable MSI on a HyperTransport bus. In order to
+ * determine that a bus is a HyperTransport bus, we look at
+ * device 24 function 0, which is the HyperTransport
+ * host/primary interface integrated on most 64-bit AMD CPUs.
+ * If that device has a HyperTransport capability, this must
+ * be a HyperTransport bus and we disable MSI.
+ */
+ tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 24, 0);
+ if (pci_get_capability(pba.pba_pc, tag, PCI_CAP_HT, NULL, NULL))
+ pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
+
+ config_found(parent, &pba, acpipci_print);
+}
+
+void
+acpipci_attach_busses(struct device *parent)
+{
+ int i;
+
+ for (i = 0; i < acpipci_cd.cd_ndevs; i++) {
+ if (acpipci_cd.cd_devs[i])
+ acpipci_attach_bus(parent, acpipci_cd.cd_devs[i]);
+ }
+}
+
+int
+acpipci_print(void *aux, const char *pnp)
+{
+ struct pcibus_attach_args *pba = aux;
+
+ if (pnp)
+ printf("%s at %s", pba->pba_busname, pnp);
+ printf(" bus %d", pba->pba_bus);
+ return (UNCONF);
+}
+
+int
+acpipci_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
+{
+ struct acpipci_softc *sc = arg;
+ int type = AML_CRSTYPE(crs);
+ int restype, tflags = 0;
+ u_long min, len = 0, tra = 0;
+
+ switch (type) {
+ case LR_WORD:
+ restype = crs->lr_word.type;
+ tflags = crs->lr_word.tflags;
+ min = crs->lr_word._min;
+ len = crs->lr_word._len;
+ tra = crs->lr_word._tra;
+ break;
+ case LR_DWORD:
+ restype = crs->lr_dword.type;
+ tflags = crs->lr_dword.tflags;
+ min = crs->lr_dword._min;
+ len = crs->lr_dword._len;
+ tra = crs->lr_dword._tra;
+ break;
+ case LR_QWORD:
+ restype = crs->lr_qword.type;
+ tflags = crs->lr_qword.tflags;
+ min = crs->lr_qword._min;
+ len = crs->lr_qword._len;
+ tra = crs->lr_qword._tra;
+ break;
+ case LR_MEM32FIXED:
+ /*
+ * Coreboot on the PC Engines apu2 incorrectly uses a
+ * Memory32Fixed resource descriptor to describe mmio
+ * address space forwarded to the PCI bus.
+ */
+ restype = LR_TYPE_MEMORY;
+ min = crs->lr_m32fixed._bas;
+ len = crs->lr_m32fixed._len;
+ break;
+ }
+
+ if (len == 0)
+ return 0;
+
+ switch (restype) {
+ case LR_TYPE_MEMORY:
+ if (tflags & LR_MEMORY_TTP)
+ return 0;
+ extent_free(sc->sc_memex, min, len, EX_WAITOK | EX_CONFLICTOK);
+ break;
+ case LR_TYPE_IO:
+ if (tflags & LR_IO_TTP)
+ return 0;
+ extent_free(sc->sc_ioex, min, len, EX_WAITOK | EX_CONFLICTOK);
+ break;
+ case LR_TYPE_BUS:
+ extent_free(sc->sc_busex, min, len, EX_WAITOK);
+ break;
+ }
+
+ return 0;
+}
+
+void
+acpipci_osc(struct acpipci_softc *sc)
+{
+ struct aml_value args[4];
+ struct aml_value res;
+ static uint8_t uuid[16] = ACPI_PCI_UUID;
+ uint32_t buf[3];
+
memset(args, 0, sizeof(args));
args[0].type = AML_OBJTYPE_BUFFER;
args[0].v_buffer = uuid;
@@ -112,10 +327,8 @@ acpipci_attach(struct device *parent, st
buf[1] = ACPI_PCI_PCIE_CONFIG | ACPI_PCI_MSI;
buf[2] = ACPI_PCI_PCIE_HOTPLUG;
- if (aml_evalname(sc->sc_acpi, sc->sc_node, "_OSC", 4, args, &res)) {
- printf(": _OSC failed\n");
+ if (aml_evalname(sc->sc_acpi, sc->sc_node, "_OSC", 4, args, &res))
return;
- }
if (res.type == AML_OBJTYPE_BUFFER) {
size_t len = res.length;
@@ -128,6 +341,4 @@ acpipci_attach(struct device *parent, st
len -= 4;
}
}
-
- printf("\n");
}
Index: arch/amd64/pci/pci_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/pci/pci_machdep.c,v
retrieving revision 1.73
diff -u -p -r1.73 pci_machdep.c
--- arch/amd64/pci/pci_machdep.c 7 Sep 2019 13:46:19 -0000 1.73
+++ arch/amd64/pci/pci_machdep.c 19 Oct 2019 18:49:49 -0000
@@ -163,64 +163,6 @@ void
pci_attach_hook(struct device *parent, struct device *self,
struct pcibus_attach_args *pba)
{
- pci_chipset_tag_t pc = pba->pba_pc;
- pcitag_t tag;
- pcireg_t id, class;
-
- if (pba->pba_bus != 0)
- return;
-
- /*
- * In order to decide whether the system supports MSI we look
- * at the host bridge, which should be device 0 function 0 on
- * bus 0. It is better to not enable MSI on systems that
- * support it than the other way around, so be conservative
- * here. So we don't enable MSI if we don't find a host
- * bridge there. We also deliberately don't enable MSI on
- * chipsets from low-end manifacturers like VIA and SiS.
- */
- tag = pci_make_tag(pc, 0, 0, 0);
- id = pci_conf_read(pc, tag, PCI_ID_REG);
- class = pci_conf_read(pc, tag, PCI_CLASS_REG);
-
- if (PCI_CLASS(class) != PCI_CLASS_BRIDGE ||
- PCI_SUBCLASS(class) != PCI_SUBCLASS_BRIDGE_HOST)
- return;
-
- switch (PCI_VENDOR(id)) {
- case PCI_VENDOR_INTEL:
- /*
- * In the wonderful world of virtualization you can
- * have the latest 64-bit AMD multicore CPU behind a
- * prehistoric Intel host bridge. Give them what they
- * deserve.
- */
- switch (PCI_PRODUCT(id)) {
- case PCI_PRODUCT_INTEL_82441FX: /* QEMU */
- case PCI_PRODUCT_INTEL_82443BX: /* VMWare */
- break;
- default:
- pba->pba_flags |= PCI_FLAGS_MSI_ENABLED;
- break;
- }
- break;
- case PCI_VENDOR_NVIDIA:
- case PCI_VENDOR_AMD:
- pba->pba_flags |= PCI_FLAGS_MSI_ENABLED;
- break;
- }
-
- /*
- * Don't enable MSI on a HyperTransport bus. In order to
- * determine that bus 0 is a HyperTransport bus, we look at
- * device 24 function 0, which is the HyperTransport
- * host/primary interface integrated on most 64-bit AMD CPUs.
- * If that device has a HyperTransport capability, bus 0 must
- * be a HyperTransport bus and we disable MSI.
- */
- tag = pci_make_tag(pc, 0, 24, 0);
- if (pci_get_capability(pc, tag, PCI_CAP_HT, NULL, NULL))
- pba->pba_flags &= ~PCI_FLAGS_MSI_ENABLED;
}
int
Index: dev/acpi/acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.374
diff -u -p -r1.374 acpi.c
--- dev/acpi/acpi.c 7 Sep 2019 13:46:20 -0000 1.374
+++ dev/acpi/acpi.c 19 Oct 2019 18:49:50 -0000
@@ -71,6 +71,7 @@ int acpi_debug = 16;
int acpi_poll_enabled;
int acpi_hasprocfvs;
+int acpi_haspci;
#define ACPIEN_RETRIES 15
Index: dev/acpi/acpivar.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v
retrieving revision 1.105
diff -u -p -r1.105 acpivar.h
--- dev/acpi/acpivar.h 7 Sep 2019 13:46:20 -0000 1.105
+++ dev/acpi/acpivar.h 19 Oct 2019 18:49:50 -0000
@@ -43,6 +43,7 @@ extern int acpi_debug;
#endif
extern int acpi_hasprocfvs;
+extern int acpi_haspci;
struct klist;
struct acpiec_softc;