Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/acpi Add acpimcfg_configure_bus, which can be used b...



details:   https://anonhg.NetBSD.org/src/rev/8bce38e25e08
branches:  trunk
changeset: 445152:8bce38e25e08
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Oct 15 10:01:32 2018 +0000

description:
Add acpimcfg_configure_bus, which can be used by MD code to implement
PCI_NETBSD_CONFIGURE using ACPI MCFG tables.

diffstat:

 sys/dev/acpi/acpi_mcfg.c |  211 ++++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/acpi/acpi_mcfg.h |    3 +-
 2 files changed, 211 insertions(+), 3 deletions(-)

diffs (258 lines):

diff -r 2f9006a9b7b1 -r 8bce38e25e08 sys/dev/acpi/acpi_mcfg.c
--- a/sys/dev/acpi/acpi_mcfg.c  Mon Oct 15 10:00:30 2018 +0000
+++ b/sys/dev/acpi/acpi_mcfg.c  Mon Oct 15 10:01:32 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: acpi_mcfg.c,v 1.7 2018/10/13 13:32:50 jmcneill Exp $   */
+/*     $NetBSD: acpi_mcfg.c,v 1.8 2018/10/15 10:01:32 jmcneill Exp $   */
 
 /*-
  * Copyright (C) 2015 NONAKA Kimihiro <nonaka%NetBSD.org@localhost>
@@ -25,16 +25,20 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_pci.h"
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.7 2018/10/13 13:32:50 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.8 2018/10/15 10:01:32 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/kmem.h>
 #include <sys/systm.h>
+#include <sys/extent.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
+#include <dev/pci/pciconf.h>
 #include <dev/pci/pcidevs.h>
 
 #include <dev/acpi/acpireg.h>
@@ -677,6 +681,209 @@
        return error;
 }
 
+#ifdef PCI_NETBSD_CONFIGURE
+struct acpimcfg_resource {
+       struct extent *ioext;
+       struct extent *memext;
+       struct extent *pmemext;
+};
+
+static ACPI_STATUS
+acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx)
+{
+       struct acpimcfg_resource *pcires = ctx;
+       struct extent *ex;
+       const char *s;
+       int error;
+
+       if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
+           res->Type != ACPI_RESOURCE_TYPE_ADDRESS64)
+               return AE_OK;
+
+       if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER)
+               return AE_OK;
+
+       if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE &&
+           res->Data.Address.ResourceType != ACPI_IO_RANGE)
+               return AE_OK;
+
+       if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE &&
+           res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) {
+               if (pcires->pmemext == NULL) {
+                       pcires->pmemext = extent_create("pcipmem", 0, ULONG_MAX,
+                           NULL, 0, EX_WAITOK);
+                       error = extent_alloc_region(pcires->pmemext, 0, ULONG_MAX,
+                           EX_WAITOK);
+                       if (error) {
+                               extent_destroy(pcires->pmemext);
+                               pcires->pmemext = NULL;
+                               return AE_NO_MEMORY;
+                       }
+               }
+               ex = pcires->pmemext;
+               s = "prefetchable";
+       } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE &&
+           res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) {
+               if (pcires->memext == NULL) {
+                       pcires->memext = extent_create("pcimem", 0, ULONG_MAX,
+                           NULL, 0, EX_WAITOK);
+                       error = extent_alloc_region(pcires->memext, 0, ULONG_MAX,
+                           EX_WAITOK);
+                       if (error) {
+                               extent_destroy(pcires->memext);
+                               pcires->memext = NULL;
+                               return AE_NO_MEMORY;
+                       }
+               }
+               ex = pcires->memext;
+               s = "non-prefetchable";
+       } else if (res->Data.Address.ResourceType == ACPI_IO_RANGE) {
+               if (pcires->ioext == NULL) {
+                       pcires->ioext = extent_create("pciio", 0, ULONG_MAX,
+                           NULL, 0, EX_WAITOK);
+                       error = extent_alloc_region(pcires->ioext, 0, ULONG_MAX,
+                           EX_WAITOK);
+                       if (error) {
+                               extent_destroy(pcires->ioext);
+                               pcires->ioext = NULL;
+                               return AE_NO_MEMORY;
+                       }
+               }
+               ex = pcires->ioext;
+               s = "i/o";
+               
+       }
+
+       switch (res->Type) {
+       case ACPI_RESOURCE_TYPE_ADDRESS16:
+               aprint_debug(
+                   "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n",
+                   res->Data.Address16.Address.Minimum,
+                   res->Data.Address16.Address.AddressLength,
+                   s);
+               error = extent_free(ex, res->Data.Address16.Address.Minimum,
+                   res->Data.Address16.Address.AddressLength, EX_WAITOK);
+               if (error)
+                       return AE_NO_MEMORY;
+               break;
+       case ACPI_RESOURCE_TYPE_ADDRESS32:
+               aprint_debug(
+                   "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n",
+                   res->Data.Address32.Address.Minimum,
+                   res->Data.Address32.Address.AddressLength,
+                   s);
+               error = extent_free(ex, res->Data.Address32.Address.Minimum,
+                   res->Data.Address32.Address.AddressLength, EX_WAITOK);
+               if (error)
+                       return AE_NO_MEMORY;
+               break;
+       case ACPI_RESOURCE_TYPE_ADDRESS64:
+               aprint_debug(
+                   "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n",
+                   res->Data.Address64.Address.Minimum,
+                   res->Data.Address64.Address.AddressLength,
+                   s);
+               error = extent_free(ex, res->Data.Address64.Address.Minimum,
+                   res->Data.Address64.Address.AddressLength, EX_WAITOK);
+               if (error)
+                       return AE_NO_MEMORY;
+               break;
+       }
+
+       return AE_OK;
+}
+
+int
+acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle,
+    int bus, int cacheline_size)
+{
+       struct acpimcfg_resource res;
+       struct mcfg_segment *seg;
+       struct mcfg_bus *mb;
+       bus_space_handle_t bsh[256];
+       bool bsh_mapped[256];
+       int error, boff, b, d, f;
+       bus_addr_t baddr;
+       ACPI_STATUS rv;
+
+       seg = acpimcfg_get_segment(bus);
+       if (seg == NULL)
+               return ENOENT;
+
+       /*
+        * Map config space for all possible busses and mark them valid during
+        * configuration so pci_configure_bus can access them through our chipset
+        * tag with acpimcfg_conf_read/write below.
+        */
+       memset(bsh_mapped, 0, sizeof(bsh_mapped));
+       for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) {
+               boff = b - seg->ms_bus_start;
+               mb = &seg->ms_bus[boff];
+               baddr = seg->ms_address + (boff * ACPIMCFG_SIZE_PER_BUS);
+
+               /* Map extended configration space of all dev/func. */
+               error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0,
+                   &bsh[b]);
+               if (error != 0)
+                       goto cleanup;
+               bsh_mapped[b] = true;
+               for (d = 0; d < 32; d++) {
+                       for (f = 0; f < 8; f++) {
+                               error = bus_space_subregion(seg->ms_bst, bsh[b],
+                                   EXTCONF_OFFSET(d, f, 0), PCI_EXTCONF_SIZE,
+                                   &mb->bsh[d][f]);
+                               if (error != 0)
+                                       break;
+                       }
+               }
+               if (error != 0)
+                       goto cleanup;
+
+               memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
+       }
+
+       memset(&res, 0, sizeof(res));
+       rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb, &res);
+       if (ACPI_FAILURE(rv)) {
+               error = ENXIO;
+               goto cleanup;
+       }
+
+       error = pci_configure_bus(pc, res.ioext, res.memext, res.pmemext, bus,
+           cacheline_size);
+
+cleanup:
+       /*
+        * Unmap config space for the segment's busses. Valid devices will be
+        * re-mapped later on by acpimcfg_map_bus.
+        */
+       for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) {
+               boff = b - seg->ms_bus_start;
+               mb = &seg->ms_bus[boff];
+               memset(mb->valid_devs, 0, sizeof(mb->valid_devs));
+
+               if (bsh_mapped[b])
+                       bus_space_unmap(seg->ms_bst, bsh[b], ACPIMCFG_SIZE_PER_BUS);
+       }
+
+       if (res.ioext)
+               extent_destroy(res.ioext);
+       if (res.memext)
+               extent_destroy(res.memext);
+       if (res.pmemext)
+               extent_destroy(res.pmemext);
+
+       return error;
+}
+#else
+int
+acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle,
+    int cacheline_size)
+{
+       return ENXIO;
+}
+#endif
+
 int
 acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data)
 {
diff -r 2f9006a9b7b1 -r 8bce38e25e08 sys/dev/acpi/acpi_mcfg.h
--- a/sys/dev/acpi/acpi_mcfg.h  Mon Oct 15 10:00:30 2018 +0000
+++ b/sys/dev/acpi/acpi_mcfg.h  Mon Oct 15 10:01:32 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: acpi_mcfg.h,v 1.1 2015/10/02 05:22:52 msaitoh Exp $    */
+/*     $NetBSD: acpi_mcfg.h,v 1.2 2018/10/15 10:01:32 jmcneill Exp $   */
 
 /*-
  * Copyright (C) 2015 NONAKA Kimihiro <nonaka%NetBSD.org@localhost>
@@ -32,6 +32,7 @@
 void   acpimcfg_probe(struct acpi_softc *);
 int    acpimcfg_init(bus_space_tag_t, const struct acpimcfg_ops *);
 int    acpimcfg_map_bus(device_t, pci_chipset_tag_t, int);
+int    acpimcfg_configure_bus(device_t, pci_chipset_tag_t, ACPI_HANDLE, int, int);
 
 int    acpimcfg_conf_read(pci_chipset_tag_t, pcitag_t, int, pcireg_t *);
 int    acpimcfg_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);



Home | Main Index | Thread Index | Old Index