diff options
| author | msaitoh <msaitoh@NetBSD.org> | 2015-10-02 05:22:49 +0000 |
|---|---|---|
| committer | msaitoh <msaitoh@NetBSD.org> | 2015-10-02 05:22:49 +0000 |
| commit | 998866035fb2f446df656a6ae9e4b0ee4ddc445c (patch) | |
| tree | d95622964c21680e079f5097dd6a20e673e3c349 /sys/dev | |
| parent | 058cde2471e6b21a2d85f267a5be1ec6b7a472b9 (diff) | |
PCI Extended Configuration stuff written by nonaka@:
- Add PCI Extended Configuration Space support into x86.
- Check register offset of pci_conf_read() in MD part. It returns (pcireg_t)-1
if it isn't accessible.
- Decode Extended Capability in PCI Extended Configuration Space.
Currently the following extended capabilities are decoded:
- Advanced Error Reporting
- Virtual Channel
- Device Serial Number
- Power Budgeting
- Root Complex Link Declaration
- Root Complex Event Collector Association
- Access Control Services
- Alternative Routing-ID Interpretation
- Address Translation Services
- Single Root IO Virtualization
- Page Request
- TPH Requester
- Latency Tolerance Reporting
- Secondary PCI Express
- Process Address Space ID
- LN Requester
- L1 PM Substates
The following extended capabilities are not decoded yet:
- Root Complex Internal Link Control
- Multi-Function Virtual Channel
- RCRB Header
- Vendor Unique
- Configuration Access Correction
- Multiple Root IO Virtualization
- Multicast
- Resizable BAR
- Dynamic Power Allocation
- Protocol Multiplexing
- Downstream Port Containment
- Precision Time Management
- M-PCIe
- Function Reading Status Queueing
- Readiness Time Reporting
- Designated Vendor-Specific
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/acpi/acpi.c | 10 | ||||
| -rw-r--r-- | sys/dev/acpi/acpi_mcfg.c | 697 | ||||
| -rw-r--r-- | sys/dev/acpi/acpi_mcfg.h | 58 | ||||
| -rw-r--r-- | sys/dev/acpi/files.acpi | 3 | ||||
| -rw-r--r-- | sys/dev/marvell/gtpci.c | 10 | ||||
| -rw-r--r-- | sys/dev/marvell/mvpex.c | 10 | ||||
| -rw-r--r-- | sys/dev/pci/pci.c | 44 | ||||
| -rw-r--r-- | sys/dev/pci/pci_subr.c | 1225 | ||||
| -rw-r--r-- | sys/dev/pci/pcireg.h | 500 | ||||
| -rw-r--r-- | sys/dev/pci/pcivar.h | 14 |
10 files changed, 2540 insertions, 31 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 3780df0d982..d55896a8f6a 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi.c,v 1.260 2015/08/18 10:41:28 christos Exp $ */ +/* $NetBSD: acpi.c,v 1.261 2015/10/02 05:22:52 msaitoh Exp $ */ /*- * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. @@ -100,7 +100,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.260 2015/08/18 10:41:28 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.261 2015/10/02 05:22:52 msaitoh Exp $"); #include "opt_acpi.h" #include "opt_pcifixup.h" @@ -118,6 +118,7 @@ __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.260 2015/08/18 10:41:28 christos Exp $"); #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> +#include <dev/acpi/acpi_mcfg.h> #include <dev/acpi/acpi_osd.h> #include <dev/acpi/acpi_pci.h> #include <dev/acpi/acpi_power.h> @@ -483,6 +484,11 @@ acpi_attach(device_t parent, device_t self, void *aux) */ acpi_build_tree(sc); + /* + * Probe MCFG table + */ + acpimcfg_probe(sc); + acpi_md_callback(sc); /* diff --git a/sys/dev/acpi/acpi_mcfg.c b/sys/dev/acpi/acpi_mcfg.c new file mode 100644 index 00000000000..87d8153ee27 --- /dev/null +++ b/sys/dev/acpi/acpi_mcfg.c @@ -0,0 +1,697 @@ +/* $NetBSD: acpi_mcfg.c,v 1.1 2015/10/02 05:22:52 msaitoh Exp $ */ + +/*- + * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.1 2015/10/02 05:22:52 msaitoh Exp $"); + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kmem.h> +#include <sys/systm.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/acpi_mcfg.h> + +#include "locators.h" + +#define EXTCONF_OFFSET(d, f, r) ((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r)) + +#define EXTCONF_SET_VALID(mb, d, f) ((mb)->valid_devs[(d)] |= __BIT((f))) +#define EXTCONF_SET_INVALID(mb, d, f) ((mb)->valid_devs[(d)] &= ~__BIT((f))) +#define EXTCONF_IS_VALID(mb, d, f) ((mb)->valid_devs[(d)] & __BIT((f))) + +struct mcfg_segment { + uint64_t ms_address; /* Base address */ + int ms_segment; /* Segment # */ + int ms_bus_start; /* Start bus # */ + int ms_bus_end; /* End bus # */ + bus_space_tag_t ms_bst; + struct mcfg_bus { + bus_space_handle_t bsh[32][8]; + uint8_t valid_devs[32]; + int valid_ndevs; + pcitag_t last_probed; + } *ms_bus; +}; + +static struct mcfg_segment *mcfg_segs; +static int mcfg_nsegs; +static ACPI_TABLE_MCFG *mcfg; +static int mcfg_inited; +static struct acpi_softc *acpi_sc; + +static const struct acpimcfg_ops mcfg_default_ops = { + .ao_validate = acpimcfg_default_validate, + + .ao_read = acpimcfg_default_read, + .ao_write = acpimcfg_default_write, +}; +static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops; + +/* + * default operations. + */ +bool +acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end) +{ + + /* Always Ok */ + return true; +} + +uint32_t +acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh, + bus_addr_t addr) +{ + + return bus_space_read_4(bst, bsh, addr); +} + +void +acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh, + bus_addr_t addr, uint32_t data) +{ + + bus_space_write_4(bst, bsh, addr, data); +} + + +/* + * Check MCFG memory region at system resource + */ +struct acpimcfg_memrange { + const char *hid; + uint64_t address; + int bus_start; + int bus_end; + bool found; +}; + +static ACPI_STATUS +acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx) +{ + struct acpimcfg_memrange *mr = ctx; + const char *type; + uint64_t size, mapaddr, mapsize; + int n; + + switch (res->Type) { + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + type = "FIXED_MEMORY32"; + mapaddr = res->Data.FixedMemory32.Address; + mapsize = res->Data.FixedMemory32.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_ADDRESS32: + /* XXX Only fixed size supported for now */ + if (res->Data.Address32.Address.AddressLength == 0 || + res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) + goto out; + + if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE) + goto out; + + if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED || + res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED) + goto out; + + type = "ADDRESS32"; + mapaddr = res->Data.Address32.Address.Minimum; + mapsize = res->Data.Address32.Address.AddressLength; + break; + +#ifdef _LP64 + case ACPI_RESOURCE_TYPE_ADDRESS64: + /* XXX Only fixed size supported for now */ + if (res->Data.Address64.Address.AddressLength == 0 || + res->Data.Address64.ProducerConsumer != ACPI_CONSUMER) + goto out; + + if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE) + goto out; + + if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED || + res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED) + goto out; + + type = "ADDRESS64"; + mapaddr = res->Data.Address64.Address.Minimum; + mapsize = res->Data.Address64.Address.AddressLength; + break; +#endif + + default: + out: + aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n", + mr->hid, res->Type); + return_ACPI_STATUS(AE_OK); + } + + aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), " + "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n", + mr->hid, res->Type, type, mapaddr, mapsize); + + if (mr->address < mapaddr || mr->address >= mapaddr + mapsize) + return_ACPI_STATUS(AE_OK); + + size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS; + + /* full map */ + if (mr->address + size <= mapaddr + mapsize) { + mr->found = true; + return_ACPI_STATUS(AE_CTRL_TERMINATE); + } + + /* partial map */ + n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS; + /* bus_start == bus_end is not allowed. */ + if (n > 1) { + mr->bus_end = mr->bus_start + n - 1; + mr->found = true; + return_ACPI_STATUS(AE_CTRL_TERMINATE); + } + + aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, " + "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64 + ", actual 0x%016" PRIx64 "\n", + mr->bus_start, mr->bus_end, mr->address, size, mapsize); + + return_ACPI_STATUS(AE_OK); +} + +static ACPI_STATUS +acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx, + void **retval) +{ + struct acpimcfg_memrange *mr = ctx; + ACPI_STATUS status; + + status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + + if (mr->found) + return_ACPI_STATUS(AE_CTRL_TERMINATE); + + aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, " + "address 0x%016" PRIx64 ": no valid region\n", mr->hid, + mr->bus_start, mr->bus_end, mr->address); + + return_ACPI_STATUS(AE_OK); +} + +static bool +acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end) +{ + static const char *system_resource_hid[] = { + "PNP0C01", /* System Board */ + "PNP0C02" /* General ID for reserving resources */ + }; + struct acpimcfg_memrange mr; + ACPI_STATUS status; + int i; + + mr.address = address; + mr.bus_start = bus_start; + mr.bus_end = *bus_end; + mr.found = false; + + for (i = 0; i < __arraycount(system_resource_hid); i++) { + mr.hid = system_resource_hid[i]; + status = AcpiGetDevices(__UNCONST(system_resource_hid[i]), + acpimcfg_check_system_resource, &mr, NULL); + if (ACPI_FAILURE(status)) + continue; + if (mr.found) { + *bus_end = mr.bus_end; + return true; + } + } + return false; +} + + +/* + * ACPI MCFG + */ +void +acpimcfg_probe(struct acpi_softc *sc) +{ + ACPI_MCFG_ALLOCATION *ama; + ACPI_STATUS status; + uint32_t offset; + int i, nsegs; + + if (acpi_sc != NULL) + panic("acpi_sc != NULL"); + acpi_sc = sc; + + status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg); + if (ACPI_FAILURE(status)) { + mcfg = NULL; + return; + } + + nsegs = 0; + offset = sizeof(ACPI_TABLE_MCFG); + ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); + for (i = 0; offset < mcfg->Header.Length; i++) { + aprint_debug_dev(sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", + ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber, + ama->Address); + nsegs++; + offset += sizeof(ACPI_MCFG_ALLOCATION); + ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, ama, offset); + } + if (nsegs == 0) { + mcfg = NULL; + return; + } + + mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP); + mcfg_nsegs = nsegs; +} + +int +acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops) +{ + ACPI_MCFG_ALLOCATION *ama; + struct mcfg_segment *seg; + uint32_t offset; + int i, n, nsegs, bus_end; + + if (mcfg == NULL) + return ENXIO; + + if (mcfg_inited) + return 0; + + if (ops != NULL) + mcfg_ops = ops; + + nsegs = 0; + offset = sizeof(ACPI_TABLE_MCFG); + ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); + for (i = 0; offset < mcfg->Header.Length; i++) { +#ifndef _LP64 + if (ama->Address >= 0x100000000ULL) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 + ": ignore (64bit address)\n", ama->PciSegment, + ama->StartBusNumber, ama->EndBusNumber, + ama->Address); + goto next; + } +#endif + /* + * Some (broken?) BIOSen have an MCFG table for an empty + * bus range. Ignore those tables. + */ + if (ama->StartBusNumber == ama->EndBusNumber) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 + ": ignore (bus %d == %d)\n", ama->PciSegment, + ama->StartBusNumber, ama->EndBusNumber, + ama->Address, ama->StartBusNumber, + ama->EndBusNumber); + goto next; + } + if (ama->StartBusNumber > ama->EndBusNumber) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 + ": ignore (bus %d > %d)\n", ama->PciSegment, + ama->StartBusNumber, ama->EndBusNumber, + ama->Address, ama->StartBusNumber, + ama->EndBusNumber); + goto next; + } + + /* Validate MCFG memory range */ + bus_end = ama->EndBusNumber; + if (mcfg_ops->ao_validate != NULL && + !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber, + &bus_end)) { + if (!acpimcfg_find_system_resource( ama->Address, + ama->StartBusNumber, &bus_end)) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, " + "address 0x%016" PRIx64 + ": ignore (invalid address)\n", + ama->PciSegment, + ama->StartBusNumber, ama->EndBusNumber, + ama->Address); + goto next; + } + } + if (ama->EndBusNumber != bus_end) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 + " -> bus %d-%d\n", ama->PciSegment, + ama->StartBusNumber, ama->EndBusNumber, + ama->Address, ama->StartBusNumber, bus_end); + } + + if (ama->PciSegment != 0) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 + ": ignore (non PCI segment 0)\n", ama->PciSegment, + ama->StartBusNumber, bus_end, ama->Address); + goto next; + } + + seg = &mcfg_segs[nsegs++]; + seg->ms_address = ama->Address; + seg->ms_segment = ama->PciSegment; + seg->ms_bus_start = ama->StartBusNumber; + seg->ms_bus_end = bus_end; + seg->ms_bst = memt; + n = seg->ms_bus_end - seg->ms_bus_start + 1; + seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP); + + next: + offset += sizeof(ACPI_MCFG_ALLOCATION); + ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, ama, offset); + } + if (nsegs == 0) + return ENOENT; + + for (i = 0; i < nsegs; i++) { + seg = &mcfg_segs[i]; + aprint_verbose_dev(acpi_sc->sc_dev, + "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", + seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end, + seg->ms_address); + } + + /* Update # of segment */ + mcfg_nsegs = nsegs; + mcfg_inited = true; + + return 0; +} + +static int +acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag) +{ + pcireg_t id; + int i; + + id = pci_conf_read(pc, tag, PCI_ID_REG); + for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) { + if (pci_conf_read(pc, tag, i) != id) + return false; + } + return true; +} + +static struct mcfg_segment * +acpimcfg_get_segment(int bus) +{ + struct mcfg_segment *seg; + int i; + + for (i = 0; i < mcfg_nsegs; i++) { + seg = &mcfg_segs[i]; + if (bus >= seg->ms_bus_start && bus <= seg->ms_bus_end) + return seg; + } + return NULL; +} + +static int +acpimcfg_device_probe(const struct pci_attach_args *pa) +{ + pci_chipset_tag_t pc = pa->pa_pc; + struct mcfg_segment *seg; + struct mcfg_bus *mb; + pcitag_t tag; + pcireg_t reg; + int bus = pa->pa_bus; + int dev = pa->pa_device; + int func = pa->pa_function; + int last_dev, last_func, end_func; + int alias = 0; + int i, j; + + seg = acpimcfg_get_segment(bus); + if (seg == NULL) + return 0; + + mb = &seg->ms_bus[bus - seg->ms_bus_start]; + tag = pci_make_tag(pc, bus, dev, func); + + /* Mark invalid between last probed device to probed device. */ + pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); + if (dev != 0 || func != 0) { + for (i = last_dev; i <= dev; i++) { + end_func = (i == dev) ? func : 8; + for (j = last_func; j < end_func; j++) { + if (i == last_dev && j == last_func) + continue; + EXTCONF_SET_INVALID(mb, i, j); + } + last_func = 0; + } + } + mb->last_probed = tag; + + /* Probe extended configuration space. */ + if (((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1) || + (alias = acpimcfg_ext_conf_is_aliased(pc, tag))) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: %03d:%02d:%d: invalid config space " + "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func, + PCI_CONF_SIZE, reg, alias ? "true" : "false"); + EXTCONF_SET_INVALID(mb, dev, func); + } else { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x)\n", + bus, dev, func, PCI_CONF_SIZE, reg); + mb->valid_ndevs++; + } + + return 0; +} + +static void +acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus) +{ + static const int wildcard[PCICF_NLOCS] = { + PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT + }; + + sc->sc_bus = bus; /* XXX */ + + pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL); +} + +int +acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus) +{ + struct pci_softc *sc = device_private(self); + struct mcfg_segment *seg = NULL; + struct mcfg_bus *mb; + bus_space_handle_t bsh; + bus_addr_t baddr; + int boff; + int last_dev, last_func; + int i, j; + int error; + + if (!mcfg_inited) + return ENXIO; + + seg = acpimcfg_get_segment(bus); + if (seg == NULL) + return ENOENT; + + boff = bus - seg->ms_bus_start; + if (seg->ms_bus[boff].valid_ndevs > 0) + return 0; + + 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); + if (error != 0) + return error; + for (i = 0; i < 32; i++) { + for (j = 0; j < 8; j++) { + error = bus_space_subregion(seg->ms_bst, bsh, + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, + &mb->bsh[i][j]); + if (error != 0) + break; + } + } + if (error != 0) + return error; + + aprint_debug("\n"); + + /* Probe extended configuration space of all devices. */ + memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); + mb->valid_ndevs = 0; + mb->last_probed = pci_make_tag(pc, bus, 0, 0); + + acpimcfg_scan_bus(sc, pc, bus); + + /* Unmap extended configration space of all dev/func. */ + bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS); + memset(mb->bsh, 0, sizeof(mb->bsh)); + + if (mb->valid_ndevs == 0) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: bus %d: no valid devices.\n", bus); + memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); + goto out; + } + + /* Mark invalid on remaining all devices. */ + pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); + for (i = last_dev; i < 32; i++) { + for (j = last_func; j < 8; j++) { + if (i == last_dev && j == last_func) { + /* Don't mark invalid to last probed device. */ + continue; + } + EXTCONF_SET_INVALID(mb, i, j); + } + last_func = 0; + } + + /* Map extended configuration space per dev/func. */ + for (i = 0; i < 32; i++) { + for (j = 0; j < 8; j++) { + if (!EXTCONF_IS_VALID(mb, i, j)) + continue; + error = bus_space_map(seg->ms_bst, + baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, + 0, &mb->bsh[i][j]); + if (error != 0) { + /* Unmap all handles when map failed. */ + do { + while (--j >= 0) { + if (!EXTCONF_IS_VALID(mb, i, j)) + continue; + bus_space_unmap(seg->ms_bst, + mb->bsh[i][j], + PCI_EXTCONF_SIZE); + } + j = 8; + } while (--i >= 0); + memset(mb->valid_devs, 0, + sizeof(mb->valid_devs)); + goto out; + } + } + } + + aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus); + for (i = 0; i < 32; i++) { + for (j = 0; j < 8; j++) { + if (EXTCONF_IS_VALID(mb, i, j)) { + aprint_debug_dev(acpi_sc->sc_dev, + "MCFG: %03d:%02d:%d\n", bus, i, j); + } + } + } + + error = 0; +out: + aprint_debug_dev(acpi_sc->sc_dev, "%s done", __func__); + + return error; +} + +int +acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data) +{ + struct mcfg_segment *seg = NULL; + struct mcfg_bus *mb; + int bus, dev, func; + + KASSERT(reg < PCI_EXTCONF_SIZE); + KASSERT((reg & 3) == 0); + + if (!mcfg_inited) { + *data = -1; + return ENXIO; + } + + pci_decompose_tag(pc, tag, &bus, &dev, &func); + + seg = acpimcfg_get_segment(bus); + if (seg == NULL) { + *data = -1; + return ERANGE; + } + + mb = &seg->ms_bus[bus - seg->ms_bus_start]; + if (!EXTCONF_IS_VALID(mb, dev, func)) { + *data = -1; + return EINVAL; + } + + *data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg); + return 0; +} + +int +acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) +{ + struct mcfg_segment *seg = NULL; + struct mcfg_bus *mb; + int bus, dev, func; + + KASSERT(reg < PCI_EXTCONF_SIZE); + KASSERT((reg & 3) == 0); + + if (!mcfg_inited) + return ENXIO; + + pci_decompose_tag(pc, tag, &bus, &dev, &func); + + seg = acpimcfg_get_segment(bus); + if (seg == NULL) + return ERANGE; + + mb = &seg->ms_bus[bus - seg->ms_bus_start]; + if (!EXTCONF_IS_VALID(mb, dev, func)) + return EINVAL; + + mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data); + return 0; +} diff --git a/sys/dev/acpi/acpi_mcfg.h b/sys/dev/acpi/acpi_mcfg.h new file mode 100644 index 00000000000..b67c360373c --- /dev/null +++ b/sys/dev/acpi/acpi_mcfg.h @@ -0,0 +1,58 @@ +/* $NetBSD: acpi_mcfg.h,v 1.1 2015/10/02 05:22:52 msaitoh Exp $ */ + +/*- + * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_DEV_ACPI_ACPI_MCFG_H +#define _SYS_DEV_ACPI_ACPI_MCFG_H + +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_conf_read(pci_chipset_tag_t, pcitag_t, int, pcireg_t *); +int acpimcfg_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); + +struct acpimcfg_ops { + /* validate MCFG memory region */ + bool (*ao_validate)(uint64_t, int, int *); + + /* override default bus_space(9) function */ + uint32_t (*ao_read)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t); + void (*ao_write)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, uint32_t); +}; + +#define ACPIMCFG_SIZE_PER_BUS (PCI_EXTCONF_SIZE * 32/*dev*/ * 8/*func*/) + +bool acpimcfg_default_validate(uint64_t, int, int *); +uint32_t acpimcfg_default_read(bus_space_tag_t, bus_space_handle_t, + bus_addr_t); +void acpimcfg_default_write(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, uint32_t); + +#endif /* _SYS_DEV_ACPI_ACPI_PCI_H */ diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index e08e4fed80d..514f27df64d 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $NetBSD: files.acpi,v 1.96 2015/09/21 12:32:06 nonaka Exp $ +# $NetBSD: files.acpi,v 1.97 2015/10/02 05:22:52 msaitoh Exp $ include "dev/acpi/acpica/files.acpica" @@ -18,6 +18,7 @@ device acpi: acpica, acpiapmbus, acpinodebus, acpiecdtbus, acpihpetbus, acpiwdrt attach acpi at acpibus file dev/acpi/acpi.c acpi file dev/acpi/acpi_debug.c acpi +file dev/acpi/acpi_mcfg.c acpi file dev/acpi/acpi_pci.c acpi file dev/acpi/acpi_pci_link.c acpi file dev/acpi/acpi_power.c acpi diff --git a/sys/dev/marvell/gtpci.c b/sys/dev/marvell/gtpci.c index 5d52cd7f866..88014b130f0 100644 --- a/sys/dev/marvell/gtpci.c +++ b/sys/dev/marvell/gtpci.c @@ -1,4 +1,4 @@ -/* $NetBSD: gtpci.c,v 1.31 2013/11/06 06:20:12 mrg Exp $ */ +/* $NetBSD: gtpci.c,v 1.32 2015/10/02 05:22:52 msaitoh Exp $ */ /* * Copyright (c) 2008, 2009 KIYOHARA Takashi * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: gtpci.c,v 1.31 2013/11/06 06:20:12 mrg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gtpci.c,v 1.32 2015/10/02 05:22:52 msaitoh Exp $"); #include "opt_pci.h" #include "pci.h" @@ -567,6 +567,9 @@ gtpci_conf_read(void *v, pcitag_t tag, int reg) struct gtpci_softc *sc = v; const pcireg_t addr = tag | reg; + if ((unsigned int)reg >= PCI_CONF_SIZE) + return -1; + GTPCI_WRITE(sc, GTPCI_CA, addr | GTPCI_CA_CONFIGEN); if ((addr | GTPCI_CA_CONFIGEN) != GTPCI_READ(sc, GTPCI_CA)) return -1; @@ -580,6 +583,9 @@ gtpci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) struct gtpci_softc *sc = v; pcireg_t addr = tag | (reg & 0xfc); + if ((unsigned int)reg >= PCI_CONF_SIZE) + return; + GTPCI_WRITE(sc, GTPCI_CA, addr | GTPCI_CA_CONFIGEN); if ((addr | GTPCI_CA_CONFIGEN) != GTPCI_READ(sc, GTPCI_CA)) return; diff --git a/sys/dev/marvell/mvpex.c b/sys/dev/marvell/mvpex.c index 2a697022ec3..f291b01ebea 100644 --- a/sys/dev/marvell/mvpex.c +++ b/sys/dev/marvell/mvpex.c @@ -1,4 +1,4 @@ -/* $NetBSD: mvpex.c,v 1.14 2015/07/28 01:57:55 knakahara Exp $ */ +/* $NetBSD: mvpex.c,v 1.15 2015/10/02 05:22:52 msaitoh Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mvpex.c,v 1.14 2015/07/28 01:57:55 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvpex.c,v 1.15 2015/10/02 05:22:52 msaitoh Exp $"); #include "opt_pci.h" #include "pci.h" @@ -507,6 +507,9 @@ mvpex_conf_read(void *v, pcitag_t tag, int reg) uint32_t stat; int bus, dev, func, pexbus, pexdev; + if ((unsigned int)reg >= PCI_EXTCONF_SIZE) + return -1; + mvpex_decompose_tag(v, tag, &bus, &dev, &func); stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_STAT); @@ -552,6 +555,9 @@ mvpex_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) uint32_t stat; int bus, dev, func, pexbus, pexdev; + if ((unsigned int)reg >= PCI_EXTCONF_SIZE) + return; + mvpex_decompose_tag(v, tag, &bus, &dev, &func); stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_STAT); diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index ec928d5909e..674e1332623 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: pci.c,v 1.148 2015/08/24 23:55:04 pooka Exp $ */ +/* $NetBSD: pci.c,v 1.149 2015/10/02 05:22:53 msaitoh Exp $ */ /* * Copyright (c) 1995, 1996, 1997, 1998 @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.148 2015/08/24 23:55:04 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.149 2015/10/02 05:22:53 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_pci.h" @@ -68,9 +68,6 @@ int pciprint(void *, const char *); #ifdef PCI_MACHDEP_ENUMERATE_BUS #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS -#else -int pci_enumerate_bus(struct pci_softc *, const int *, - int (*)(const struct pci_attach_args *), struct pci_attach_args *); #endif /* @@ -614,6 +611,43 @@ pci_msix_count(pci_chipset_tag_t pc, pcitag_t tag) } int +pci_get_ext_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, + int *offset, pcireg_t *value) +{ + pcireg_t reg; + unsigned int ofs; + + /* Only supported for PCI-express devices */ + if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, NULL, NULL)) + return 0; + + ofs = PCI_EXTCAPLIST_BASE; + reg = pci_conf_read(pc, tag, ofs); + if (reg == 0xffffffff || reg == 0) + return 0; + + for (;;) { +#ifdef DIAGNOSTIC + if ((ofs & 3) || ofs < PCI_EXTCAPLIST_BASE) + panic("%s: invalid offset %u", __func__, ofs); +#endif + if (PCI_EXTCAPLIST_CAP(reg) == capid) { + if (offset != NULL) + *offset = ofs; + if (value != NULL) + *value = reg; + return 1; + } + ofs = PCI_EXTCAPLIST_NEXT(reg); + if (ofs == 0) + break; + reg = pci_conf_read(pc, tag, ofs); + } + + return 0; +} + +int pci_find_device(struct pci_attach_args *pa, int (*match)(const struct pci_attach_args *)) { diff --git a/sys/dev/pci/pci_subr.c b/sys/dev/pci/pci_subr.c index a2353191c4a..20a8b669a66 100644 --- a/sys/dev/pci/pci_subr.c +++ b/sys/dev/pci/pci_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: pci_subr.c,v 1.134 2015/07/27 15:46:03 msaitoh Exp $ */ +/* $NetBSD: pci_subr.c,v 1.135 2015/10/02 05:22:53 msaitoh Exp $ */ /* * Copyright (c) 1997 Zubin D. Dittia. All rights reserved. @@ -40,7 +40,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pci_subr.c,v 1.134 2015/07/27 15:46:03 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_subr.c,v 1.135 2015/10/02 05:22:53 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_pci.h" @@ -56,6 +56,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_subr.c,v 1.134 2015/07/27 15:46:03 msaitoh Exp $ #include <pci.h> #include <stdbool.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #endif @@ -1841,6 +1842,26 @@ static struct { { PCI_CAP_PCIAF, "Advanced Features", pci_conf_print_pciaf_cap } }; +static int +pci_conf_find_cap(const pcireg_t *regs, int capoff, unsigned int capid, + int *offsetp) +{ + pcireg_t rval; + int off; + + for (off = PCI_CAPLIST_PTR(regs[o2i(capoff)]); + off != 0; + off = PCI_CAPLIST_NEXT(rval)) { + rval = regs[o2i(off)]; + if (capid == PCI_CAPLIST_CAP(rval)) { + if (offsetp != NULL) + *offsetp = off; + return 1; + } + } + return 0; +} + static void pci_conf_print_caplist( #ifdef _KERNEL @@ -1889,16 +1910,1177 @@ pci_conf_print_caplist( * the same. This is required because some capabilities * appear multiple times (e.g. HyperTransport capability). */ - for (off = PCI_CAPLIST_PTR(regs[o2i(capoff)]); - off != 0; - off = PCI_CAPLIST_NEXT(regs[o2i(off)])) { + if (pci_conf_find_cap(regs, capoff, i, &off)) { rval = regs[o2i(off)]; - foundcap = PCI_CAPLIST_CAP(rval); - if ((i == foundcap) - && (pci_captab[foundcap].printfunc != NULL)) - pci_captab[foundcap].printfunc(regs, off); + if (pci_captab[i].printfunc != NULL) + pci_captab[i].printfunc(regs, off); + } + } +} + +/* Extended Capability */ + +static void +pci_conf_print_aer_cap_uc(pcireg_t reg) +{ + + onoff("Undefined", reg, PCI_AER_UC_UNDEFINED); + onoff("Data Link Protocol Error", reg, PCI_AER_UC_DL_PROTOCOL_ERROR); + onoff("Surprise Down Error", reg, PCI_AER_UC_SURPRISE_DOWN_ERROR); + onoff("Poisoned TLP", reg, PCI_AER_UC_POISONED_TLP); + onoff("Flow Control Protocol Error", reg, PCI_AER_UC_FC_PROTOCOL_ERROR); + onoff("Completion Timeout", reg, PCI_AER_UC_COMPLETION_TIMEOUT); + onoff("Completer Abort", reg, PCI_AER_UC_COMPLETER_ABORT); + onoff("Unexpected Completion", reg, PCI_AER_UC_UNEXPECTED_COMPLETION); + onoff("Receiver Overflow", reg, PCI_AER_UC_RECEIVER_OVERFLOW); + onoff("Malformed TLP", reg, PCI_AER_UC_MALFORMED_TLP); + onoff("ECRC Error", reg, PCI_AER_UC_ECRC_ERROR); + onoff("Unsupported Request Error", reg, + PCI_AER_UC_UNSUPPORTED_REQUEST_ERROR); + onoff("ACS Violation", reg, PCI_AER_UC_ACS_VIOLATION); + onoff("Uncorrectable Internal Error", reg, PCI_AER_UC_INTERNAL_ERROR); + onoff("MC Blocked TLP", reg, PCI_AER_UC_MC_BLOCKED_TLP); + onoff("AtomicOp Egress BLK", reg, PCI_AER_UC_ATOMIC_OP_EGRESS_BLOCKED); + onoff("TLP Prefix Blocked Error", reg, + PCI_AER_UC_TLP_PREFIX_BLOCKED_ERROR); +} + +static void +pci_conf_print_aer_cap_cor(pcireg_t reg) +{ + + onoff("Receiver Error", reg, PCI_AER_COR_RECEIVER_ERROR); + onoff("Bad TLP", reg, PCI_AER_COR_BAD_TLP); + onoff("Bad DLLP", reg, PCI_AER_COR_BAD_DLLP); + onoff("REPLAY_NUM Rollover", reg, PCI_AER_COR_REPLAY_NUM_ROLLOVER); + onoff("Replay Timer Timeout", reg, PCI_AER_COR_REPLAY_TIMER_TIMEOUT); + onoff("Advisory Non-Fatal Error", reg, PCI_AER_COR_ADVISORY_NF_ERROR); + onoff("Corrected Internal Error", reg, PCI_AER_COR_INTERNAL_ERROR); + onoff("Header Log Overflow", reg, PCI_AER_COR_HEADER_LOG_OVERFLOW); +} + +static void +pci_conf_print_aer_cap_control(pcireg_t reg, bool *tlp_prefix_log) +{ + + printf(" First Error Pointer: 0x%04x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_AER_FIRST_ERROR_PTR)); + onoff("ECRC Generation Capable", reg, PCI_AER_ECRC_GEN_CAPABLE); + onoff("ECRC Generation Enable", reg, PCI_AER_ECRC_GEN_ENABLE); + onoff("ECRC Check Capable", reg, PCI_AER_ECRC_CHECK_CAPABLE); + onoff("ECRC Check Enab", reg, PCI_AER_ECRC_CHECK_ENABLE); + onoff("Multiple Header Recording Capable", reg, + PCI_AER_MULT_HDR_CAPABLE); + onoff("Multiple Header Recording Enable", reg, PCI_AER_MULT_HDR_ENABLE); + + /* This bit is RsvdP if the End-End TLP Prefix Supported bit is Clear */ + if (!tlp_prefix_log) + return; + onoff("TLP Prefix Log Present", reg, PCI_AER_TLP_PREFIX_LOG_PRESENT); + *tlp_prefix_log = (reg & PCI_AER_TLP_PREFIX_LOG_PRESENT) ? true : false; +} + +static void +pci_conf_print_aer_cap_rooterr_cmd(pcireg_t reg) +{ + + onoff("Correctable Error Reporting Enable", reg, + PCI_AER_ROOTERR_COR_ENABLE); + onoff("Non-Fatal Error Reporting Enable", reg, + PCI_AER_ROOTERR_NF_ENABLE); + onoff("Fatal Error Reporting Enable", reg, PCI_AER_ROOTERR_F_ENABLE); +} + +static void +pci_conf_print_aer_cap_rooterr_status(pcireg_t reg) +{ + + onoff("ERR_COR Received", reg, PCI_AER_ROOTERR_COR_ERR); + onoff("Multiple ERR_COR Received", reg, PCI_AER_ROOTERR_MULTI_COR_ERR); + onoff("ERR_FATAL/NONFATAL_ERR Received", reg, PCI_AER_ROOTERR_UC_ERR); + onoff("Multiple ERR_FATAL/NONFATAL_ERR Received", reg, + PCI_AER_ROOTERR_MULTI_UC_ERR); + onoff("First Uncorrectable Fatal", reg, PCI_AER_ROOTERR_FIRST_UC_FATAL); + onoff("Non-Fatal Error Messages Received", reg, PCI_AER_ROOTERR_NF_ERR); + onoff("Fatal Error Messages Received", reg, PCI_AER_ROOTERR_F_ERR); + printf(" Advanced Error Interrupt Message Number: 0x%u\n", + (pcireg_t)__SHIFTOUT(reg, PCI_AER_ROOTERR_INT_MESSAGE)); +} + +static void +pci_conf_print_aer_cap_errsrc_id(pcireg_t reg) +{ + + printf(" Correctable Source ID: 0x%04x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_AER_ERRSRC_ID_ERR_COR)); + printf(" ERR_FATAL/NONFATAL Source ID: 0x%04x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_AER_ERRSRC_ID_ERR_UC)); +} + +static void +pci_conf_print_aer_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + int pcie_capoff; + int pcie_devtype = -1; + bool tlp_prefix_log = false; + + if (pci_conf_find_cap(regs, capoff, PCI_CAP_PCIEXPRESS, &pcie_capoff)) { + reg = regs[o2i(pcie_capoff)]; + pcie_devtype = reg & PCIE_XCAP_TYPE_MASK; + /* PCIe DW9 to DW14 is for PCIe 2.0 and newer */ + if (__SHIFTOUT(reg, PCIE_XCAP_VER_MASK) >= 2) { + reg = regs[o2i(pcie_capoff + PCIE_DCAP2)]; + /* End-End TLP Prefix Supported */ + if (reg & PCIE_DCAP2_EETLP_PREF) { + tlp_prefix_log = true; + } } } + + printf("\n Advanced Error Reporting Register\n"); + + reg = regs[o2i(extcapoff + PCI_AER_UC_STATUS)]; + printf(" Uncorrectable Error Status register: 0x%08x\n", reg); + pci_conf_print_aer_cap_uc(reg); + reg = regs[o2i(extcapoff + PCI_AER_UC_MASK)]; + printf(" Uncorrectable Error Mask register: 0x%08x\n", reg); + pci_conf_print_aer_cap_uc(reg); + reg = regs[o2i(extcapoff + PCI_AER_UC_SEVERITY)]; + printf(" Uncorrectable Error Severity register: 0x%08x\n", reg); + pci_conf_print_aer_cap_uc(reg); + + reg = regs[o2i(extcapoff + PCI_AER_COR_STATUS)]; + printf(" Correctable Error Status register: 0x%08x\n", reg); + pci_conf_print_aer_cap_cor(reg); + reg = regs[o2i(extcapoff + PCI_AER_COR_MASK)]; + printf(" Correctable Error Mask register: 0x%08x\n", reg); + pci_conf_print_aer_cap_cor(reg); + + reg = regs[o2i(extcapoff + PCI_AER_CAP_CONTROL)]; + printf(" Advanced Error Capabilities and Control register: 0x%08x\n", + reg); + pci_conf_print_aer_cap_control(reg, &tlp_prefix_log); + reg = regs[o2i(extcapoff + PCI_AER_HEADER_LOG)]; + printf(" Header Log register:\n"); + pci_conf_print_regs(regs, extcapoff + PCI_AER_HEADER_LOG, + extcapoff + PCI_AER_ROOTERR_CMD); + + switch (pcie_devtype) { + case PCIE_XCAP_TYPE_ROOT: /* Root Port of PCI Express Root Complex */ + case PCIE_XCAP_TYPE_ROOT_EVNTC: /* Root Complex Event Collector */ + reg = regs[o2i(extcapoff + PCI_AER_ROOTERR_CMD)]; + printf(" Root Error Command register: 0x%08x\n", reg); + pci_conf_print_aer_cap_rooterr_cmd(reg); + reg = regs[o2i(extcapoff + PCI_AER_ROOTERR_STATUS)]; + printf(" Root Error Status register: 0x%08x\n", reg); + pci_conf_print_aer_cap_rooterr_status(reg); + + reg = regs[o2i(extcapoff + PCI_AER_ERRSRC_ID)]; + printf(" Error Source Identification: 0x%04x\n", reg); + pci_conf_print_aer_cap_errsrc_id(reg); + break; + } + + if (tlp_prefix_log) { + reg = regs[o2i(extcapoff + PCI_AER_TLP_PREFIX_LOG)]; + printf(" TLP Prefix Log register: 0x%08x\n", reg); + } +} + +static void +pci_conf_print_vc_cap_arbtab(const pcireg_t *regs, int off, const char *name, + pcireg_t parbsel, int parbsize) +{ + pcireg_t reg; + int num = 16 << parbsel; + int num_per_reg = sizeof(pcireg_t) / parbsize; + int i, j; + + /* First, dump the table */ + for (i = 0; i < num; i += num_per_reg) { + reg = regs[o2i(off + i / num_per_reg)]; + printf(" %s Arbitration Table: 0x%08x\n", name, reg); + } + /* And then, decode each entry */ + for (i = 0; i < num; i += num_per_reg) { + reg = regs[o2i(off + i / num_per_reg)]; + for (j = 0; j < num_per_reg; j++) + printf(" Phase[%d]: %d\n", j, reg); + } +} + +static void +pci_conf_print_vc_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, n; + int parbtab, parbsize; + pcireg_t parbsel; + int varbtab, varbsize; + pcireg_t varbsel; + int i, count; + + printf("\n Virtual Channel Register\n"); + reg = regs[o2i(extcapoff + PCI_VC_CAP1)]; + printf(" Port VC Capability register 1: 0x%08x\n", reg); + count = __SHIFTOUT(reg, PCI_VC_CAP1_EXT_COUNT); + printf(" Extended VC Count: %d\n", count); + n = __SHIFTOUT(reg, PCI_VC_CAP1_LOWPRI_EXT_COUNT); + printf(" Low Priority Extended VC Count: %u\n", n); + n = __SHIFTOUT(reg, PCI_VC_CAP1_REFCLK); + printf(" Reference Clock: %s\n", + (n == PCI_VC_CAP1_REFCLK_100NS) ? "100" : "unknown"); + parbsize = 1 << __SHIFTOUT(reg, PCI_VC_CAP1_PORT_ARB_TABLE_SIZE); + printf(" Port Arbitration Table Entry Size: %dbit\n", parbsize); + + reg = regs[o2i(extcapoff + PCI_VC_CAP2)]; + printf(" Port VC Capability register 2: 0x%08x\n", reg); + onoff("Hardware fixed arbitration scheme", + reg, PCI_VC_CAP2_ARB_CAP_HW_FIXED_SCHEME); + onoff("WRR arbitration with 32 phases", + reg, PCI_VC_CAP2_ARB_CAP_WRR_32); + onoff("WRR arbitration with 64 phases", + reg, PCI_VC_CAP2_ARB_CAP_WRR_64); + onoff("WRR arbitration with 128 phases", + reg, PCI_VC_CAP2_ARB_CAP_WRR_128); + varbtab = __SHIFTOUT(reg, PCI_VC_CAP2_ARB_TABLE_OFFSET); + printf(" VC Arbitration Table Offset: 0x%x\n", varbtab); + + reg = regs[o2i(extcapoff + PCI_VC_CONTROL)] & 0xffff; + printf(" Port VC Control register: 0x%04x\n", reg); + varbsel = __SHIFTOUT(reg, PCI_VC_CONTROL_VC_ARB_SELECT); + printf(" VC Arbitration Select: 0x%x\n", varbsel); + + reg = regs[o2i(extcapoff + PCI_VC_STATUS)] >> 16; + printf(" Port VC Status register: 0x%04x\n", reg); + onoff("VC Arbitration Table Status", + reg, PCI_VC_STATUS_LOAD_VC_ARB_TABLE); + + for (i = 0; i < count + 1; i++) { + reg = regs[o2i(extcapoff + PCI_VC_RESOURCE_CAP(i))]; + printf(" VC number %d\n", i); + printf(" VC Resource Capability Register: 0x%08x\n", reg); + onoff(" Non-configurable Hardware fixed arbitration scheme", + reg, PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_HW_FIXED_SCHEME); + onoff(" WRR arbitration with 32 phases", + reg, PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_32); + onoff(" WRR arbitration with 64 phases", + reg, PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_64); + onoff(" WRR arbitration with 128 phases", + reg, PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_128); + onoff(" Time-based WRR arbitration with 128 phases", + reg, PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_TWRR_128); + onoff(" WRR arbitration with 256 phases", + reg, PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_256); + onoff(" Advanced Packet Switching", + reg, PCI_VC_RESOURCE_CAP_ADV_PKT_SWITCH); + onoff(" Reject Snoop Transaction", + reg, PCI_VC_RESOURCE_CAP_REJCT_SNOOP_TRANS); + n = __SHIFTOUT(reg, PCI_VC_RESOURCE_CAP_MAX_TIME_SLOTS) + 1; + printf(" Maximum Time Slots: %d\n", n); + parbtab = reg >> PCI_VC_RESOURCE_CAP_PORT_ARB_TABLE_OFFSET_S; + printf(" Port Arbitration Table offset: 0x%02x\n", + parbtab); + + reg = regs[o2i(extcapoff + PCI_VC_RESOURCE_CTL(i))]; + printf(" VC Resource Control Register: 0x%08x\n", reg); + printf(" TC/VC Map: %02x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_VC_RESOURCE_CTL_TCVC_MAP)); + /* + * The load Port Arbitration Table bit is used to update + * the Port Arbitration logic and it's always 0 on read, so + * we don't print it. + */ + parbsel = __SHIFTOUT(reg, PCI_VC_RESOURCE_CTL_PORT_ARB_SELECT); + printf(" Port Arbitration Select: %x\n", parbsel); + n = __SHIFTOUT(reg, PCI_VC_RESOURCE_CTL_VC_ID); + printf(" VC ID %d\n", n); + onoff(" VC Enable", reg, PCI_VC_RESOURCE_CTL_VC_ENABLE); + + reg = regs[o2i(extcapoff + PCI_VC_RESOURCE_STA(i))] >> 16; + printf(" VC Resource Status Register: 0x%08x\n", reg); + onoff(" Port Arbitration Table Status", + reg, PCI_VC_RESOURCE_STA_PORT_ARB_TABLE); + onoff(" VC Negotiation Pending", + reg, PCI_VC_RESOURCE_STA_VC_NEG_PENDING); + + if ((parbtab != 0) && (parbsel != 0)) + pci_conf_print_vc_cap_arbtab(regs, extcapoff + parbtab, + "Port", parbsel, parbsize); + } + + varbsize = 8; + if ((varbtab != 0) && (varbsel != 0)) + pci_conf_print_vc_cap_arbtab(regs, extcapoff + varbtab, + " VC", varbsel, varbsize); +} + +static const char * +pci_conf_print_pwrbdgt_base_power(uint8_t reg) +{ + + switch (reg) { + case 0xf0: + return "250W"; + case 0xf1: + return "275W"; + case 0xf2: + return "300W"; + default: + return "Unknown"; + } +} + +static const char * +pci_conf_print_pwrbdgt_data_scale(uint8_t reg) +{ + + switch (reg) { + case 0x00: + return "1.0x"; + case 0x01: + return "0.1x"; + case 0x02: + return "0.01x"; + case 0x03: + return "0.001x"; + default: + return "wrong value!"; + } +} + +static const char * +pci_conf_print_pwrbdgt_type(uint8_t reg) +{ + + switch (reg) { + case 0x00: + return "PME Aux"; + case 0x01: + return "Auxilary"; + case 0x02: + return "Idle"; + case 0x03: + return "Sustained"; + case 0x07: + return "Maximun"; + default: + return "Unknown"; + } +} + +static const char * +pci_conf_print_pwrbdgt_pwrrail(uint8_t reg) +{ + + switch (reg) { + case 0x00: + return "Power(12V)"; + case 0x01: + return "Power(3.3V)"; + case 0x02: + return "Power(1.5V or 1.8V)"; + case 0x07: + return "Thermal"; + default: + return "Unknown"; + } +} + +static void +pci_conf_print_pwrbdgt_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + + printf("\n Power Budget Register\n"); + + reg = regs[o2i(extcapoff + PCI_PWRBDGT_DSEL)]; + printf(" Data Select register: 0x%08x\n", reg); + + reg = regs[o2i(extcapoff + PCI_PWRBDGT_DATA)]; + printf(" Data register: 0x%08x\n", reg); + printf(" Base Power: %s\n", + pci_conf_print_pwrbdgt_base_power((uint8_t)reg)); + printf(" Data Scale: %s\n", + pci_conf_print_pwrbdgt_data_scale( + (uint8_t)(__SHIFTOUT(reg, PCI_PWRBDGT_DATA_SCALE)))); + printf(" PM Sub State: 0x%hhx\n", + (uint8_t)__SHIFTOUT(reg, PCI_PWRBDGT_PM_SUBSTAT)); + printf(" PM State: D%u\n", + (unsigned int)__SHIFTOUT(reg, PCI_PWRBDGT_PM_STAT)); + printf(" Type: %s\n", + pci_conf_print_pwrbdgt_type( + (uint8_t)(__SHIFTOUT(reg, PCI_PWRBDGT_TYPE)))); + printf(" Power Rail: %s\n", + pci_conf_print_pwrbdgt_pwrrail( + (uint8_t)(__SHIFTOUT(reg, PCI_PWRBDGT_PWRRAIL)))); + + reg = regs[o2i(extcapoff + PCI_PWRBDGT_CAP)]; + printf(" Power Budget Capability register: 0x%08x\n", reg); + onoff("System Allocated", + reg, PCI_PWRBDGT_CAP_SYSALLOC); +} + +static const char * +pci_conf_print_rclink_dcl_cap_elmtype(unsigned char type) +{ + + switch (type) { + case 0x00: + return "Configuration Space Element"; + case 0x01: + return "System Egress Port or internal sink (memory)"; + case 0x02: + return "Internal Root Complex Link"; + default: + return "Unknown"; + } +} + +static void +pci_conf_print_rclink_dcl_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + unsigned char nent, linktype; + int i; + + printf("\n Root Complex Link Declaration\n"); + + reg = regs[o2i(extcapoff + PCI_RCLINK_DCL_ESDESC)]; + printf(" Element Self Description Register: 0x%08x\n", reg); + printf(" Element Type: %s\n", + pci_conf_print_rclink_dcl_cap_elmtype((unsigned char)reg)); + nent = __SHIFTOUT(reg, PCI_RCLINK_DCL_ESDESC_NUMLINKENT); + printf(" Number of Link Entries: %hhu\n", nent); + printf(" Component ID: %hhu\n", + (uint8_t)__SHIFTOUT(reg, PCI_RCLINK_DCL_ESDESC_COMPID)); + printf(" Port Number: %hhu\n", + (uint8_t)__SHIFTOUT(reg, PCI_RCLINK_DCL_ESDESC_PORTNUM)); + for (i = 0; i < nent; i++) { + reg = regs[o2i(extcapoff + PCI_RCLINK_DCL_LINKDESC(i))]; + printf(" Link Description Register: 0x%08x\n", reg); + onoff("Link Valid", reg,PCI_RCLINK_DCL_LINKDESC_LVALID); + linktype = reg & PCI_RCLINK_DCL_LINKDESC_LTYPE; + onoff2("Link Type", reg, PCI_RCLINK_DCL_LINKDESC_LTYPE, + "Configuration Space", "Memory-Mapped Space"); + onoff("Associated RCRB Header", reg, + PCI_RCLINK_DCL_LINKDESC_ARCRBH); + printf(" Target Component ID: %hhu\n", + (unsigned char)__SHIFTOUT(reg, + PCI_RCLINK_DCL_LINKDESC_TCOMPID)); + printf(" Target Port Number: %hhu\n", + (unsigned char)__SHIFTOUT(reg, + PCI_RCLINK_DCL_LINKDESC_TPNUM)); + + if (linktype == 0) { + /* Memory-Mapped Space */ + reg = regs[o2i(extcapoff + + PCI_RCLINK_DCL_LINKADDR_LT0_LO(i))]; + printf(" Link Address Low Register: 0x%08x\n", reg); + reg = regs[o2i(extcapoff + + PCI_RCLINK_DCL_LINKADDR_LT0_HI(i))]; + printf(" Link Address High Register: 0x%08x\n",reg); + } else { + unsigned int nb; + pcireg_t lo, hi; + + /* Configuration Space */ + lo = regs[o2i(extcapoff + + PCI_RCLINK_DCL_LINKADDR_LT1_LO(i))]; + printf(" Configuration Space Low Register: 0x%08x" + "\n", lo); + hi = regs[o2i(extcapoff + + PCI_RCLINK_DCL_LINKADDR_LT1_HI(i))]; + printf(" Configuration Space High Register: 0x%08x" + "\n", hi); + nb = __SHIFTOUT(lo, PCI_RCLINK_DCL_LINKADDR_LT1_N); + printf(" N: %u\n", nb); + printf(" Func: %hhu\n", + (unsigned char)__SHIFTOUT(lo, + PCI_RCLINK_DCL_LINKADDR_LT1_FUNC)); + printf(" Dev: %hhu\n", + (unsigned char)__SHIFTOUT(lo, + PCI_RCLINK_DCL_LINKADDR_LT1_DEV)); + printf(" Bus: %hhu\n", + (unsigned char)__SHIFTOUT(lo, + PCI_RCLINK_DCL_LINKADDR_LT1_BUS(nb))); + lo &= PCI_RCLINK_DCL_LINKADDR_LT1_BAL(i); + printf(" Configuration Space Base Address: 0x%016" + PRIx64 "\n", ((uint64_t)hi << 32) + lo); + } + } +} + +/* XXX pci_conf_print_rclink_ctl_cap */ + +static void +pci_conf_print_rcec_assoc_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + + printf("\n Root Complex Event Collector Association\n"); + + reg = regs[o2i(extcapoff + PCI_RCEC_ASSOC_ASSOCBITMAP)]; + printf(" Association Bitmap for Root Complex Integrated Devices:" + " 0x%08x\n", reg); +} + +/* XXX pci_conf_print_mfvc_cap */ +/* XXX pci_conf_print_vc2_cap */ +/* XXX pci_conf_print_rcrb_cap */ +/* XXX pci_conf_print_vendor_cap */ +/* XXX pci_conf_print_cac_cap */ + +static void +pci_conf_print_acs_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, cap, ctl; + unsigned int size, i; + + printf("\n Access Control Services\n"); + + reg = regs[o2i(extcapoff + PCI_ACS_CAP)]; + cap = reg & 0xffff; + ctl = reg >> 16; + printf(" ACS Capability register: 0x%08x\n", cap); + onoff("ACS Source Validation", cap, PCI_ACS_CAP_V); + onoff("ACS Transaction Blocking", cap, PCI_ACS_CAP_B); + onoff("ACS P2P Request Redirect", cap, PCI_ACS_CAP_R); + onoff("ACS P2P Completion Redirect", cap, PCI_ACS_CAP_C); + onoff("ACS Upstream Forwarding", cap, PCI_ACS_CAP_U); + onoff("ACS Egress Control", cap, PCI_ACS_CAP_E); + onoff("ACS Direct Translated P2P", cap, PCI_ACS_CAP_T); + size = __SHIFTOUT(cap, PCI_ACS_CAP_ECVSIZE); + if (size == 0) + size = 256; + printf(" Egress Control Vector Size: %u\n", size); + printf(" ACS Control register: 0x%08x\n", ctl); + onoff("ACS Source Validation Enable", ctl, PCI_ACS_CTL_V); + onoff("ACS Transaction Blocking Enable", ctl, PCI_ACS_CTL_B); + onoff("ACS P2P Request Redirect Enable", ctl, PCI_ACS_CTL_R); + onoff("ACS P2P Completion Redirect Enable", ctl, PCI_ACS_CTL_C); + onoff("ACS Upstream Forwarding Enable", ctl, PCI_ACS_CTL_U); + onoff("ACS Egress Control Enable", ctl, PCI_ACS_CTL_E); + onoff("ACS Direct Translated P2P Enable", ctl, PCI_ACS_CTL_T); + + /* + * If the P2P Egress Control Capability bit is 0, ignore the Egress + * Control vector. + */ + if ((cap & PCI_ACS_CAP_E) == 0) + return; + for (i = 0; i < size; i += 32) + printf(" Egress Control Vector [%u..%u]: %x\n", i + 31, + i, regs[o2i(extcapoff + PCI_ACS_ECV + (i / 32) * 4 )]); +} + +static void +pci_conf_print_ari_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, cap, ctl; + + printf("\n Alternative Routing-ID Interpretation Register\n"); + + reg = regs[o2i(extcapoff + PCI_ARI_CAP)]; + cap = reg & 0xffff; + ctl = reg >> 16; + printf(" Capability register: 0x%08x\n", cap); + onoff("MVFC Function Groups Capability", reg, PCI_ARI_CAP_M); + onoff("ACS Function Groups Capability", reg, PCI_ARI_CAP_A); + printf(" Next Function Number: %u\n", + (unsigned int)__SHIFTOUT(reg, PCI_ARI_CAP_NXTFN)); + printf(" Control register: 0x%08x\n", ctl); + onoff("MVFC Function Groups Enable", reg, PCI_ARI_CTL_M); + onoff("ACS Function Groups Enable", reg, PCI_ARI_CTL_A); + printf(" Function Group: %u\n", + (unsigned int)__SHIFTOUT(reg, PCI_ARI_CTL_FUNCGRP)); +} + +static void +pci_conf_print_ats_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, cap, ctl; + unsigned int num; + + printf("\n Address Translation Services\n"); + + reg = regs[o2i(extcapoff + PCI_ARI_CAP)]; + cap = reg & 0xffff; + ctl = reg >> 16; + printf(" Capability register: 0x%04x\n", cap); + num = __SHIFTOUT(reg, PCI_ATS_CAP_INVQDEPTH); + if (num == 0) + num = 32; + printf(" Invalidate Queue Depth: %u\n", num); + onoff("Page Aligned Request", reg, PCI_ATS_CAP_PALIGNREQ); + + printf(" Control register: 0x%04x\n", ctl); + printf(" Smallest Translation Unit: %u\n", + (unsigned int)__SHIFTOUT(reg, PCI_ATS_CTL_STU)); + onoff("Enable", reg, PCI_ATS_CTL_EN); +} + +static void +pci_conf_print_sernum_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t lo, hi; + + printf("\n Device Serial Number Register\n"); + + lo = regs[o2i(extcapoff + PCI_SERIAL_LOW)]; + hi = regs[o2i(extcapoff + PCI_SERIAL_HIGH)]; + printf(" Serial Number: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", + hi >> 24, (hi >> 16) & 0xff, (hi >> 8) & 0xff, hi & 0xff, + lo >> 24, (lo >> 16) & 0xff, (lo >> 8) & 0xff, lo & 0xff); +} + +static void +pci_conf_print_sriov_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + char buf[sizeof("99999 MB")]; + pcireg_t reg; + pcireg_t total_vfs; + int i; + bool first; + + printf("\n Single Root IO Virtualization Register\n"); + + reg = regs[o2i(extcapoff + PCI_SRIOV_CAP)]; + printf(" Capabilities register: 0x%08x\n", reg); + onoff("VF Migration Capable", reg, PCI_SRIOV_CAP_VF_MIGRATION); + onoff("ARI Capable Hierarchy Preserved", reg, + PCI_SRIOV_CAP_ARI_CAP_HIER_PRESERVED); + if (reg & PCI_SRIOV_CAP_VF_MIGRATION) { + printf(" VF Migration Interrupt Message Number: 0x%u\n", + (pcireg_t)__SHIFTOUT(reg, + PCI_SRIOV_CAP_VF_MIGRATION_INTMSG_N)); + } + + reg = regs[o2i(extcapoff + PCI_SRIOV_CTL)] & 0xffff; + printf(" Control register: 0x%04x\n", reg); + onoff("VF Enable", reg, PCI_SRIOV_CTL_VF_ENABLE); + onoff("VF Migration Enable", reg, PCI_SRIOV_CTL_VF_MIGRATION_SUPPORT); + onoff("VF Migration Interrupt Enable", reg, + PCI_SRIOV_CTL_VF_MIGRATION_INT_ENABLE); + onoff("VF Memory Space Enable", reg, PCI_SRIOV_CTL_VF_MSE); + onoff("ARI Capable Hierarchy", reg, PCI_SRIOV_CTL_ARI_CAP_HIER); + + reg = regs[o2i(extcapoff + PCI_SRIOV_STA)] >> 16; + printf(" Status register: 0x%04x\n", reg); + onoff("VF Migration Status", reg, PCI_SRIOV_STA_VF_MIGRATION); + + reg = regs[o2i(extcapoff + PCI_SRIOV_INITIAL_VFS)] & 0xffff; + printf(" InitialVFs register: 0x%04x\n", reg); + total_vfs = reg = regs[o2i(extcapoff + PCI_SRIOV_TOTAL_VFS)] >> 16; + printf(" TotalVFs register: 0x%04x\n", reg); + reg = regs[o2i(extcapoff + PCI_SRIOV_NUM_VFS)] & 0xffff; + printf(" NumVFs register: 0x%04x\n", reg); + + reg = regs[o2i(extcapoff + PCI_SRIOV_FUNC_DEP_LINK)] >> 16; + printf(" Function Dependency Link register: 0x%04x\n", reg); + + reg = regs[o2i(extcapoff + PCI_SRIOV_VF_OFF)] & 0xffff; + printf(" First VF Offset register: 0x%04x\n", reg); + reg = regs[o2i(extcapoff + PCI_SRIOV_VF_STRIDE)] >> 16; + printf(" VF Stride register: 0x%04x\n", reg); + + reg = regs[o2i(extcapoff + PCI_SRIOV_PAGE_CAP)]; + printf(" Supported Page Sizes register: 0x%08x\n", reg); + printf(" Supported Page Size:"); + for (i = 0, first = true; i < 32; i++) { + if (reg & __BIT(i)) { +#ifdef _KERNEL + format_bytes(buf, sizeof(buf), 1LL << (i + 12)); +#else + humanize_number(buf, sizeof(buf), 1LL << (i + 12), "B", + HN_AUTOSCALE, 0); +#endif + printf("%s %s", first ? "" : ",", buf); + first = false; + } + } + printf("\n"); + + reg = regs[o2i(extcapoff + PCI_SRIOV_PAGE_SIZE)]; + printf(" System Page Sizes register: 0x%08x\n", reg); + printf(" Page Size: "); + if (reg != 0) { +#ifdef _KERNEL + format_bytes(buf, sizeof(buf), 1LL << (ffs(reg) + 12)); +#else + humanize_number(buf, sizeof(buf), 1LL << (ffs(reg) + 12), "B", + HN_AUTOSCALE, 0); +#endif + printf("%s", buf); + } else { + printf("unknown"); + } + printf("\n"); + + for (i = 0; i < 6; i++) { + reg = regs[o2i(extcapoff + PCI_SRIOV_BAR(i))]; + printf(" VF BAR%d register: 0x%08x\n", i, reg); + } + + if (total_vfs > 0) { + reg = regs[o2i(extcapoff + PCI_SRIOV_VF_MIG_STA_AR)]; + printf(" VF Migration State Array Offset register: 0x%08x\n", + reg); + printf(" VF Migration State Offset: 0x%08x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_SRIOV_VF_MIG_STA_OFFSET)); + i = __SHIFTOUT(reg, PCI_SRIOV_VF_MIG_STA_BIR); + printf(" VF Migration State BIR: "); + if (i >= 0 && i <= 5) { + printf("BAR%d", i); + } else { + printf("unknown BAR (%d)", i); + } + printf("\n"); + } +} + +/* XXX pci_conf_print_mriov_cap */ +/* XXX pci_conf_print_multicast_cap */ + +static void +pci_conf_print_page_req_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, ctl, sta; + + printf("\n Page Request\n"); + + reg = regs[o2i(extcapoff + PCI_PAGE_REQ_CTL)]; + ctl = reg & 0xffff; + sta = reg >> 16; + printf(" Control Register: 0x%04x\n", ctl); + onoff("Enalbe", reg, PCI_PAGE_REQ_CTL_E); + onoff("Reset", reg, PCI_PAGE_REQ_CTL_R); + + printf(" Status Register: 0x%04x\n", sta); + onoff("Response Failure", reg, PCI_PAGE_REQ_STA_RF); + onoff("Unexpected Page Request Group Index", reg, + PCI_PAGE_REQ_STA_UPRGI); + onoff("Stopped", reg, PCI_PAGE_REQ_STA_S); + + reg = regs[o2i(extcapoff + PCI_PAGE_REQ_OUTSTCAPA)]; + printf(" Outstanding Page Request Capacity: %u\n", reg); + reg = regs[o2i(extcapoff + PCI_PAGE_REQ_OUTSTALLOC)]; + printf(" Outstanding Page Request Allocation: %u\n", reg); +} + +/* XXX pci_conf_print_amd_cap */ +/* XXX pci_conf_print_resize_bar_cap */ +/* XXX pci_conf_print_dpa_cap */ + +static const char * +pci_conf_print_tph_req_cap_sttabloc(unsigned char val) +{ + + switch (val) { + case 0x0: + return "Not Present"; + case 0x1: + return "in the TPH Requester Capability Structure"; + case 0x2: + return "in the MSI-X Table"; + default: + return "Unknown"; + } +} + +static void +pci_conf_print_tph_req_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + int size, i, j; + + printf("\n TPH Requester Extended Capability\n"); + + reg = regs[o2i(extcapoff + PCI_TPH_REQ_CAP)]; + printf(" TPH Requester Capabililty register: 0x%08x\n", reg); + onoff("No ST Mode Supported", reg, PCI_TPH_REQ_CAP_NOST); + onoff("Interrupt Vector Mode Supported", reg, PCI_TPH_REQ_CAP_INTVEC); + onoff("Device Specific Mode Supported", reg, PCI_TPH_REQ_CAP_DEVSPEC); + onoff("Extend TPH Reqester Supported", reg, PCI_TPH_REQ_CAP_XTPHREQ); + printf(" ST Table Location: %s\n", + pci_conf_print_tph_req_cap_sttabloc( + (unsigned char)__SHIFTOUT(reg, PCI_TPH_REQ_CAP_STTBLLOC))); + size = __SHIFTOUT(reg, PCI_TPH_REQ_CAP_STTBLSIZ) + 1; + printf(" ST Table Size: %d\n", size); + for (i = 0; i < size ; i += 2) { + reg = regs[o2i(extcapoff + PCI_TPH_REQ_STTBL + i / 2)]; + for (j = 0; j < 2 ; j++) { + uint16_t entry = reg; + + if (j != 0) + entry >>= 16; + entry &= 0xffff; + printf(" TPH ST Table Entry (%d): 0x%04hx\n", + i + j, entry); + } + } +} + +static void +pci_conf_print_ltr_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + + printf("\n Latency Tolerance Reporting\n"); + reg = regs[o2i(extcapoff + PCI_LTR_MAXSNOOPLAT)] & 0xffff; + printf(" Max Snoop Latency Register: 0x%04x\n", reg); + printf(" Max Snoop LatencyValue: %u\n", + (pcireg_t)__SHIFTOUT(reg, PCI_LTR_MAXSNOOPLAT_VAL)); + printf(" Max Snoop LatencyScale: %uns\n", + PCI_LTR_SCALETONS(__SHIFTOUT(reg, PCI_LTR_MAXSNOOPLAT_SCALE))); + reg = regs[o2i(extcapoff + PCI_LTR_MAXNOSNOOPLAT)] >> 16; + printf(" Max No-Snoop Latency Register: 0x%04x\n", reg); + printf(" Max No-Snoop LatencyValue: %u\n", + (pcireg_t)__SHIFTOUT(reg, PCI_LTR_MAXNOSNOOPLAT_VAL)); + printf(" Max No-Snoop LatencyScale: %uns\n", + PCI_LTR_SCALETONS(__SHIFTOUT(reg, PCI_LTR_MAXNOSNOOPLAT_SCALE))); +} + +static void +pci_conf_print_sec_pcie_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + int pcie_capoff; + pcireg_t reg; + int i, maxlinkwidth; + + printf("\n Secondary PCI Express Register\n"); + + reg = regs[o2i(extcapoff + PCI_SECPCIE_LCTL3)]; + printf(" Link Control 3 register: 0x%08x\n", reg); + onoff("Perform Equalization", reg, PCI_SECPCIE_LCTL3_PERFEQ); + onoff("Link Equalization Request Interrupt Enable", + reg, PCI_SECPCIE_LCTL3_LINKEQREQ_IE); + + reg = regs[o2i(extcapoff + PCI_SECPCIE_LANEERR_STA)]; + printf(" Lane Error Status register: 0x%08x\n", reg); + + /* Get Max Link Width */ + if (pci_conf_find_cap(regs, capoff, PCI_CAP_PCIEXPRESS, &pcie_capoff)){ + reg = regs[o2i(pcie_capoff + PCIE_LCAP)]; + maxlinkwidth = __SHIFTOUT(reg, PCIE_LCAP_MAX_WIDTH); + } else { + printf("error: falied to get PCIe capablity\n"); + return; + } + for (i = 0; i < maxlinkwidth; i++) { + reg = regs[o2i(extcapoff + PCI_SECPCIE_EQCTL(i))]; + if (i % 2 != 0) + reg >>= 16; + else + reg &= 0xffff; + printf(" Equalization Control Register (Link %d): %04x\n", + i, reg); + printf(" Downstream Port Transmit Preset: 0x%x\n", + (pcireg_t)__SHIFTOUT(reg, + PCI_SECPCIE_EQCTL_DP_XMIT_PRESET)); + printf(" Downstream Port Receive Hint: 0x%x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_SECPCIE_EQCTL_DP_RCV_HINT)); + printf(" Upstream Port Transmit Preset: 0x%x\n", + (pcireg_t)__SHIFTOUT(reg, + PCI_SECPCIE_EQCTL_UP_XMIT_PRESET)); + printf(" Upstream Port Receive Hint: 0x%x\n", + (pcireg_t)__SHIFTOUT(reg, PCI_SECPCIE_EQCTL_UP_RCV_HINT)); + } +} + +/* XXX pci_conf_print_pmux_cap */ + +static void +pci_conf_print_pasid_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, cap, ctl; + unsigned int num; + + printf("\n Process Address Space ID\n"); + + reg = regs[o2i(extcapoff + PCI_PASID_CAP)]; + cap = reg & 0xffff; + ctl = reg >> 16; + printf(" PASID Capability Register: 0x%04x\n", cap); + onoff("Execute Permission Supported", reg, PCI_PASID_CAP_XPERM); + onoff("Privileged Mode Supported", reg, PCI_PASID_CAP_PRIVMODE); + num = (1 << __SHIFTOUT(reg, PCI_PASID_CAP_MAXPASIDW)) - 1; + printf(" Max PASID Width: %u\n", num); + + printf(" PASID Control Register: 0x%04x\n", ctl); + onoff("PASID Enable", reg, PCI_PASID_CTL_PASID_EN); + onoff("Execute Permission Enable", reg, PCI_PASID_CTL_XPERM_EN); + onoff("Privileged Mode Enable", reg, PCI_PASID_CTL_PRIVMODE_EN); +} + +static void +pci_conf_print_lnr_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg, cap, ctl; + unsigned int num; + + printf("\n LN Requester\n"); + + reg = regs[o2i(extcapoff + PCI_LNR_CAP)]; + cap = reg & 0xffff; + ctl = reg >> 16; + printf(" LNR Capability register: 0x%04x\n", cap); + onoff("LNR-64 Supported", reg, PCI_LNR_CAP_64); + onoff("LNR-128 Supported", reg, PCI_LNR_CAP_128); + num = 1 << __SHIFTOUT(reg, PCI_LNR_CAP_REGISTMAX); + printf(" LNR Registration MAX: %u\n", num); + + printf(" LNR Control register: 0x%04x\n", ctl); + onoff("LNR Enable", reg, PCI_LNR_CTL_EN); + onoff("LNR CLS", reg, PCI_LNR_CTL_CLS); + num = 1 << __SHIFTOUT(reg, PCI_LNR_CTL_REGISTLIM); + printf(" LNR Registration Limit: %u\n", num); +} + +/* XXX pci_conf_print_dpc_cap */ + +static int +pci_conf_l1pm_cap_tposcale(unsigned char scale) +{ + + /* Return scale in us */ + switch (scale) { + case 0x0: + return 2; + case 0x1: + return 10; + case 0x2: + return 100; + default: + return -1; + } +} + +static void +pci_conf_print_l1pm_cap(const pcireg_t *regs, int capoff, int extcapoff) +{ + pcireg_t reg; + int scale, val; + + printf("\n L1 PM Substates\n"); + + reg = regs[o2i(extcapoff + PCI_L1PM_CAP)]; + printf(" L1 PM Substates Capability register: 0x%08x\n", reg); + onoff("PCI-PM L1.2 Supported", reg, PCI_L1PM_CAP_PCIPM12); + onoff("PCI-PM L1.1 Supported", reg, PCI_L1PM_CAP_PCIPM11); + onoff("ASPM L1.2 Supported", reg, PCI_L1PM_CAP_ASPM12); + onoff("ASPM L1.1 Supported", reg, PCI_L1PM_CAP_ASPM11); + onoff("L1 PM Substates Supported", reg, PCI_L1PM_CAP_L1PM); + printf(" Port Common Mode Restore Time: %uus\n", + (unsigned int)__SHIFTOUT(reg, PCI_L1PM_CAP_PCMRT)); + scale = pci_conf_l1pm_cap_tposcale( + __SHIFTOUT(reg, PCI_L1PM_CAP_PTPOSCALE)); + val = __SHIFTOUT(reg, PCI_L1PM_CAP_PTPOVAL); + printf(" Port T_POWER_ON: "); + if (scale == -1) + printf("unknown\n"); + else + printf("%dus\n", val * scale); + + reg = regs[o2i(extcapoff + PCI_L1PM_CTL1)]; + printf(" L1 PM Substates Control register 1: 0x%08x\n", reg); + onoff("PCI-PM L1.2 Enable", reg, PCI_L1PM_CTL1_PCIPM12_EN); + onoff("PCI-PM L1.1 Enable", reg, PCI_L1PM_CTL1_PCIPM11_EN); + onoff("ASPM L1.2 Enable", reg, PCI_L1PM_CTL1_ASPM12_EN); + onoff("ASPM L1.1 Enable", reg, PCI_L1PM_CTL1_ASPM11_EN); + printf(" Common Mode Restore Time: %uus\n", + (unsigned int)__SHIFTOUT(reg, PCI_L1PM_CTL1_CMRT)); + scale = PCI_LTR_SCALETONS(__SHIFTOUT(reg, PCI_L1PM_CTL1_LTRTHSCALE)); + val = __SHIFTOUT(reg, PCI_L1PM_CTL1_LTRTHVAL); + printf(" LTR L1.2 THRESHOLD: %dus\n", val * scale); + + reg = regs[o2i(extcapoff + PCI_L1PM_CTL2)]; + printf(" L1 PM Substates Control register 2: 0x%08x\n", reg); + scale = pci_conf_l1pm_cap_tposcale( + __SHIFTOUT(reg, PCI_L1PM_CTL2_TPOSCALE)); + val = __SHIFTOUT(reg, PCI_L1PM_CTL2_TPOVAL); + printf(" T_POWER_ON: "); + if (scale == -1) + printf("unknown\n"); + else + printf("%dus\n", val * scale); +} + +/* XXX pci_conf_print_ptm_cap */ +/* XXX pci_conf_print_mpcie_cap */ +/* XXX pci_conf_print_frsq_cap */ +/* XXX pci_conf_print_rtr_cap */ +/* XXX pci_conf_print_desigvndsp_cap */ + +#undef MS +#undef SM +#undef RW + +static struct { + pcireg_t cap; + const char *name; + void (*printfunc)(const pcireg_t *, int, int); +} pci_extcaptab[] = { + { 0, "reserved", + NULL }, + { PCI_EXTCAP_AER, "Advanced Error Reporting", + pci_conf_print_aer_cap }, + { PCI_EXTCAP_VC, "Virtual Channel", + pci_conf_print_vc_cap }, + { PCI_EXTCAP_SERNUM, "Device Serial Number", + pci_conf_print_sernum_cap }, + { PCI_EXTCAP_PWRBDGT, "Power Budgeting", + pci_conf_print_pwrbdgt_cap }, + { PCI_EXTCAP_RCLINK_DCL,"Root Complex Link Declaration", + pci_conf_print_rclink_dcl_cap }, + { PCI_EXTCAP_RCLINK_CTL,"Root Complex Internal Link Control", + NULL }, + { PCI_EXTCAP_RCEC_ASSOC,"Root Complex Event Collector Association", + pci_conf_print_rcec_assoc_cap }, + { PCI_EXTCAP_MFVC, "Multi-Function Virtual Channel", + NULL }, + { PCI_EXTCAP_VC2, "Virtual Channel", + NULL }, + { PCI_EXTCAP_RCRB, "RCRB Header", + NULL }, + { PCI_EXTCAP_VENDOR, "Vendor Unique", + NULL }, + { PCI_EXTCAP_CAC, "Configuration Access Correction", + NULL }, + { PCI_EXTCAP_ACS, "Access Control Services", + pci_conf_print_acs_cap }, + { PCI_EXTCAP_ARI, "Alternative Routing-ID Interpretation", + pci_conf_print_ari_cap }, + { PCI_EXTCAP_ATS, "Address Translation Services", + pci_conf_print_ats_cap }, + { PCI_EXTCAP_SRIOV, "Single Root IO Virtualization", + pci_conf_print_sriov_cap }, + { PCI_EXTCAP_MRIOV, "Multiple Root IO Virtualization", + NULL }, + { PCI_EXTCAP_MULTICAST, "Multicast", + NULL }, + { PCI_EXTCAP_PAGE_REQ, "Page Request", + pci_conf_print_page_req_cap }, + { PCI_EXTCAP_AMD, "Reserved for AMD", + NULL }, + { PCI_EXTCAP_RESIZE_BAR,"Resizable BAR", + NULL }, + { PCI_EXTCAP_DPA, "Dynamic Power Allocation", + NULL }, + { PCI_EXTCAP_TPH_REQ, "TPH Requester", + pci_conf_print_tph_req_cap }, + { PCI_EXTCAP_LTR, "Latency Tolerance Reporting", + pci_conf_print_ltr_cap }, + { PCI_EXTCAP_SEC_PCIE, "Secondary PCI Express", + pci_conf_print_sec_pcie_cap }, + { PCI_EXTCAP_PMUX, "Protocol Multiplexing", + NULL }, + { PCI_EXTCAP_PASID, "Process Address Space ID", + pci_conf_print_pasid_cap }, + { PCI_EXTCAP_LN_REQ, "LN Requester", + pci_conf_print_lnr_cap }, + { PCI_EXTCAP_DPC, "Downstream Port Containment", + NULL }, + { PCI_EXTCAP_L1PM, "L1 PM Substates", + pci_conf_print_l1pm_cap }, + { PCI_EXTCAP_PTM, "Precision Time Management", + NULL }, + { PCI_EXTCAP_MPCIE, "M-PCIe", + NULL }, + { PCI_EXTCAP_FRSQ, "Function Reading Status Queueing", + NULL }, + { PCI_EXTCAP_RTR, "Readiness Time Reporting", + NULL }, + { PCI_EXTCAP_DESIGVNDSP, "Designated Vendor-Specific", + NULL }, +}; + +static int +pci_conf_find_extcap(const pcireg_t *regs, int capoff, unsigned int capid, + int *offsetp) +{ + int off; + pcireg_t rval; + + for (off = PCI_EXTCAPLIST_BASE; + off != 0; + off = PCI_EXTCAPLIST_NEXT(rval)) { + rval = regs[o2i(off)]; + if (capid == PCI_EXTCAPLIST_CAP(rval)) { + if (offsetp != NULL) + *offsetp = off; + return 1; + } + } + return 0; +} + +static void +pci_conf_print_extcaplist( +#ifdef _KERNEL + pci_chipset_tag_t pc, pcitag_t tag, +#endif + const pcireg_t *regs, int capoff) +{ + int off; + pcireg_t foundcap; + pcireg_t rval; + bool foundtable[__arraycount(pci_extcaptab)]; + unsigned int i; + + /* Check Extended capability structure */ + off = PCI_EXTCAPLIST_BASE; + rval = regs[o2i(off)]; + if (rval == 0xffffffff || rval == 0) + return; + + /* Clear table */ + for (i = 0; i < __arraycount(pci_extcaptab); i++) + foundtable[i] = false; + + /* Print extended capability register's offset and the type first */ + for (;;) { + printf(" Extended Capability Register at 0x%02x\n", off); + + foundcap = PCI_EXTCAPLIST_CAP(rval); + printf(" type: 0x%04x (", foundcap); + if (foundcap < __arraycount(pci_extcaptab)) { + printf("%s)\n", pci_extcaptab[foundcap].name); + /* Mark as found */ + foundtable[foundcap] = true; + } else + printf("unknown)\n"); + printf(" version: %d\n", PCI_EXTCAPLIST_VERSION(rval)); + + off = PCI_EXTCAPLIST_NEXT(rval); + if (off == 0) + break; + rval = regs[o2i(off)]; + } + + /* + * And then, print the detail of each capability registers + * in capability value's order. + */ + for (i = 0; i < __arraycount(pci_extcaptab); i++) { + if (foundtable[i] == false) + continue; + + /* + * The type was found. Search capability list again and + * print all capabilities that the capabiliy type is + * the same. + */ + if (pci_conf_find_extcap(regs, capoff, i, &off) == 0) + continue; + rval = regs[o2i(off)]; + if ((PCI_EXTCAPLIST_VERSION(rval) <= 0) + || (pci_extcaptab[i].printfunc == NULL)) + continue; + + pci_extcaptab[i].printfunc(regs, capoff, off); + + } } /* Print the Secondary Status Register. */ @@ -2216,8 +3398,8 @@ pci_conf_print_type2( printf(" Capability list pointer: 0x%02x\n", PCI_CAPLIST_PTR(rval)); else - printf(" Reserved @ 0x14: 0x%04" PRIxMAX "\n", - __SHIFTOUT(rval, __BITS(15, 0))); + printf(" Reserved @ 0x14: 0x%04x\n", + (pcireg_t)__SHIFTOUT(rval, __BITS(15, 0))); pci_conf_print_ssr(__SHIFTOUT(rval, __BITS(31, 16))); rval = regs[o2i(PCI_BRIDGE_BUS_REG)]; @@ -2306,7 +3488,7 @@ pci_conf_print( #endif ) { - pcireg_t regs[o2i(256)]; + pcireg_t regs[o2i(PCI_EXTCONF_SIZE)]; int off, capoff, endoff, hdrtype; const char *type_name; #ifdef _KERNEL @@ -2319,7 +3501,7 @@ pci_conf_print( printf("PCI configuration registers:\n"); - for (off = 0; off < 256; off += 4) { + for (off = 0; off < PCI_EXTCONF_SIZE; off += 4) { #ifdef _KERNEL regs[o2i(off)] = pci_conf_read(pc, tag, off); #else @@ -2409,7 +3591,7 @@ pci_conf_print( /* device-dependent header */ printf(" Device-dependent header:\n"); - pci_conf_print_regs(regs, endoff, 256); + pci_conf_print_regs(regs, endoff, PCI_CONF_SIZE); printf("\n"); #ifdef _KERNEL if (printfn) @@ -2418,4 +3600,19 @@ pci_conf_print( printf(" Don't know how to pretty-print device-dependent header.\n"); printf("\n"); #endif /* _KERNEL */ + + if (regs[o2i(PCI_EXTCAPLIST_BASE)] == 0xffffffff || + regs[o2i(PCI_EXTCAPLIST_BASE)] == 0) + return; + +#ifdef _KERNEL + pci_conf_print_extcaplist(pc, tag, regs, capoff); +#else + pci_conf_print_extcaplist(regs, capoff); +#endif + printf("\n"); + + /* Extended Configuration Space, if present */ + printf(" Extended Configuration Space:\n"); + pci_conf_print_regs(regs, PCI_EXTCAPLIST_BASE, PCI_EXTCONF_SIZE); } diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 90911e3e5be..d89c6e7da74 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: pcireg.h,v 1.103 2015/07/27 15:46:03 msaitoh Exp $ */ +/* $NetBSD: pcireg.h,v 1.104 2015/10/02 05:22:53 msaitoh Exp $ */ /* * Copyright (c) 1995, 1996, 1999, 2000 @@ -1319,7 +1319,7 @@ struct pci_rom { #define PCI32_DMA_BOUNCE_THRESHOLD 0x100000000ULL /* - * PCI-X 2.0 Extended Capability List + * PCI-X 2.0/ PCI-express Extended Capability List */ #define PCI_EXTCAPLIST_BASE 0x100 @@ -1328,6 +1328,502 @@ struct pci_rom { #define PCI_EXTCAPLIST_VERSION(ecr) (((ecr) >> 16) & 0xf) #define PCI_EXTCAPLIST_NEXT(ecr) (((ecr) >> 20) & 0xfff) +/* Extended Capability Identification Numbers */ + +#define PCI_EXTCAP_AER 0x0001 /* Advanced Error Reporting */ +#define PCI_EXTCAP_VC 0x0002 /* Virtual Channel if MFVC Ext Cap not set */ +#define PCI_EXTCAP_SERNUM 0x0003 /* Device Serial Number */ +#define PCI_EXTCAP_PWRBDGT 0x0004 /* Power Budgeting */ +#define PCI_EXTCAP_RCLINK_DCL 0x0005 /* Root Complex Link Declaration */ +#define PCI_EXTCAP_RCLINK_CTL 0x0006 /* Root Complex Internal Link Control */ +#define PCI_EXTCAP_RCEC_ASSOC 0x0007 /* Root Complex Event Collector Association */ +#define PCI_EXTCAP_MFVC 0x0008 /* Multi-Function Virtual Channel */ +#define PCI_EXTCAP_VC2 0x0009 /* Virtual Channel if MFVC Ext Cap set */ +#define PCI_EXTCAP_RCRB 0x000a /* RCRB Header */ +#define PCI_EXTCAP_VENDOR 0x000b /* Vendor Unique */ +#define PCI_EXTCAP_CAC 0x000c /* Configuration Access Correction -- obsolete */ +#define PCI_EXTCAP_ACS 0x000d /* Access Control Services */ +#define PCI_EXTCAP_ARI 0x000e /* Alternative Routing-ID Interpretation */ +#define PCI_EXTCAP_ATS 0x000f /* Address Translation Services */ +#define PCI_EXTCAP_SRIOV 0x0010 /* Single Root IO Virtualization */ +#define PCI_EXTCAP_MRIOV 0x0011 /* Multiple Root IO Virtualization */ +#define PCI_EXTCAP_MULTICAST 0x0012 /* Multicast */ +#define PCI_EXTCAP_PAGE_REQ 0x0013 /* Page Request */ +#define PCI_EXTCAP_AMD 0x0014 /* Reserved for AMD */ +#define PCI_EXTCAP_RESIZE_BAR 0x0015 /* Resizable BAR */ +#define PCI_EXTCAP_DPA 0x0016 /* Dynamic Power Allocation */ +#define PCI_EXTCAP_TPH_REQ 0x0017 /* TPH Requester */ +#define PCI_EXTCAP_LTR 0x0018 /* Latency Tolerance Reporting */ +#define PCI_EXTCAP_SEC_PCIE 0x0019 /* Secondary PCI Express */ +#define PCI_EXTCAP_PMUX 0x001a /* Protocol Multiplexing */ +#define PCI_EXTCAP_PASID 0x001b /* Process Address Space ID */ +#define PCI_EXTCAP_LN_REQ 0x001c /* LN Requester */ +#define PCI_EXTCAP_DPC 0x001d /* Downstream Port Containment */ +#define PCI_EXTCAP_L1PM 0x001e /* L1 PM Substates */ +#define PCI_EXTCAP_PTM 0x001f /* Precision Time Management */ +#define PCI_EXTCAP_MPCIE 0x0020 /* M-PCIe */ +#define PCI_EXTCAP_FRSQ 0x0021 /* Function Reading Status Queueing */ +#define PCI_EXTCAP_RTR 0x0022 /* Readiness Time Reporting */ +#define PCI_EXTCAP_DESIGVNDSP 0x0023 /* Designated Vendor-Specific */ + +/* + * Extended capability ID: 0x0001 + * Advanced Error Reporting + */ +#define PCI_AER_UC_STATUS 0x04 /* Uncorrectable Error Status Register */ +#define PCI_AER_UC_UNDEFINED __BIT(0) +#define PCI_AER_UC_DL_PROTOCOL_ERROR __BIT(4) +#define PCI_AER_UC_SURPRISE_DOWN_ERROR __BIT(5) +#define PCI_AER_UC_POISONED_TLP __BIT(12) +#define PCI_AER_UC_FC_PROTOCOL_ERROR __BIT(13) +#define PCI_AER_UC_COMPLETION_TIMEOUT __BIT(14) +#define PCI_AER_UC_COMPLETER_ABORT __BIT(15) +#define PCI_AER_UC_UNEXPECTED_COMPLETION __BIT(16) +#define PCI_AER_UC_RECEIVER_OVERFLOW __BIT(17) +#define PCI_AER_UC_MALFORMED_TLP __BIT(18) +#define PCI_AER_UC_ECRC_ERROR __BIT(19) +#define PCI_AER_UC_UNSUPPORTED_REQUEST_ERROR __BIT(20) +#define PCI_AER_UC_ACS_VIOLATION __BIT(21) +#define PCI_AER_UC_INTERNAL_ERROR __BIT(22) +#define PCI_AER_UC_MC_BLOCKED_TLP __BIT(23) +#define PCI_AER_UC_ATOMIC_OP_EGRESS_BLOCKED __BIT(24) +#define PCI_AER_UC_TLP_PREFIX_BLOCKED_ERROR __BIT(25) +#define PCI_AER_UC_MASK 0x08 /* Uncorrectable Error Mask Register */ + /* Shares bits with UC_STATUS */ +#define PCI_AER_UC_SEVERITY 0x0c /* Uncorrectable Error Severity Register */ + /* Shares bits with UC_STATUS */ +#define PCI_AER_COR_STATUS 0x10 /* Correctable Error Status Register */ +#define PCI_AER_COR_RECEIVER_ERROR __BIT(0) +#define PCI_AER_COR_BAD_TLP __BIT(6) +#define PCI_AER_COR_BAD_DLLP __BIT(7) +#define PCI_AER_COR_REPLAY_NUM_ROLLOVER __BIT(8) +#define PCI_AER_COR_REPLAY_TIMER_TIMEOUT __BIT(12) +#define PCI_AER_COR_ADVISORY_NF_ERROR __BIT(13) +#define PCI_AER_COR_INTERNAL_ERROR __BIT(14) +#define PCI_AER_COR_HEADER_LOG_OVERFLOW __BIT(15) +#define PCI_AER_COR_MASK 0x14 /* Correctable Error Mask Register */ + /* Shares bits with COR_STATUS */ +#define PCI_AER_CAP_CONTROL 0x18 /* Advanced Error Capabilities and Control Register */ +#define PCI_AER_FIRST_ERROR_PTR __BITS(4, 0) +#define PCI_AER_FIRST_ERROR_PTR_S 0 +#define PCI_AER_FIRST_ERROR_PTR_M 0x1f +#define PCI_AER_ECRC_GEN_CAPABLE __BIT(5) +#define PCI_AER_ECRC_GEN_ENABLE __BIT(6) +#define PCI_AER_ECRC_CHECK_CAPABLE __BIT(7) +#define PCI_AER_ECRC_CHECK_ENABLE __BIT(8) +#define PCI_AER_MULT_HDR_CAPABLE __BIT(9) +#define PCI_AER_MULT_HDR_ENABLE __BIT(10) +#define PCI_AER_TLP_PREFIX_LOG_PRESENT __BIT(11) +#define PCI_AER_HEADER_LOG 0x1c /* Header Log Register */ +#define PCI_AER_ROOTERR_CMD 0x2c /* Root Error Command Register */ + /* Only for root complex ports */ +#define PCI_AER_ROOTERR_COR_ENABLE __BIT(0) +#define PCI_AER_ROOTERR_NF_ENABLE __BIT(1) +#define PCI_AER_ROOTERR_F_ENABLE __BIT(2) +#define PCI_AER_ROOTERR_STATUS 0x30 /* Root Error Status Register */ + /* Only for root complex ports */ +#define PCI_AER_ROOTERR_COR_ERR __BIT(0) +#define PCI_AER_ROOTERR_MULTI_COR_ERR __BIT(1) +#define PCI_AER_ROOTERR_UC_ERR __BIT(2) +#define PCI_AER_ROOTERR_MULTI_UC_ERR __BIT(3) +#define PCI_AER_ROOTERR_FIRST_UC_FATAL __BIT(4) +#define PCI_AER_ROOTERR_NF_ERR __BIT(5) +#define PCI_AER_ROOTERR_F_ERR __BIT(6) +#define PCI_AER_ROOTERR_INT_MESSAGE __BITS(31, 27) +#define PCI_AER_ROOTERR_INT_MESSAGE_S 27 +#define PCI_AER_ROOTERR_INT_MESSAGE_M 0x1f +#define PCI_AER_ERRSRC_ID 0x34 /* Error Source Identification Register */ +#define PCI_AER_ERRSRC_ID_ERR_COR __BITS(15, 0) +#define PCI_AER_ERRSRC_ID_ERR_COR_S 0 +#define PCI_AER_ERRSRC_ID_ERR_COR_M 0xffff +#define PCI_AER_ERRSRC_ID_ERR_UC __BITS(31, 16) +#define PCI_AER_ERRSRC_ID_ERR_UC_S 16 +#define PCI_AER_ERRSRC_ID_ERR_UC_M 0xffff + /* Only for root complex ports */ +#define PCI_AER_TLP_PREFIX_LOG 0x38 /*TLP Prefix Log Register */ + /* Only for TLP prefix functions */ + +/* + * Extended capability ID: 0x0002, 0x0009 + * Virtual Channel + */ +#define PCI_VC_CAP1 0x04 /* Port VC Capability Register 1 */ +#define PCI_VC_CAP1_EXT_COUNT __BITS(2, 0) +#define PCI_VC_CAP1_EXT_COUNT_S 0 +#define PCI_VC_CAP1_EXT_COUNT_M 0x7 +#define PCI_VC_CAP1_LOWPRI_EXT_COUNT __BITS(6, 4) +#define PCI_VC_CAP1_LOWPRI_EXT_COUNT_S 4 +#define PCI_VC_CAP1_LOWPRI_EXT_COUNT_M 0x7 +#define PCI_VC_CAP1_REFCLK __BITS(9, 8) +#define PCI_VC_CAP1_REFCLK_S 8 +#define PCI_VC_CAP1_REFCLK_M 0x3 +#define PCI_VC_CAP1_REFCLK_100NS 0x0 +#define PCI_VC_CAP1_PORT_ARB_TABLE_SIZE __BITS(11, 10) +#define PCI_VC_CAP1_PORT_ARB_TABLE_SIZE_S 10 +#define PCI_VC_CAP1_PORT_ARB_TABLE_SIZE_M 0x3 +#define PCI_VC_CAP2 0x08 /* Port VC Capability Register 2 */ +#define PCI_VC_CAP2_ARB_CAP_HW_FIXED_SCHEME __BIT(0) +#define PCI_VC_CAP2_ARB_CAP_WRR_32 __BIT(1) +#define PCI_VC_CAP2_ARB_CAP_WRR_64 __BIT(2) +#define PCI_VC_CAP2_ARB_CAP_WRR_128 __BIT(3) +#define PCI_VC_CAP2_ARB_TABLE_OFFSET __BITS(31, 24) +#define PCI_VC_CAP2_ARB_TABLE_OFFSET_S 24 +#define PCI_VC_CAP2_ARB_TABLE_OFFSET_M 0xff +#define PCI_VC_CONTROL 0x0c /* Port VC Control Register (16bit) */ +#define PCI_VC_CONTROL_LOAD_VC_ARB_TABLE __BIT(0) +#define PCI_VC_CONTROL_VC_ARB_SELECT __BITS(3, 1) +#define PCI_VC_CONTROL_VC_ARB_SELECT_S 1 +#define PCI_VC_CONTROL_VC_ARB_SELECT_M 0x7 +#define PCI_VC_STATUS 0x0e /* Port VC Status Register (16bit) */ +#define PCI_VC_STATUS_LOAD_VC_ARB_TABLE __BIT(0) +#define PCI_VC_RESOURCE_CAP(n) (0x10 + ((n) * 0x0c)) /* VC Resource Capability Register */ +#define PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_HW_FIXED_SCHEME __BIT(0) +#define PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_32 __BIT(1) +#define PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_64 __BIT(2) +#define PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_128 __BIT(3) +#define PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_TWRR_128 __BIT(4) +#define PCI_VC_RESOURCE_CAP_PORT_ARB_CAP_WRR_256 __BIT(5) +#define PCI_VC_RESOURCE_CAP_ADV_PKT_SWITCH __BIT(14) +#define PCI_VC_RESOURCE_CAP_REJCT_SNOOP_TRANS __BIT(15) +#define PCI_VC_RESOURCE_CAP_MAX_TIME_SLOTS __BITS(22, 16) +#define PCI_VC_RESOURCE_CAP_MAX_TIME_SLOTS_S 16 +#define PCI_VC_RESOURCE_CAP_MAX_TIME_SLOTS_M 0x7f +#define PCI_VC_RESOURCE_CAP_PORT_ARB_TABLE_OFFSET __BITS(31, 24) +#define PCI_VC_RESOURCE_CAP_PORT_ARB_TABLE_OFFSET_S 24 +#define PCI_VC_RESOURCE_CAP_PORT_ARB_TABLE_OFFSET_M 0xff +#define PCI_VC_RESOURCE_CTL(n) (0x14 + ((n) * 0x0c)) /* VC Resource Control Register */ +#define PCI_VC_RESOURCE_CTL_TCVC_MAP __BITS(7, 0) +#define PCI_VC_RESOURCE_CTL_TCVC_MAP_S 0 +#define PCI_VC_RESOURCE_CTL_TCVC_MAP_M 0xff +#define PCI_VC_RESOURCE_CTL_LOAD_PORT_ARB_TABLE __BIT(16) +#define PCI_VC_RESOURCE_CTL_PORT_ARB_SELECT __BITS(19, 17) +#define PCI_VC_RESOURCE_CTL_PORT_ARB_SELECT_S 17 +#define PCI_VC_RESOURCE_CTL_PORT_ARB_SELECT_M 0x7 +#define PCI_VC_RESOURCE_CTL_VC_ID __BITS(26, 24) +#define PCI_VC_RESOURCE_CTL_VC_ID_S 24 +#define PCI_VC_RESOURCE_CTL_VC_ID_M 0x7 +#define PCI_VC_RESOURCE_CTL_VC_ENABLE __BIT(31) +#define PCI_VC_RESOURCE_STA(n) (0x18 + ((n) * 0x0c)) /* VC Resource Status Register */ +#define PCI_VC_RESOURCE_STA_PORT_ARB_TABLE __BIT(0) +#define PCI_VC_RESOURCE_STA_VC_NEG_PENDING __BIT(1) + +/* + * Extended capability ID: 0x0003 + * Serial Number + */ +#define PCI_SERIAL_LOW 0x04 +#define PCI_SERIAL_HIGH 0x08 + +/* + * Extended capability ID: 0x0004 + * Power Budgeting + */ +#define PCI_PWRBDGT_DSEL 0x04 /* Data Select */ +#define PCI_PWRBDGT_DATA 0x08 /* Data */ +#define PCI_PWRBDGT_DATA_BASEPWR __BITS(7, 0) /* Base Power */ +#define PCI_PWRBDGT_DATA_SCALE __BITS(9, 8) /* Data Scale */ +#define PCI_PWRBDGT_PM_SUBSTAT __BITS(12, 10) /* PM Sub State */ +#define PCI_PWRBDGT_PM_STAT __BITS(14, 13) /* PM State */ +#define PCI_PWRBDGT_TYPE __BITS(17, 15) /* Type */ +#define PCI_PWRBDGT_PWRRAIL __BITS(20, 18) /* Power Rail */ +#define PCI_PWRBDGT_CAP 0x0c /* Capability */ +#define PCI_PWRBDGT_CAP_SYSALLOC __BIT(0) /* System Allocated */ + +/* + * Extended capability ID: 0x0005 + * Root Complex Link Declaration + */ +#define PCI_RCLINK_DCL_ESDESC 0x04 /* Element Self Description */ +#define PCI_RCLINK_DCL_ESDESC_ELMTYPE __BITS(3, 0) /* Element Type */ +#define PCI_RCLINK_DCL_ESDESC_NUMLINKENT __BITS(15, 8) /* Num of Link Entries*/ +#define PCI_RCLINK_DCL_ESDESC_COMPID __BITS(23, 16) /* Component ID */ +#define PCI_RCLINK_DCL_ESDESC_PORTNUM __BITS(31, 24) /* Port Number */ +#define PCI_RCLINK_DCL_LINKENTS 0x10 /* Link Entries */ +#define PCI_RCLINK_DCL_LINKDESC(x) /* Link Description */ \ + (PCI_RCLINK_DCL_LINKENTS + ((x) * 16)) +#define PCI_RCLINK_DCL_LINKDESC_LVALID __BIT(0) /* Link Valid */ +#define PCI_RCLINK_DCL_LINKDESC_LTYPE __BIT(1) /* Link Type */ +#define PCI_RCLINK_DCL_LINKDESC_ARCRBH __BIT(2) /* Associate RCRB Header */ +#define PCI_RCLINK_DCL_LINKDESC_TCOMPID __BITS(23, 16) /* Target Component ID*/ +#define PCI_RCLINK_DCL_LINKDESC_TPNUM __BITS(31, 24) /* Target Port Number */ +#define PCI_RCLINK_DCL_LINKADDR_LT0_LO(x) /* LT0: Link Address Low */ \ + (PCI_RCLINK_DCL_LINKENTS + ((x) * 16) + 0x08) +#define PCI_RCLINK_DCL_LINKADDR_LT0_HI(x) /* LT0: Link Address High */ \ + (PCI_RCLINK_DCL_LINKENTS + ((x) * 16) + 0x0c) +#define PCI_RCLINK_DCL_LINKADDR_LT1_LO(x) /* LT1: Config Space (low) */ \ + (PCI_RCLINK_DCL_LINKENTS + ((x) * 16) + 0x08) +#define PCI_RCLINK_DCL_LINKADDR_LT1_N __BITS(2, 0) /* N */ +#define PCI_RCLINK_DCL_LINKADDR_LT1_FUNC __BITS(14, 12) /* Function Number */ +#define PCI_RCLINK_DCL_LINKADDR_LT1_DEV __BITS(19, 15) /* Device Number */ +#define PCI_RCLINK_DCL_LINKADDR_LT1_BUS(N) __BITS(19 + (N), 20) /* Bus Number*/ +#define PCI_RCLINK_DCL_LINKADDR_LT1_BAL(N) __BITS(31, 20 + (N)) /* BAddr(L) */ +#define PCI_RCLINK_DCL_LINKADDR_LT1_HI(x) /* LT1: Config Space Base Addr(H) */\ + (PCI_RCLINK_DCL_LINKENTS + ((x) * 16) + 0x0c) + +/* + * Extended capability ID: 0x0006 + * Root Complex Internal Link Control + */ + +/* + * Extended capability ID: 0x0007 + * Root Complex Event Collector Association + */ +#define PCI_RCEC_ASSOC_ASSOCBITMAP 0x04 + +/* + * Extended capability ID: 0x0008 + * Multi-Function Virtual Channel + */ + +/* + * Extended capability ID: 0x0009 + * Virtual Channel if MFVC Ext Cap set + */ + +/* + * Extended capability ID: 0x000a + * RCRB Header + */ + +/* + * Extended capability ID: 0x000b + * Vendor Unique + */ + +/* + * Extended capability ID: 0x000c + * Configuration Access Correction + */ + +/* + * Extended capability ID: 0x000d + * Access Control Services + */ +#define PCI_ACS_CAP 0x04 /* Capability Register */ +#define PCI_ACS_CAP_V __BIT(0) /* Source Validation */ +#define PCI_ACS_CAP_B __BIT(1) /* Transaction Blocking */ +#define PCI_ACS_CAP_R __BIT(2) /* P2P Request Redirect */ +#define PCI_ACS_CAP_C __BIT(3) /* P2P Completion Redirect */ +#define PCI_ACS_CAP_U __BIT(4) /* Upstream Forwarding */ +#define PCI_ACS_CAP_E __BIT(5) /* Egress Control */ +#define PCI_ACS_CAP_T __BIT(6) /* Direct Translated P2P */ +#define PCI_ACS_CAP_ECVSIZE __BITS(15, 8) /* Egress Control Vector Size */ +#define PCI_ACS_CTL 0x04 /* Control Register */ +#define PCI_ACS_CTL_V __BIT(0 + 16) /* Source Validation Enable */ +#define PCI_ACS_CTL_B __BIT(1 + 16) /* Transaction Blocking Enable */ +#define PCI_ACS_CTL_R __BIT(2 + 16) /* P2P Request Redirect Enable */ +#define PCI_ACS_CTL_C __BIT(3 + 16) /* P2P Completion Redirect Enable */ +#define PCI_ACS_CTL_U __BIT(4 + 16) /* Upstream Forwarding Enable */ +#define PCI_ACS_CTL_E __BIT(5 + 16) /* Egress Control Enable */ +#define PCI_ACS_CTL_T __BIT(6 + 16) /* Direct Translated P2P Enable */ +#define PCI_ACS_ECV 0x08 /* Egress Control Vector */ + +/* + * Extended capability ID: 0x000e + * ARI + */ +#define PCI_ARI_CAP 0x04 /* Capability Register */ +#define PCI_ARI_CAP_M __BIT(0) /* MFVC Function Groups Cap. */ +#define PCI_ARI_CAP_A __BIT(1) /* ACS Function Groups Cap. */ +#define PCI_ARI_CAP_NXTFN __BITS(15, 8) /* Next Function Number */ +#define PCI_ARI_CTL 0x04 /* Control Register */ +#define PCI_ARI_CTL_M __BIT(16) /* MFVC Function Groups Ena. */ +#define PCI_ARI_CTL_A __BIT(17) /* ACS Function Groups Ena. */ +#define PCI_ARI_CTL_FUNCGRP __BITS(31, 24) /* Function Group */ + +/* + * Extended capability ID: 0x000f + * Address Translation Services + */ +#define PCI_ATS_CAP 0x04 /* Capability Register */ +#define PCI_ATS_CAP_INVQDEPTH __BITS(4, 0) /* Invalidate Queue Depth */ +#define PCI_ATS_CAP_PALIGNREQ __BIT(5) /* Page Aligned Request */ +#define PCI_ATS_CTL 0x04 /* Control Register */ +#define PCI_ATS_CTL_STU __BITS(20, 16) /* Smallest Translation Unit */ +#define PCI_ATS_CTL_EN __BIT(31) /* Enable */ + +/* + * Extended capability ID: 0x0010 + * SR-IOV + */ +#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ +#define PCI_SRIOV_CAP_VF_MIGRATION __BIT(0) +#define PCI_SRIOV_CAP_ARI_CAP_HIER_PRESERVED __BIT(1) +#define PCI_SRIOV_CAP_VF_MIGRATION_INTMSG_N __BITS(31, 21) +#define PCI_SRIOV_CAP_VF_MIGRATION_INTMSG_N_S 21 +#define PCI_SRIOV_CAP_VF_MIGRATION_INTMSG_N_M 0x7ff +#define PCI_SRIOV_CTL 0x08 /* SR-IOV Control (16bit) */ +#define PCI_SRIOV_CTL_VF_ENABLE __BIT(0) +#define PCI_SRIOV_CTL_VF_MIGRATION_SUPPORT __BIT(1) +#define PCI_SRIOV_CTL_VF_MIGRATION_INT_ENABLE __BIT(2) +#define PCI_SRIOV_CTL_VF_MSE __BIT(3) +#define PCI_SRIOV_CTL_ARI_CAP_HIER __BIT(4) +#define PCI_SRIOV_STA 0x0a /* SR-IOV Status (16bit) */ +#define PCI_SRIOV_STA_VF_MIGRATION __BIT(0) +#define PCI_SRIOV_INITIAL_VFS 0x0c /* InitialVFs (16bit) */ +#define PCI_SRIOV_TOTAL_VFS 0x0e /* TotalVFs (16bit) */ +#define PCI_SRIOV_NUM_VFS 0x10 /* NumVFs (16bit) */ +#define PCI_SRIOV_FUNC_DEP_LINK 0x12 /* Function Dependency Link (16bit) */ +#define PCI_SRIOV_VF_OFF 0x14 /* First VF Offset (16bit) */ +#define PCI_SRIOV_VF_STRIDE 0x16 /* VF Stride (16bit) */ +#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID (16bit) */ +#define PCI_SRIOV_PAGE_CAP 0x1c /* Supported Page Sizes */ +#define PCI_SRIOV_PAGE_SIZE 0x20 /* System Page Size */ +#define PCI_SRIOV_BASE_PAGE_SHIFT 12 +#define PCI_SRIOV_BARS 0x24 /* VF BAR0-5 */ +#define PCI_SRIOV_BAR(x) (PCI_SRIOV_BARS + ((x) * 4)) +#define PCI_SRIOV_VF_MIG_STA_AR 0x3c /* VF Migration State Array Offset */ +#define PCI_SRIOV_VF_MIG_STA_OFFSET __BITS(31, 3) +#define PCI_SRIOV_VF_MIG_STA_OFFSET_S 3 +#define PCI_SRIOV_VF_MIG_STA_OFFSET_M 0x1fffffff +#define PCI_SRIOV_VF_MIG_STA_BIR __BITS(2, 0) +#define PCI_SRIOV_VF_MIG_STA_BIR_S 0 +#define PCI_SRIOV_VF_MIG_STA_BIR_M 0x7 + +/* + * Extended capability ID: 0x0011 + * Multiple Root IO Virtualization + */ + +/* + * Extended capability ID: 0x0012 + * Multicast + */ + +/* + * Extended capability ID: 0x0013 + * Page Request + */ +#define PCI_PAGE_REQ_CTL 0x04 /* Control Register */ +#define PCI_PAGE_REQ_CTL_E __BIT(0) /* Enalbe */ +#define PCI_PAGE_REQ_CTL_R __BIT(1) /* Reset */ +#define PCI_PAGE_REQ_STA 0x04 /* Status Register */ +#define PCI_PAGE_REQ_STA_RF __BIT(0+16) /* Response Failure */ +#define PCI_PAGE_REQ_STA_UPRGI __BIT(1+16) /* Unexpected Page Req Grp Idx */ +#define PCI_PAGE_REQ_STA_S __BIT(8+16) /* Stopped */ +#define PCI_PAGE_REQ_OUTSTCAPA 0x08 /* Outstanding Page Request Capacity */ +#define PCI_PAGE_REQ_OUTSTALLOC 0x0c /* Outstanding Page Request Allocation */ + +/* + * Extended capability ID: 0x0014 + * (Reserved for AMD) + */ + +/* + * Extended capability ID: 0x0015 + * Resizable BAR + */ + +/* + * Extended capability ID: 0x0016 + * Dynamic Power Allocation + */ + +/* + * Extended capability ID: 0x0017 + * TPH Requester + */ +#define PCI_TPH_REQ_CAP 0x04 /* TPH Requester Capability */ +#define PCI_TPH_REQ_CAP_NOST __BIT(0) /* No ST Mode Supported */ +#define PCI_TPH_REQ_CAP_INTVEC __BIT(1) /* Intr Vec Mode Supported */ +#define PCI_TPH_REQ_CAP_DEVSPEC __BIT(2) /* Device Specific Mode Supported */ +#define PCI_TPH_REQ_CAP_XTPHREQ __BIT(8) /* Extend TPH Reqester Supported */ +#define PCI_TPH_REQ_CAP_STTBLLOC __BITS(10, 9) /* ST Table Location */ +#define PCI_TPH_REQ_CAP_STTBLSIZ __BITS(26, 16) /* ST Table Size */ +#define PCI_TPH_REQ_CTL 0x08 /* TPH Requester Control */ +#define PCI_TPH_REQ_CTL_STSEL _BITS(2, 0) /* ST Mode Select */ +#define PCI_TPH_REQ_CTL_TPHREQEN _BITS(9, 8) /* TPH Requester Enable */ +#define PCI_TPH_REQ_STTBL 0x0c /* TPH ST Table */ + +/* + * Extended capability ID: 0x0018 + * Latency Tolerance Reporting + */ +#define PCI_LTR_MAXSNOOPLAT 0x04 /* Max Snoop Latency */ +#define PCI_LTR_MAXSNOOPLAT_VAL __BITS(9, 0) /* Max Snoop LatencyValue */ +#define PCI_LTR_MAXSNOOPLAT_SCALE __BITS(12, 10) /* Max Snoop LatencyScale */ +#define PCI_LTR_MAXNOSNOOPLAT 0x04 /* Max No-Snoop Latency */ +#define PCI_LTR_MAXNOSNOOPLAT_VAL __BITS(25, 16) /* Max No-Snoop LatencyValue*/ +#define PCI_LTR_MAXNOSNOOPLAT_SCALE __BITS(28, 26) /*Max NoSnoop LatencyScale*/ +#define PCI_LTR_SCALETONS(x) ((32 << (x)) / 32) + +/* + * Extended capability ID: 0x0019 + * Seconday PCI Express Extended Capability + */ +#define PCI_SECPCIE_LCTL3 0x04 /* Link Control 3 */ +#define PCI_SECPCIE_LCTL3_PERFEQ __BIT(0) /* Perform Equalization */ +#define PCI_SECPCIE_LCTL3_LINKEQREQ_IE __BIT(1) /* Link Eq. Req. Int. Ena. */ +#define PCI_SECPCIE_LANEERR_STA 0x08 /* Lane Error Status */ +#define PCI_SECPCIE_EQCTLS 0x0c /* Equalization Control [0-maxlane] */ +#define PCI_SECPCIE_EQCTL(x) (PCI_SECPCIE_EQCTLS + ((x) * 2)) +#define PCI_SECPCIE_EQCTL_DP_XMIT_PRESET __BITS(3, 0) /* DwnStPort Xmit Pres */ +#define PCI_SECPCIE_EQCTL_DP_RCV_HINT __BITS(6, 4) /* DwnStPort Rcv PreHnt */ +#define PCI_SECPCIE_EQCTL_UP_XMIT_PRESET __BITS(11, 8) /* UpStPort Xmit Pres */ +#define PCI_SECPCIE_EQCTL_UP_RCV_HINT __BITS(14, 12) /* UpStPort Rcv PreHnt*/ + +/* + * Extended capability ID: 0x001a + * Protocol Multiplexing + */ + +/* + * Extended capability ID: 0x001b + * Process Address Space ID + */ +#define PCI_PASID_CAP 0x04 /* Capability Register */ +#define PCI_PASID_CAP_XPERM __BIT(1) /* Execute Permission Supported */ +#define PCI_PASID_CAP_PRIVMODE __BIT(2) /* Privileged Mode Supported */ +#define PCI_PASID_CAP_MAXPASIDW __BITS(12, 8) /* Max PASID Width */ +#define PCI_PASID_CTL 0x04 /* Control Register */ +#define PCI_PASID_CTL_PASID_EN __BIT(0) /* PASID Enable */ +#define PCI_PASID_CTL_XPERM_EN __BIT(1) /* Execute Permission Enable */ +#define PCI_PASID_CTL_PRIVMODE_EN __BIT(2) /* Privileged Mode Enable */ + +/* + * Extended capability ID: 0x001c + * LN Requester + */ +#define PCI_LNR_CAP 0x04 /* Capability Register */ +#define PCI_LNR_CAP_64 __BIT(0) /* LNR-64 Supported */ +#define PCI_LNR_CAP_128 __BIT(1) /* LNR-128 Supported */ +#define PCI_LNR_CAP_REGISTMAX __BITS(12, 8) /* LNR Registration MAX */ +#define PCI_LNR_CTL 0x04 /* Control Register */ +#define PCI_LNR_CTL_EN __BIT(0+16) /* LNR Enable */ +#define PCI_LNR_CTL_CLS __BIT(1+16) /* LNR CLS */ +#define PCI_LNR_CTL_REGISTLIM __BITS(28, 24) /* LNR Registration Limit */ + +/* + * Extended capability ID: 0x001d + * Downstream Port Containment + */ + +/* + * Extended capability ID: 0x001e + * L1 PM Substates + */ +#define PCI_L1PM_CAP 0x04 /* Capabilities Register */ +#define PCI_L1PM_CAP_PCIPM12 __BIT(0) /* PCI-PM L1.2 Supported */ +#define PCI_L1PM_CAP_PCIPM11 __BIT(1) /* PCI-PM L1.1 Supported */ +#define PCI_L1PM_CAP_ASPM12 __BIT(2) /* ASPM L1.2 Supported */ +#define PCI_L1PM_CAP_ASPM11 __BIT(3) /* ASPM L1.1 Supported */ +#define PCI_L1PM_CAP_L1PM __BIT(4) /* L1 PM Substates Supported */ +#define PCI_L1PM_CAP_PCMRT __BITS(15, 8) /*Port Common Mode Restore Time*/ +#define PCI_L1PM_CAP_PTPOSCALE __BITS(17, 16) /* Port T_POWER_ON Scale */ +#define PCI_L1PM_CAP_PTPOVAL __BITS(23, 19) /* Port T_POWER_ON Value */ +#define PCI_L1PM_CTL1 0x08 /* Control Register 1 */ +#define PCI_L1PM_CTL1_PCIPM12_EN __BIT(0) /* PCI-PM L1.2 Enable */ +#define PCI_L1PM_CTL1_PCIPM11_EN __BIT(1) /* PCI-PM L1.1 Enable */ +#define PCI_L1PM_CTL1_ASPM12_EN __BIT(2) /* ASPM L1.2 Enable */ +#define PCI_L1PM_CTL1_ASPM11_EN __BIT(3) /* ASPM L1.1 Enable */ +#define PCI_L1PM_CTL1_CMRT __BITS(15, 8) /* Common Mode Restore Time */ +#define PCI_L1PM_CTL1_LTRTHVAL __BITS(25, 16) /* LTR L1.2 THRESHOLD Value */ +#define PCI_L1PM_CTL1_LTRTHSCALE __BITS(31, 29) /* LTR L1.2 THRESHOLD Scale */ +#define PCI_L1PM_CTL2 0x0c /* Control Register 2 */ +#define PCI_L1PM_CTL2_TPOSCALE __BITS(1, 0) /* T_POWER_ON Scale */ +#define PCI_L1PM_CTL2_TPOVAL __BITS(7, 3) /* T_POWER_ON Value */ + /* * Local constants */ diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 8bd2fcb1e5d..5bdd392cf75 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: pcivar.h,v 1.104 2015/08/17 06:16:03 knakahara Exp $ */ +/* $NetBSD: pcivar.h,v 1.105 2015/10/02 05:22:53 msaitoh Exp $ */ /* * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. @@ -278,14 +278,22 @@ int pci_find_rom(const struct pci_attach_args *, bus_space_tag_t, bus_space_handle_t, bus_size_t, int, bus_space_handle_t *, bus_size_t *); -int pci_get_capability(pci_chipset_tag_t, pcitag_t, int, int *, pcireg_t *); -int pci_get_ht_capability(pci_chipset_tag_t, pcitag_t, int, int *, pcireg_t *); +int pci_get_capability(pci_chipset_tag_t, pcitag_t, int, int *, pcireg_t *); +int pci_get_ht_capability(pci_chipset_tag_t, pcitag_t, int, int *, + pcireg_t *); +int pci_get_ext_capability(pci_chipset_tag_t, pcitag_t, int, int *, + pcireg_t *); + int pci_msi_count(pci_chipset_tag_t, pcitag_t); int pci_msix_count(pci_chipset_tag_t, pcitag_t); /* * Helper functions for autoconfiguration. */ +#ifndef PCI_MACHDEP_ENUMERATE_BUS +int pci_enumerate_bus(struct pci_softc *, const int *, + int (*)(const struct pci_attach_args *), struct pci_attach_args *); +#endif int pci_probe_device(struct pci_softc *, pcitag_t tag, int (*)(const struct pci_attach_args *), struct pci_attach_args *); |
