-/* $OpenBSD: acpi_machdep.c,v 1.84 2018/07/04 20:46:21 kettenis Exp $ */
+/* $OpenBSD: acpi_machdep.c,v 1.85 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
sc->sc_iot = ba->ba_iot;
sc->sc_memt = ba->ba_memt;
sc->sc_dmat = &pci_bus_dma_tag;
- sc->sc_pc = NULL; /* Legacy 0xcf8/0xcfc access mechanism */
acpi_attach_common(sc, ba->ba_acpipbase);
}
-/* $OpenBSD: pci_machdep.h,v 1.26 2018/07/04 20:46:22 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.27 2018/08/19 08:23:47 kettenis Exp $ */
/* $NetBSD: pci_machdep.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */
/*
pcireg_t pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
void pci_set_powerstate_md(pci_chipset_tag_t, pcitag_t, int, int);
-pci_chipset_tag_t pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int);
+void pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int);
+pci_chipset_tag_t pci_lookup_segment(int);
/*
* ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED
-/* $OpenBSD: pci_machdep.c,v 1.68 2018/07/04 20:46:22 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.69 2018/08/19 08:23:47 kettenis Exp $ */
/* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */
/*-
_bus_dmamem_mmap,
};
-pci_chipset_tag_t
-pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int min_bus, int max_bus)
+void
+pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment,
+ int min_bus, int max_bus)
{
- pci_mcfgt = iot;
- pci_mcfg_addr = addr;
- pci_mcfg_min_bus = min_bus;
- pci_mcfg_max_bus = max_bus;
+ if (segment == 0) {
+ pci_mcfgt = iot;
+ pci_mcfg_addr = addr;
+ pci_mcfg_min_bus = min_bus;
+ pci_mcfg_max_bus = max_bus;
+ }
+}
+pci_chipset_tag_t
+pci_lookup_segment(int segment)
+{
+ KASSERT(segment == 0);
return NULL;
}
-/* $OpenBSD: acpipci.c,v 1.6 2018/08/11 22:47:27 kettenis Exp $ */
+/* $OpenBSD: acpipci.c,v 1.7 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis
*
#include <dev/pci/pcivar.h>
#include <dev/pci/ppbreg.h>
-bus_addr_t pci_mcfg_addr;
-int pci_mcfg_min_bus, pci_mcfg_max_bus;
-bus_space_tag_t pci_mcfgt;
-bus_space_handle_t pci_mcfgh;
+struct acpipci_mcfg {
+ SLIST_ENTRY(acpipci_mcfg) am_list;
+
+ uint16_t am_segment;
+ uint8_t am_min_bus;
+ uint8_t am_max_bus;
+
+ bus_space_tag_t am_iot;
+ bus_space_handle_t am_ioh;
+
+ struct arm64_pci_chipset am_pc;
+};
struct acpipci_trans {
struct acpipci_trans *at_next;
struct device sc_dev;
struct acpi_softc *sc_acpi;
struct aml_node *sc_node;
-
bus_space_tag_t sc_iot;
- bus_space_handle_t sc_ioh;
+ pci_chipset_tag_t sc_pc;
struct bus_space sc_bus_iot;
struct bus_space sc_bus_memt;
struct acpipci_trans *sc_io_trans;
struct acpipci_trans *sc_mem_trans;
- struct arm64_pci_chipset sc_pc;
struct extent *sc_busex;
struct extent *sc_memex;
struct extent *sc_ioex;
uint64_t bbn = 0;
uint64_t seg = 0;
- /* Bail out early if we don't have a valid MCFG table. */
- if (pci_mcfg_addr == 0 || pci_mcfg_max_bus <= pci_mcfg_min_bus) {
- printf(": no registers\n");
- return;
- }
-
sc->sc_acpi = (struct acpi_softc *)parent;
sc->sc_node = aaa->aaa_node;
printf(" %s", sc->sc_node->name);
aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg);
sc->sc_seg = seg;
- sc->sc_iot = pci_mcfgt;
- sc->sc_ioh = pci_mcfgh;
-
+ sc->sc_iot = aaa->aaa_memt;
+
printf("\n");
- /* XXX We only support segment 0 for now. */
- if (seg != 0)
- return;
-
/* Create extents for our address spaces. */
snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name),
"%s pcibus", sc->sc_dev.dv_xname);
sc->sc_bus_memt.bus_private = sc->sc_mem_trans;
sc->sc_bus_memt._space_map = acpipci_bs_map;
- sc->sc_pc.pc_conf_v = sc;
- sc->sc_pc.pc_attach_hook = acpipci_attach_hook;
- sc->sc_pc.pc_bus_maxdevs = acpipci_bus_maxdevs;
- sc->sc_pc.pc_make_tag = acpipci_make_tag;
- sc->sc_pc.pc_decompose_tag = acpipci_decompose_tag;
- sc->sc_pc.pc_conf_size = acpipci_conf_size;
- sc->sc_pc.pc_conf_read = acpipci_conf_read;
- sc->sc_pc.pc_conf_write = acpipci_conf_write;
-
- sc->sc_pc.pc_intr_v = sc;
- sc->sc_pc.pc_intr_map = acpipci_intr_map;
- sc->sc_pc.pc_intr_map_msi = acpipci_intr_map_msi;
- sc->sc_pc.pc_intr_map_msix = acpipci_intr_map_msix;
- sc->sc_pc.pc_intr_string = acpipci_intr_string;
- sc->sc_pc.pc_intr_establish = acpipci_intr_establish;
- sc->sc_pc.pc_intr_disestablish = acpipci_intr_disestablish;
+ sc->sc_pc = pci_lookup_segment(seg);
+ KASSERT(sc->sc_pc->pc_intr_v == NULL);
+
+ sc->sc_pc->pc_intr_v = sc;
+ sc->sc_pc->pc_intr_map = acpipci_intr_map;
+ sc->sc_pc->pc_intr_map_msi = acpipci_intr_map_msi;
+ sc->sc_pc->pc_intr_map_msix = acpipci_intr_map_msix;
+ sc->sc_pc->pc_intr_string = acpipci_intr_string;
+ sc->sc_pc->pc_intr_establish = acpipci_intr_establish;
+ sc->sc_pc->pc_intr_disestablish = acpipci_intr_disestablish;
memset(&pba, 0, sizeof(pba));
pba.pba_busname = "pci";
pba.pba_iot = &sc->sc_bus_iot;
pba.pba_memt = &sc->sc_bus_memt;
pba.pba_dmat = aaa->aaa_dmat;
- pba.pba_pc = &sc->sc_pc;
+ pba.pba_pc = sc->sc_pc;
pba.pba_busex = sc->sc_busex;
pba.pba_ioex = sc->sc_ioex;
pba.pba_memex = sc->sc_memex;
pcireg_t
acpipci_conf_read(void *v, pcitag_t tag, int reg)
{
- struct acpipci_softc *sc = v;
+ struct acpipci_mcfg *am = v;
+
+ if (tag < (am->am_min_bus << 20) ||
+ tag >= ((am->am_max_bus + 1) << 20))
+ return 0xffffffff;
- return bus_space_read_4(sc->sc_iot, sc->sc_ioh, tag | reg);
+ return bus_space_read_4(am->am_iot, am->am_ioh, tag | reg);
}
void
acpipci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
{
- struct acpipci_softc *sc = v;
+ struct acpipci_mcfg *am = v;
+
+ if (tag < (am->am_min_bus << 20) ||
+ tag >= ((am->am_max_bus + 1) << 20))
+ return;
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, tag | reg, data);
+ bus_space_write_4(am->am_iot, am->am_ioh, tag | reg, data);
}
struct acpipci_intr_handle {
return ENXIO;
}
-struct arm64_pci_chipset pci_mcfg_chipset;
+SLIST_HEAD(,acpipci_mcfg) acpipci_mcfgs =
+ SLIST_HEAD_INITIALIZER(acpipci_mcfgs);
+
+void
+pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment,
+ int min_bus, int max_bus)
+{
+ struct acpipci_mcfg *am;
+
+ am = malloc(sizeof(struct acpipci_mcfg), M_DEVBUF, M_WAITOK | M_ZERO);
+ am->am_segment = segment;
+ am->am_min_bus = min_bus;
+ am->am_max_bus = max_bus;
+
+ am->am_iot = iot;
+ if (bus_space_map(iot, addr, (max_bus + 1) << 20, 0, &am->am_ioh))
+ panic("%s: can't map config space", __func__);
+
+ am->am_pc.pc_conf_v = am;
+ am->am_pc.pc_attach_hook = acpipci_attach_hook;
+ am->am_pc.pc_bus_maxdevs = acpipci_bus_maxdevs;
+ am->am_pc.pc_make_tag = acpipci_make_tag;
+ am->am_pc.pc_decompose_tag = acpipci_decompose_tag;
+ am->am_pc.pc_conf_size = acpipci_conf_size;
+ am->am_pc.pc_conf_read = acpipci_conf_read;
+ am->am_pc.pc_conf_write = acpipci_conf_write;
+ SLIST_INSERT_HEAD(&acpipci_mcfgs, am, am_list);
+}
pcireg_t
-pci_mcfg_conf_read(void *v, pcitag_t tag, int reg)
+acpipci_dummy_conf_read(void *v, pcitag_t tag, int reg)
{
- return bus_space_read_4(pci_mcfgt, pci_mcfgh, tag | reg);
+ return 0xffffffff;
}
void
-pci_mcfg_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
+acpipci_dummy_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
{
- bus_space_write_4(pci_mcfgt, pci_mcfgh, tag | reg, data);
}
+struct arm64_pci_chipset acpipci_dummy_chipset = {
+ .pc_attach_hook = acpipci_attach_hook,
+ .pc_bus_maxdevs = acpipci_bus_maxdevs,
+ .pc_make_tag = acpipci_make_tag,
+ .pc_decompose_tag = acpipci_decompose_tag,
+ .pc_conf_size = acpipci_conf_size,
+ .pc_conf_read = acpipci_dummy_conf_read,
+ .pc_conf_write = acpipci_dummy_conf_write,
+};
+
pci_chipset_tag_t
-pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int min_bus, int max_bus)
+pci_lookup_segment(int segment)
{
- pci_chipset_tag_t pc = &pci_mcfg_chipset;
-
- pci_mcfgt = iot;
- pci_mcfg_addr = addr;
- pci_mcfg_min_bus = min_bus;
- pci_mcfg_max_bus = max_bus;
+ struct acpipci_mcfg *am;
- if (bus_space_map(iot, addr, (pci_mcfg_max_bus + 1) << 20, 0,
- &pci_mcfgh))
- panic("%s: can't map config space", __func__);
-
- memset(pc, 0, sizeof(*pc));
- pc->pc_bus_maxdevs = acpipci_bus_maxdevs;
- pc->pc_make_tag = acpipci_make_tag;
- pc->pc_decompose_tag = acpipci_decompose_tag;
- pc->pc_conf_size = acpipci_conf_size;
- pc->pc_conf_read = pci_mcfg_conf_read;
- pc->pc_conf_write = pci_mcfg_conf_write;
+ SLIST_FOREACH(am, &acpipci_mcfgs, am_list) {
+ if (am->am_segment == segment)
+ return &am->am_pc;
+ }
- return pc;
+ return &acpipci_dummy_chipset;
}
/*
-/* $OpenBSD: pci_machdep.h,v 1.2 2018/07/05 19:25:38 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.3 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
#define pci_dev_postattach(a, b)
-pci_chipset_tag_t pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int);
+void pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int);
+pci_chipset_tag_t pci_lookup_segment(int);
-/* $OpenBSD: acpi_machdep.c,v 1.68 2018/07/04 20:46:22 kettenis Exp $ */
+/* $OpenBSD: acpi_machdep.c,v 1.69 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
sc->sc_iot = ba->ba_iot;
sc->sc_memt = ba->ba_memt;
sc->sc_dmat = &pci_bus_dma_tag;
- sc->sc_pc = NULL; /* Legacy 0xcf8/0xcfc access mechanism */
acpi_attach_common(sc, ba->ba_acpipbase);
}
-/* $OpenBSD: pci_machdep.c,v 1.83 2018/07/04 20:46:22 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.84 2018/08/19 08:23:47 kettenis Exp $ */
/* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */
/*-
_bus_dmamem_mmap,
};
-pci_chipset_tag_t
-pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int min_bus, int max_bus)
+void
+pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment,
+ int min_bus, int max_bus)
{
- pci_mcfgt = iot;
- pci_mcfg_addr = addr;
- pci_mcfg_min_bus = min_bus;
- pci_mcfg_max_bus = max_bus;
+ if (segment == 0) {
+ pci_mcfgt = iot;
+ pci_mcfg_addr = addr;
+ pci_mcfg_min_bus = min_bus;
+ pci_mcfg_max_bus = max_bus;
+ }
+}
+pci_chipset_tag_t
+pci_lookup_segment(int segment)
+{
+ KASSERT(segment == 0);
return NULL;
}
-/* $OpenBSD: pci_machdep.h,v 1.29 2018/07/04 20:46:22 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.30 2018/08/19 08:23:47 kettenis Exp $ */
/* $NetBSD: pci_machdep.h,v 1.7 1997/06/06 23:29:18 thorpej Exp $ */
/*
pcireg_t pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
void pci_set_powerstate_md(pci_chipset_tag_t, pcitag_t, int, int);
-pci_chipset_tag_t pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int);
+void pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int);
+pci_chipset_tag_t pci_lookup_segment(int);
/*
* Section 6.2.4, `Miscellaneous Functions' of the PIC Specification,
-/* $OpenBSD: acpi.c,v 1.356 2018/08/03 22:18:13 kettenis Exp $ */
+/* $OpenBSD: acpi.c,v 1.357 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
break;
case GAS_PCI_CFG_SPACE:
- /* format of address:
- * bits 00..15 = register
- * bits 16..31 = function
- * bits 32..47 = device
- * bits 48..63 = bus
- */
-
/*
* The ACPI standard says that a function number of
* FFFF can be used to refer to all functions on a
return (0);
}
- pc = sc->sc_pc;
+ pc = pci_lookup_segment(ACPI_PCI_SEG(address));
tag = pci_make_tag(pc,
ACPI_PCI_BUS(address), ACPI_PCI_DEV(address),
ACPI_PCI_FN(address));
struct acpi_pci *pci, *ppci;
struct aml_value res;
struct acpi_softc *sc = arg;
- pci_chipset_tag_t pc = sc->sc_pc;
+ pci_chipset_tag_t pc;
pcitag_t tag;
uint64_t val;
uint32_t reg;
return 0;
pci = malloc(sizeof(*pci), M_DEVBUF, M_WAITOK|M_ZERO);
+ pci->seg = ppci->seg;
pci->bus = ppci->sub;
pci->dev = ACPI_ADR_PCIDEV(val);
pci->fun = ACPI_ADR_PCIFUN(val);
free(pci, M_DEVBUF, sizeof(*pci));
return (1);
}
+ pc = pci_lookup_segment(pci->seg);
tag = pci_make_tag(pc, pci->bus, pci->dev, pci->fun);
reg = pci_conf_read(pc, tag, PCI_ID_REG);
if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) {
acpi_pci_notify(struct aml_node *node, int ntype, void *arg)
{
struct acpi_pci *pdev = arg;
- pci_chipset_tag_t pc = acpi_softc->sc_pc;
+ pci_chipset_tag_t pc;
pcitag_t tag;
pcireg_t reg;
int offset;
if (ntype != 2)
return (0);
+ pc = pci_lookup_segment(pdev->seg);
tag = pci_make_tag(pc, pdev->bus, pdev->dev, pdev->fun);
if (pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, 0)) {
/* Clear the PME Status bit if it is set. */
-/* $OpenBSD: acpimcfg.c,v 1.3 2018/07/04 20:46:22 kettenis Exp $ */
+/* $OpenBSD: acpimcfg.c,v 1.4 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2010 Mark Kettenis <kettenis@openbsd.org>
*
void
acpimcfg_attach(struct device *parent, struct device *self, void *aux)
{
- struct acpi_softc *sc = (struct acpi_softc *)parent;
struct acpi_attach_args *aaa = aux;
struct acpi_mcfg *mcfg = (struct acpi_mcfg *)aaa->aaa_table;
+ caddr_t addr = (caddr_t)(mcfg + 1);
- printf(" addr 0x%llx, bus %d-%d\n", mcfg->base_address,
- mcfg->min_bus_number, mcfg->max_bus_number);
+ printf("\n");
- /*
- * Some (broken?) BIOSen have an MCFG table for an empty bus
- * range. Ignore those tables.
- */
- if (mcfg->min_bus_number == mcfg->max_bus_number)
- return;
+ while (addr < (caddr_t)mcfg + mcfg->hdr.length) {
+ struct acpi_mcfg_entry *entry = (struct acpi_mcfg_entry *)addr;
+
+ printf("%s: addr 0x%llx, bus %d-%d\n", self->dv_xname,
+ entry->base_address, entry->min_bus_number, entry->max_bus_number);
- sc->sc_pc = pci_mcfg_init(aaa->aaa_memt, mcfg->base_address,
- mcfg->min_bus_number, mcfg->max_bus_number);
+ pci_mcfg_init(aaa->aaa_memt, entry->base_address,
+ entry->segment, entry->min_bus_number, entry->max_bus_number);
+ addr += sizeof(struct acpi_mcfg_entry);
+ }
}
-/* $OpenBSD: acpireg.h,v 1.42 2018/07/01 10:26:17 kettenis Exp $ */
+/* $OpenBSD: acpireg.h,v 1.43 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
struct acpi_table_header hdr;
#define MCFG_SIG "MCFG"
uint8_t reserved[8];
+} __packed;
+
+struct acpi_mcfg_entry {
uint64_t base_address;
uint16_t segment;
uint8_t min_bus_number;
*/
#define ACPI_ADR_PCIDEV(addr) (uint16_t)(addr >> 16)
#define ACPI_ADR_PCIFUN(addr) (uint16_t)(addr & 0xFFFF)
-#define ACPI_PCI_BUS(addr) (uint16_t)((addr) >> 48)
-#define ACPI_PCI_DEV(addr) (uint16_t)((addr) >> 32)
+
+#define ACPI_PCI_SEG(addr) (uint16_t)((addr) >> 48)
+#define ACPI_PCI_BUS(addr) (uint8_t)((addr) >> 40)
+#define ACPI_PCI_DEV(addr) (uint8_t)((addr) >> 32)
#define ACPI_PCI_FN(addr) (uint16_t)((addr) >> 16)
#define ACPI_PCI_REG(addr) (uint16_t)(addr)
-#define ACPI_PCI_ADDR(b,d,f,r) ((uint64_t)(b)<<48LL | (uint64_t)(d)<<32LL | (f)<<16LL | (r))
/*
* PM1 Status Registers Fixed Hardware Feature Status Bits
-/* $OpenBSD: acpivar.h,v 1.97 2018/08/03 22:18:13 kettenis Exp $ */
+/* $OpenBSD: acpivar.h,v 1.98 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
bus_space_tag_t sc_memt;
bus_dma_tag_t sc_dmat;
- pci_chipset_tag_t sc_pc; /* XXX assume single segment */
-
/*
* First-level ACPI tables
*/
-/* $OpenBSD: dsdt.c,v 1.242 2018/06/29 17:39:18 kettenis Exp $ */
+/* $OpenBSD: dsdt.c,v 1.243 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
*
{
int64_t res;
+ addr->bus = 0;
+ addr->seg = 0;
if (aml_evalinteger(acpi_softc, pcidev, "_ADR", 0, NULL, &res) == 0) {
addr->fun = res & 0xFFFF;
addr->dev = res >> 16;
}
while (pcidev != NULL) {
- /* HID device (PCI or PCIE root): eval _BBN */
+ /* HID device (PCI or PCIE root): eval _SEG and _BBN */
if (__aml_search(pcidev, "_HID", 0)) {
- if (aml_evalinteger(acpi_softc, pcidev, "_BBN", 0, NULL, &res) == 0) {
+ if (aml_evalinteger(acpi_softc, pcidev, "_SEG",
+ 0, NULL, &res) == 0) {
+ addr->seg = res;
+ }
+ if (aml_evalinteger(acpi_softc, pcidev, "_BBN",
+ 0, NULL, &res) == 0) {
addr->bus = res;
break;
}
-/* $OpenBSD: dsdt.h,v 1.76 2018/07/05 19:25:38 kettenis Exp $ */
+/* $OpenBSD: dsdt.h,v 1.77 2018/08/19 08:23:47 kettenis Exp $ */
/*
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
*
struct {
uint16_t reg;
uint16_t fun;
- uint16_t dev;
- uint16_t bus;
+ uint8_t dev;
+ uint8_t bus;
+ uint16_t seg;
};
};
int aml_rdpciaddr(struct aml_node *pcidev,