Add acpimcfg_configure_bus, which can be used by MD code to implement
PCI_NETBSD_CONFIGURE using ACPI MCFG tables.
This commit is contained in:
parent
7a0ad3635b
commit
aaf945cfa7
@ -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>
|
||||
@ -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 @@ out:
|
||||
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)
|
||||
{
|
||||
|
@ -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>
|
||||
@ -32,6 +32,7 @@ struct acpimcfg_ops;
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user