From cd0d4b4073e62fa22997078b1595f399434a1047 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Wed, 19 Jan 2022 21:33:26 +0000 Subject: [PATCH] 14450 Want PCI platform resource discovery module Reviewed by: Rich Lowe Reviewed by: Patrick Mooney Reviewed by: Andy Fiddaman Approved by: Dan McDonald --- .../pkg/manifests/system-kernel-platform.p5m | 2 + usr/src/uts/common/sys/Makefile | 8 +- usr/src/uts/common/sys/plat/pci_prd.h | 130 +++++ usr/src/uts/i86pc/Makefile.files | 4 +- usr/src/uts/i86pc/Makefile.i86pc | 2 +- .../uts/{intel => i86pc}/io/pci/mps_table.h | 8 +- .../io/pci/pci_prd_i86pc.c} | 451 ++++++++++++------ usr/src/uts/{intel => i86pc}/io/pci/pcihrt.h | 8 +- usr/src/uts/i86pc/os/pci_bios.c | 21 + usr/src/uts/i86pc/pci_prd/Makefile | 66 +++ usr/src/uts/i86pc/sys/pci_cfgspace_impl.h | 11 +- usr/src/uts/intel/Makefile.files | 2 +- usr/src/uts/intel/io/pci/pci_autoconfig.c | 27 +- usr/src/uts/intel/io/pci/pci_boot.c | 380 +++------------ usr/src/uts/intel/io/pci/pci_memlist.c | 4 +- usr/src/uts/intel/pci_autoconfig/Makefile | 4 +- 16 files changed, 647 insertions(+), 481 deletions(-) create mode 100644 usr/src/uts/common/sys/plat/pci_prd.h rename usr/src/uts/{intel => i86pc}/io/pci/mps_table.h (95%) rename usr/src/uts/{intel/io/pci/pci_resource.c => i86pc/io/pci/pci_prd_i86pc.c} (64%) rename usr/src/uts/{intel => i86pc}/io/pci/pcihrt.h (91%) create mode 100644 usr/src/uts/i86pc/pci_prd/Makefile diff --git a/usr/src/pkg/manifests/system-kernel-platform.p5m b/usr/src/pkg/manifests/system-kernel-platform.p5m index a7318e04e453..094eb360dbf5 100644 --- a/usr/src/pkg/manifests/system-kernel-platform.p5m +++ b/usr/src/pkg/manifests/system-kernel-platform.p5m @@ -559,6 +559,8 @@ $(i386_ONLY)file path=platform/i86pc/kernel/misc/$(ARCH64)/acpidev group=sys \ mode=0755 $(i386_ONLY)file path=platform/i86pc/kernel/misc/$(ARCH64)/gfx_private \ group=sys mode=0755 +$(i386_ONLY)file path=platform/i86pc/kernel/misc/$(ARCH64)/pci_prd group=sys \ + mode=0755 $(i386_ONLY)dir path=platform/i86pc/ucode group=sys $(i386_ONLY)dir path=platform/i86xpv group=sys $(i386_ONLY)dir path=platform/i86xpv/kernel group=sys diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 71fe53313c95..c05f5ca58fe1 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -1125,6 +1125,9 @@ NXGEHDRS= \ nxge_virtual.h \ nxge_espc.h +PLATHDRS= \ + pci_prd.h + include Makefile.syshdrs dcam/%.check: dcam/%.h @@ -1192,7 +1195,8 @@ CHECKHDRS= \ $(I1394HDRS:%.h=1394/%.check) \ $(RSMHDRS:%.h=rsm/%.check) \ $(TSOLHDRS:%.h=tsol/%.check) \ - $(NXGEHDRS:%.h=nxge/%.check) + $(NXGEHDRS:%.h=nxge/%.check) \ + $(PLATHDRS:%.h=plat/%.check) .KEEP_STATE: @@ -1232,6 +1236,7 @@ CHECKHDRS= \ $(ROOTTAVORHDRS) \ $(ROOTHERMONHDRS) \ $(ROOTMLNXHDRS) \ + $(ROOTPLATHDRS) \ $(ROOTSCSIHDRS) \ $(ROOTSCSIADHDRS) \ $(ROOTSCSICONFHDRS) \ @@ -1300,6 +1305,7 @@ install_h: \ $(ROOTTAVORHDRS) \ $(ROOTHERMONHDRS) \ $(ROOTMLNXHDRS) \ + $(ROOTPLATHDRS) \ $(ROOTSCSIHDRS) \ $(ROOTSCSIADHDRS) \ $(ROOTSCSIISCSIHDRS) \ diff --git a/usr/src/uts/common/sys/plat/pci_prd.h b/usr/src/uts/common/sys/plat/pci_prd.h new file mode 100644 index 000000000000..aa0a7932b822 --- /dev/null +++ b/usr/src/uts/common/sys/plat/pci_prd.h @@ -0,0 +1,130 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2022 Oxide Computer Company + */ + +#ifndef _SYS_PLAT_PCI_PRD_H +#define _SYS_PLAT_PCI_PRD_H + +/* + * PCI Platform Resource Discovery (PRD) + * + * This file forms the platform-specific interfaces that a given platform must + * implement to support the discovery of PCI resources. In particular: + * + * o Any root complexes that do not show up through the use of normal scanning + * o Available resources per root-port including: + * + I/O ports + * + Prefetchable Memory + * + Normal Memory + * + PCI buses + * o The naming of slots (the platform uses the PCIe default) + * + * These interfaces are all expected to be implemented by a platform's 'pci_prd' + * module. This is left as a module and not a part of say, unix, so that it can + * in turn depend on other modules that a platform might require, such as ACPI. + * + * In general, unless otherwise indicated, these interfaces will always be + * called from kernel context, typically during boot. The interfaces will only + * be called from a single thread at this time and any locking is managed at a + * layer outside of the pci_prd interfaces. If the subsystem is using some other + * interfaces that may be used by multiple consumers and needs locking (e.g. + * ACPI), then that still must be considered in the design and implementation. + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Resource types that can be asked after. + */ +typedef enum pci_prd_rsrc { + PCI_PRD_R_IO, + PCI_PRD_R_MMIO, + PCI_PRD_R_PREFETCH, + PCI_PRD_R_BUS +} pci_prd_rsrc_t; + +typedef struct pci_prd_upcalls { + /* + * Return a dev_info_t, if one exists, for this PCI bus. + */ + dev_info_t *(*pru_bus2dip_f)(uint32_t); +} pci_prd_upcalls_t; + +/* + * Initialization and teardown functions that will be used by the PCI + * enumeration code when it attaches and detaches. If all work is done before + * these come up, there is nothing to do; however, after a call to the _init() + * function, it is expected that the platform module will be ready to respond to + * all function calls. + * + * Note that the _fini function may never be called as on a typical system, as + * any PCI(e) devices with attached drivers will result in the PRD consumer + * remaining loaded. + */ +extern int pci_prd_init(pci_prd_upcalls_t *); +extern void pci_prd_fini(void); + +/* + * Return the maximum PCI bus on this platform that should be searched. This + * number is the last bus number that should be scanned. e.g. a value of 0x10 + * indicates that we will search buses [0, 0x10]. In general, it is expected + * that platforms will just return 0xff (PCI_MAX_BUS_NUM - 1) unless for some + * reason it has other knowledge here. + */ +extern uint32_t pci_prd_max_bus(void); + +/* + * Look up a set of resources that should be assigned to the PCI bus. In + * general, it is expected that these are only the buses that are assigned to + * root complexes. + */ +extern struct memlist *pci_prd_find_resource(uint32_t, pci_prd_rsrc_t); + +/* + * Originally when only using BIOS-derived (pre-ACPI) sources on i86pc, the + * ability to utilize data about multiple buses was considered suspect. As such, + * this exists as a way to indicate that resources on each root complex are + * actually valid. + */ +extern boolean_t pci_prd_multi_root_ok(void); + +/* + * This is used to allow the PCI enumeration code to ask the platform about any + * PCI root complexes that it might know about which might not be discovered + * through the normal scanning process. One callback will be emitted for each + * PCI bus via a call to the callback function. The return value of the callback + * function determines whether we should continue iterating (B_TRUE) or + * terminate (B_FALSE). + */ +typedef boolean_t (*pci_prd_root_complex_f)(uint32_t, void *); +extern void pci_prd_root_complex_iter(pci_prd_root_complex_f, void *); + +/* + * Give the chance for a platform file to go through and use knowledge that it + * has (such as the traditional BIOS PCI IRQ routing table) to name the PCI(e) + * slot. + */ +extern void pci_prd_slot_name(uint32_t, dev_info_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PLAT_PCI_PRD_H */ diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files index 3f387f508c52..e29d11b64b8c 100644 --- a/usr/src/uts/i86pc/Makefile.files +++ b/usr/src/uts/i86pc/Makefile.files @@ -25,7 +25,7 @@ # Copyright (c) 2010, Intel Corporation. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # Copyright 2020 Joyent, Inc. -# Copyright 2021 Oxide Computer Company +# Copyright 2022 Oxide Computer Company # Copyright 2021 Jason King # # This Makefile defines file modules in the directory uts/i86pc @@ -287,6 +287,8 @@ VIONA_OBJS += viona_main.o \ PPT_OBJS += ppt.o +PCI_PRD_OBJS += pci_prd_i86pc.o pci_memlist.o + # # Build up defines and paths. # diff --git a/usr/src/uts/i86pc/Makefile.i86pc b/usr/src/uts/i86pc/Makefile.i86pc index e803d338016c..d23b092b0f50 100644 --- a/usr/src/uts/i86pc/Makefile.i86pc +++ b/usr/src/uts/i86pc/Makefile.i86pc @@ -293,7 +293,7 @@ SYS_KMODS += # # 'Misc' Modules (/kernel/misc): # -MISC_KMODS += gfx_private pcie +MISC_KMODS += gfx_private pcie pci_prd MISC_KMODS += acpidev MISC_KMODS += drmach_acpi diff --git a/usr/src/uts/intel/io/pci/mps_table.h b/usr/src/uts/i86pc/io/pci/mps_table.h similarity index 95% rename from usr/src/uts/intel/io/pci/mps_table.h rename to usr/src/uts/i86pc/io/pci/mps_table.h index 8f8c1dc24e3f..df693eb091bb 100644 --- a/usr/src/uts/intel/io/pci/mps_table.h +++ b/usr/src/uts/i86pc/io/pci/mps_table.h @@ -29,8 +29,6 @@ #ifndef _MPS_TABLE_H #define _MPS_TABLE_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -42,7 +40,7 @@ struct mps_fps_hdr { /* MP Floating Pointer Structure */ uchar_t fps_len; /* in paragraph (16-bytes units) */ uchar_t fps_spec_rev; /* MP Spec. version no. */ uchar_t fps_cksum; /* checksum of complete structure */ - uchar_t fps_featinfo1; /* mp feature info byte 1 */ + uchar_t fps_featinfo1; /* mp feature info byte 1 */ uchar_t fps_featinfo2; /* mp feature info byte 2 */ uchar_t fps_featinfo3; /* mp feature info byte 3 */ uchar_t fps_featinfo4; /* mp feature info byte 4 */ @@ -51,7 +49,7 @@ struct mps_fps_hdr { /* MP Floating Pointer Structure */ struct mps_ct_hdr { /* MP Configuration Table Header */ uint32_t ct_sig; /* "PCMP" */ - uint16_t ct_len; /* base configuration in bytes */ + uint16_t ct_len; /* base configuration in bytes */ uchar_t ct_spec_rev; /* MP Spec. version no. */ uchar_t ct_cksum; /* base configuration table checksum */ char ct_oem_id[8]; /* string identifies the manufacturer */ @@ -60,7 +58,7 @@ struct mps_ct_hdr { /* MP Configuration Table Header */ uint16_t ct_oem_tbl_len; /* size of base OEM table in bytes */ uint16_t ct_entry_cnt; /* no. of entries in the base table */ uint32_t ct_local_apic; /* paddr of local APIC */ - uint16_t ct_ext_tbl_len; /* extended table in bytes */ + uint16_t ct_ext_tbl_len; /* extended table in bytes */ uchar_t ct_ext_cksum; /* checksum for the extended table */ }; diff --git a/usr/src/uts/intel/io/pci/pci_resource.c b/usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c similarity index 64% rename from usr/src/uts/intel/io/pci/pci_resource.c rename to usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c index 57dbe12427fd..5ba872655c59 100644 --- a/usr/src/uts/intel/io/pci/pci_resource.c +++ b/usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c @@ -19,54 +19,63 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2016 Joyent, Inc. + * Copyright 2019 Western Digital Corporation * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2022 Oxide Computer Company + */ + +/* + * This file contains the x86 PCI platform resource discovery backend. This uses + * data from a combination of sources, preferring ACPI, if present, and if not, + * falling back to either the PCI hot-plug resource table or the mps tables. * - * pci_resource.c -- routines to retrieve available bus resources from - * the MP Spec. Table and Hotplug Resource Table + * Today, to get information from ACPI we need to start from a dev_info_t. This + * is partly why the PRD interface has a callback for getting information about + * a dev_info_t. It also means we cannot initialize the tables with information + * until all devices have been initially scanned. */ #include #include +#include #include +#include +#include #include #include #include #include +#include #include "mps_table.h" #include "pcihrt.h" -extern int pci_boot_debug; extern int pci_bios_maxbus; -#define dprintf if (pci_boot_debug) printf + +int pci_prd_debug = 0; +#define dprintf if (pci_prd_debug) printf +#define dcmn_err if (pci_prd_debug != 0) cmn_err static int tbl_init = 0; static uchar_t *mps_extp = NULL; static uchar_t *mps_ext_endp = NULL; static struct php_entry *hrt_hpep; -static int hrt_entry_cnt = 0; +static uint_t hrt_entry_cnt = 0; static int acpi_cb_cnt = 0; +static pci_prd_upcalls_t *prd_upcalls; static void mps_probe(void); static void acpi_pci_probe(void); -static int mps_find_bus_res(int, int, struct memlist **); +static int mps_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **); static void hrt_probe(void); -static int hrt_find_bus_res(int, int, struct memlist **); -static int acpi_find_bus_res(int, int, struct memlist **); +static int hrt_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **); +static int acpi_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **); static uchar_t *find_sig(uchar_t *cp, int len, char *sig); static int checksum(unsigned char *cp, int len); static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context); -void bus_res_fini(void); static void acpi_trim_bus_ranges(void); -struct memlist *acpi_io_res[256]; -struct memlist *acpi_mem_res[256]; -struct memlist *acpi_pmem_res[256]; -struct memlist *acpi_bus_res[256]; - /* * -1 = attempt ACPI resource discovery * 0 = don't attempt ACPI resource discovery @@ -74,53 +83,35 @@ struct memlist *acpi_bus_res[256]; */ volatile int acpi_resource_discovery = -1; -struct memlist * -find_bus_res(int bus, int type) -{ - struct memlist *res = NULL; - boolean_t bios = B_TRUE; - - /* if efi-systab property exist, there is no BIOS */ - if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, - "efi-systab")) { - bios = B_FALSE; - } - - if (tbl_init == 0) { - tbl_init = 1; - acpi_pci_probe(); - if (bios) { - hrt_probe(); - mps_probe(); - } - } - - if (acpi_find_bus_res(bus, type, &res) > 0) - return (res); - - if (bios && hrt_find_bus_res(bus, type, &res) > 0) - return (res); +struct memlist *acpi_io_res[PCI_MAX_BUS_NUM]; +struct memlist *acpi_mem_res[PCI_MAX_BUS_NUM]; +struct memlist *acpi_pmem_res[PCI_MAX_BUS_NUM]; +struct memlist *acpi_bus_res[PCI_MAX_BUS_NUM]; - if (bios) - (void) mps_find_bus_res(bus, type, &res); - return (res); -} +/* + * This indicates whether or not we have a traditional x86 BIOS present or not. + */ +static boolean_t pci_prd_have_bios = B_TRUE; +/* + * This value is set up as part of PCI configuration space initialization. + */ +extern int pci_bios_maxbus; static void acpi_pci_probe(void) { ACPI_HANDLE ah; - dev_info_t *dip; int bus; if (acpi_resource_discovery == 0) return; for (bus = 0; bus <= pci_bios_maxbus; bus++) { - /* if no dip or no ACPI handle, no resources to discover */ - dip = pci_bus_res[bus].dip; - if ((dip == NULL) || + dev_info_t *dip; + + dip = prd_upcalls->pru_bus2dip_f(bus); + if (dip == NULL || (ACPI_FAILURE(acpica_get_handle(dip, &ah)))) continue; @@ -142,7 +133,7 @@ acpi_pci_probe(void) * be trimmed to "0..7", in the example). */ static void -acpi_trim_bus_ranges() +acpi_trim_bus_ranges(void) { struct memlist *ranges, *current; int bus; @@ -154,7 +145,7 @@ acpi_trim_bus_ranges() * - there exists at most 1 bus range entry for each bus number * - there are no (broken) ranges that start at the same bus number */ - for (bus = 0; bus < 256; bus++) { + for (bus = 0; bus < PCI_MAX_BUS_NUM; bus++) { struct memlist *prev, *orig, *new; /* skip buses with no range entry */ if ((orig = acpi_bus_res[bus]) == NULL) @@ -211,20 +202,21 @@ acpi_trim_bus_ranges() } static int -acpi_find_bus_res(int bus, int type, struct memlist **res) +acpi_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res) { + ASSERT3U(bus, <, PCI_MAX_BUS_NUM); switch (type) { - case IO_TYPE: + case PCI_PRD_R_IO: *res = acpi_io_res[bus]; break; - case MEM_TYPE: + case PCI_PRD_R_MMIO: *res = acpi_mem_res[bus]; break; - case PREFETCH_TYPE: + case PCI_PRD_R_PREFETCH: *res = acpi_pmem_res[bus]; break; - case BUSRANGE_TYPE: + case PCI_PRD_R_BUS: *res = acpi_bus_res[bus]; break; default: @@ -236,19 +228,6 @@ acpi_find_bus_res(int bus, int type, struct memlist **res) return (memlist_count(*res)); } -void -bus_res_fini(void) -{ - int bus; - - for (bus = 0; bus <= pci_bios_maxbus; bus++) { - memlist_free_all(&acpi_io_res[bus]); - memlist_free_all(&acpi_mem_res[bus]); - memlist_free_all(&acpi_pmem_res[bus]); - memlist_free_all(&acpi_bus_res[bus]); - } -} - static struct memlist ** rlistpp(UINT8 t, UINT8 caching, int bus) { @@ -298,7 +277,7 @@ acpi_dbg(uint_t bus, uint64_t addr, uint64_t len, uint8_t caching, uint8_t type, } -ACPI_STATUS +static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context) { int bus = (intptr_t)context; @@ -332,7 +311,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context) acpi_cb_cnt++; memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum, rp->Data.Io.AddressLength); - if (pci_boot_debug != 0) { + if (pci_prd_debug != 0) { acpi_dbg(bus, rp->Data.Io.Minimum, rp->Data.Io.AddressLength, 0, ACPI_IO_RANGE, "IO"); } @@ -374,7 +353,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context) rp->Data.Address.Info.Mem.Caching, bus), rp->Data.Address16.Address.Minimum, rp->Data.Address16.Address.AddressLength); - if (pci_boot_debug != 0) { + if (pci_prd_debug != 0) { acpi_dbg(bus, rp->Data.Address16.Address.Minimum, rp->Data.Address16.Address.AddressLength, @@ -391,7 +370,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context) rp->Data.Address.Info.Mem.Caching, bus), rp->Data.Address32.Address.Minimum, rp->Data.Address32.Address.AddressLength); - if (pci_boot_debug != 0) { + if (pci_prd_debug != 0) { acpi_dbg(bus, rp->Data.Address32.Address.Minimum, rp->Data.Address32.Address.AddressLength, @@ -409,7 +388,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context) rp->Data.Address.Info.Mem.Caching, bus), rp->Data.Address64.Address.Minimum, rp->Data.Address64.Address.AddressLength); - if (pci_boot_debug != 0) { + if (pci_prd_debug != 0) { acpi_dbg(bus, rp->Data.Address64.Address.Minimum, rp->Data.Address64.Address.AddressLength, @@ -426,7 +405,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context) rp->Data.Address.Info.Mem.Caching, bus), rp->Data.ExtAddress64.Address.Minimum, rp->Data.ExtAddress64.Address.AddressLength); - if (pci_boot_debug != 0) { + if (pci_prd_debug != 0) { acpi_dbg(bus, rp->Data.ExtAddress64.Address.Minimum, rp->Data.ExtAddress64.Address.AddressLength, @@ -450,7 +429,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context) } static void -mps_probe() +mps_probe(void) { uchar_t *extp; struct mps_fps_hdr *fpp = NULL; @@ -521,22 +500,43 @@ mps_probe() static int -mps_find_bus_res(int bus, int type, struct memlist **res) +mps_find_bus_res(uint32_t bus, pci_prd_rsrc_t rsrc, struct memlist **res) { struct sasm *sasmp; uchar_t *extp; - int res_cnt; + int res_cnt, type; + + ASSERT3U(bus, <, PCI_MAX_BUS_NUM); if (mps_extp == NULL) return (0); + + switch (rsrc) { + case PCI_PRD_R_IO: + type = IO_TYPE; + break; + case PCI_PRD_R_MMIO: + type = MEM_TYPE; + break; + case PCI_PRD_R_PREFETCH: + type = PREFETCH_TYPE; + break; + case PCI_PRD_R_BUS: + type = BUSRANGE_TYPE; + break; + default: + *res = NULL; + return (0); + } + extp = mps_extp; res_cnt = 0; while (extp < mps_ext_endp) { switch (*extp) { case SYS_AS_MAPPING: sasmp = (struct sasm *)extp; - if (((int)sasmp->sasm_as_type) == type && - ((int)sasmp->sasm_bus_id) == bus) { + if (sasmp->sasm_as_type == type && + sasmp->sasm_bus_id == bus) { uint64_t base, len; base = (uint64_t)sasmp->sasm_as_base | @@ -558,11 +558,7 @@ mps_find_bus_res(int bus, int type, struct memlist **res) cmn_err(CE_WARN, "Unknown descriptor type %d" " in BIOS Multiprocessor Spec table.", *extp); - while (*res) { - struct memlist *tmp = *res; - *res = tmp->ml_next; - memlist_free(tmp); - } + memlist_free_all(res); return (0); } } @@ -570,7 +566,7 @@ mps_find_bus_res(int bus, int type, struct memlist **res) } static void -hrt_probe() +hrt_probe(void) { struct hrt_hdr *hrtp; @@ -585,44 +581,46 @@ hrt_probe() dprintf("PCI Hot-Plug Resource Table version no. <> 1\n"); return; } - hrt_entry_cnt = (int)hrtp->hrt_entry_cnt; + hrt_entry_cnt = (uint_t)hrtp->hrt_entry_cnt; dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt); hrt_hpep = (struct php_entry *)(hrtp + 1); } static int -hrt_find_bus_res(int bus, int type, struct memlist **res) +hrt_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res) { - int res_cnt, i; + int res_cnt; struct php_entry *hpep; + ASSERT3U(bus, <, PCI_MAX_BUS_NUM); + if (hrt_hpep == NULL || hrt_entry_cnt == 0) return (0); hpep = hrt_hpep; res_cnt = 0; - for (i = 0; i < hrt_entry_cnt; i++, hpep++) { + for (uint_t i = 0; i < hrt_entry_cnt; i++, hpep++) { if (hpep->php_pri_bus != bus) continue; - if (type == IO_TYPE) { + if (type == PCI_PRD_R_IO) { if (hpep->php_io_start == 0 || hpep->php_io_size == 0) continue; memlist_insert(res, (uint64_t)hpep->php_io_start, (uint64_t)hpep->php_io_size); res_cnt++; - } else if (type == MEM_TYPE) { + } else if (type == PCI_PRD_R_MMIO) { if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0) continue; memlist_insert(res, - (uint64_t)(((int)hpep->php_mem_start) << 16), - (uint64_t)(((int)hpep->php_mem_size) << 16)); + ((uint64_t)hpep->php_mem_start) << 16, + ((uint64_t)hpep->php_mem_size) << 16); res_cnt++; - } else if (type == PREFETCH_TYPE) { + } else if (type == PCI_PRD_R_PREFETCH) { if (hpep->php_pfmem_start == 0 || hpep->php_pfmem_size == 0) continue; memlist_insert(res, - (uint64_t)(((int)hpep->php_pfmem_start) << 16), - (uint64_t)(((int)hpep->php_pfmem_size) << 16)); + ((uint64_t)hpep->php_pfmem_start) << 16, + ((uint64_t)hpep->php_pfmem_size) << 16); res_cnt++; } } @@ -656,67 +654,226 @@ checksum(unsigned char *cp, int len) return ((int)(cksum & 0xFF)); } -#ifdef UNUSED_BUS_HIERARY_INFO +uint32_t +pci_prd_max_bus(void) +{ + return ((uint32_t)pci_bios_maxbus); +} + +struct memlist * +pci_prd_find_resource(uint32_t bus, pci_prd_rsrc_t rsrc) +{ + struct memlist *res = NULL; + + if (bus > pci_bios_maxbus) + return (NULL); + + if (tbl_init == 0) { + tbl_init = 1; + acpi_pci_probe(); + if (pci_prd_have_bios) { + hrt_probe(); + mps_probe(); + } + } + + if (acpi_find_bus_res(bus, rsrc, &res) > 0) + return (res); + + if (pci_prd_have_bios && hrt_find_bus_res(bus, rsrc, &res) > 0) + return (res); + + if (pci_prd_have_bios) + (void) mps_find_bus_res(bus, rsrc, &res); + return (res); +} + +typedef struct { + pci_prd_root_complex_f ppac_func; + void *ppac_arg; +} pci_prd_acpi_cb_t; + +static ACPI_STATUS +pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv) +{ + ACPI_DEVICE_INFO *adi; + int busnum; + pci_prd_acpi_cb_t *cb = ctx; + + /* + * Use AcpiGetObjectInfo() to find the device _HID + * If not a PCI root-bus, ignore this device and continue + * the walk + */ + if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi))) + return (AE_OK); + + if (!(adi->Valid & ACPI_VALID_HID)) { + AcpiOsFree(adi); + return (AE_OK); + } + + if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING, + sizeof (PCI_ROOT_HID_STRING)) && + strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING, + sizeof (PCI_EXPRESS_ROOT_HID_STRING))) { + AcpiOsFree(adi); + return (AE_OK); + } + + AcpiOsFree(adi); + + /* + * acpica_get_busno() will check the presence of _BBN and + * fail if not present. It will then use the _CRS method to + * retrieve the actual bus number assigned, it will fall back + * to _BBN should the _CRS method fail. + */ + if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) { + /* + * Ignore invalid _BBN return values here (rather + * than panic) and emit a warning; something else + * may suffer failure as a result of the broken BIOS. + */ + if (busnum < 0) { + dcmn_err(CE_NOTE, + "pci_process_acpi_device: invalid _BBN 0x%x", + busnum); + return (AE_CTRL_DEPTH); + } + + if (cb->ppac_func((uint32_t)busnum, cb->ppac_arg)) + return (AE_CTRL_DEPTH); + return (AE_CTRL_TERMINATE); + } + + /* PCI and no _BBN, continue walk */ + return (AE_OK); +} + +void +pci_prd_root_complex_iter(pci_prd_root_complex_f func, void *arg) +{ + void *rv; + pci_prd_acpi_cb_t cb; + + cb.ppac_func = func; + cb.ppac_arg = arg; + + /* + * First scan ACPI devices for anything that might be here. After that, + * go through and check the old BIOS IRQ routing table for additional + * buses. Note, slot naming from the IRQ table comes later. + */ + (void) AcpiGetDevices(NULL, pci_process_acpi_device, &cb, &rv); + pci_bios_bus_iter(func, arg); + +} + /* - * At this point, the bus hierarchy entries do not appear to - * provide anything we can't find out from PCI config space. - * The only interesting bit is the ISA bus number, which we - * don't care. + * If there is actually a PCI IRQ routing table present, then we want to use + * this to go back and update the slot name. In particular, if we have no PCI + * IRQ routing table, then we use the existing slot names that were already set + * up for us in picex_slot_names_prop() from the capability register. Otherwise, + * we actually delete all slot-names properties from buses and instead use + * something from the IRQ routing table if it exists. + * + * Note, the property is always deleted regardless of whether or not it exists + * in the IRQ routing table. Finally, we have traditionally kept "pcie0" names + * as special as apparently that can't be represented in the IRQ routing table. */ -int -mps_find_parent_bus(int bus) +void +pci_prd_slot_name(uint32_t bus, dev_info_t *dip) { - struct sasm *sasmp; - uchar_t *extp; + char slotprop[256]; + int len; + char *slotcap_name; - if (mps_extp == NULL) - return (-1); + if (pci_irq_nroutes == 0) + return; - extp = mps_extp; - while (extp < mps_ext_endp) { - bhdp = (struct bhd *)extp; - switch (*extp) { - case SYS_AS_MAPPING: - extp += SYS_AS_MAPPING_SIZE; - break; - case BUS_HIERARCHY_DESC: - if (bhdp->bhd_bus_id == bus) - return (bhdp->bhd_parent); - extp += BUS_HIERARCHY_DESC_SIZE; - break; - case COMP_BUS_AS_MODIFIER: - extp += COMP_BUS_AS_MODIFIER_SIZE; - break; - default: - cmn_err(CE_WARN, "Unknown descriptor type %d" - " in BIOS Multiprocessor Spec table.", - *extp); - return (-1); + if (dip != NULL) { + if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pci_bus_res[bus].dip, + DDI_PROP_DONTPASS, "slot-names", &slotcap_name) != + DDI_SUCCESS || strcmp(slotcap_name, "pcie0") != 0) { + (void) ndi_prop_remove(DDI_DEV_T_NONE, + pci_bus_res[bus].dip, "slot-names"); + } + } + + + len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop)); + if (len > 0) { + if (dip != NULL) { + ASSERT((len % sizeof (int)) == 0); + (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, + pci_bus_res[bus].dip, "slot-names", + (int *)slotprop, len / sizeof (int)); + } else { + cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI " + "IRQ routing table; Not adding slot-names " + "property for incorrect bus %d", bus); } } - return (-1); } -int -hrt_find_bus_range(int bus) +boolean_t +pci_prd_multi_root_ok(void) { - int i, max_bus, sub_bus; - struct php_entry *hpep; + return (acpi_resource_discovery > 0); +} - if (hrt_hpep == NULL || hrt_entry_cnt == 0) { - return (-1); +int +pci_prd_init(pci_prd_upcalls_t *upcalls) +{ + if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, + "efi-systab")) { + pci_prd_have_bios = B_FALSE; } - hpep = hrt_hpep; - max_bus = -1; - for (i = 0; i < hrt_entry_cnt; i++, hpep++) { - if (hpep->php_pri_bus != bus) - continue; - sub_bus = (int)hpep->php_subord_bus; - if (sub_bus > max_bus) - max_bus = sub_bus; + + prd_upcalls = upcalls; + + return (0); +} + +void +pci_prd_fini(void) +{ + int bus; + + for (bus = 0; bus <= pci_bios_maxbus; bus++) { + memlist_free_all(&acpi_io_res[bus]); + memlist_free_all(&acpi_mem_res[bus]); + memlist_free_all(&acpi_pmem_res[bus]); + memlist_free_all(&acpi_bus_res[bus]); } - return (max_bus); } -#endif /* UNUSED_BUS_HIERARY_INFO */ +static struct modlmisc pci_prd_modlmisc_i86pc = { + .misc_modops = &mod_miscops, + .misc_linkinfo = "i86pc PCI Resource Discovery" +}; + +static struct modlinkage pci_prd_modlinkage_i86pc = { + .ml_rev = MODREV_1, + .ml_linkage = { &pci_prd_modlmisc_i86pc, NULL } +}; + +int +_init(void) +{ + return (mod_install(&pci_prd_modlinkage_i86pc)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&pci_prd_modlinkage_i86pc, modinfop)); +} + +int +_fini(void) +{ + return (mod_remove(&pci_prd_modlinkage_i86pc)); +} diff --git a/usr/src/uts/intel/io/pci/pcihrt.h b/usr/src/uts/i86pc/io/pci/pcihrt.h similarity index 91% rename from usr/src/uts/intel/io/pci/pcihrt.h rename to usr/src/uts/i86pc/io/pci/pcihrt.h index 7192eca2c54a..7857e0314f60 100644 --- a/usr/src/uts/intel/io/pci/pcihrt.h +++ b/usr/src/uts/i86pc/io/pci/pcihrt.h @@ -31,16 +31,14 @@ #ifndef _PCIHRT_H #define _PCIHRT_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif struct hrt_hdr { /* PCI Hot-Plug Configuration Resource Table header */ - uint32_t hrt_sig; /* $HRT */ + uint32_t hrt_sig; /* $HRT */ uint16_t hrt_avail_imap; /* Bitmap of unused IRQs */ - uint16_t hrt_used_imap; /* Bitmap of IRQs used by PCI */ + uint16_t hrt_used_imap; /* Bitmap of IRQs used by PCI */ uchar_t hrt_entry_cnt; /* no. of PCI hot-plug slot entries */ uchar_t hrt_ver; /* version no. = 1 */ uchar_t hrt_resv0; /* reserved */ @@ -58,7 +56,7 @@ struct php_entry { /* PCI hot-plug slot entry */ uchar_t php_subord_bus; /* Max Subordinate bus of this slot */ uint16_t php_io_start; /* allocated I/O space starting addr */ uint16_t php_io_size; /* allocated I/O space size in bytes */ - uint16_t php_mem_start; /* allocated Memory space start addr */ + uint16_t php_mem_start; /* allocated Memory space start addr */ uint16_t php_mem_size; /* allocated Memory space size in 64k */ uint16_t php_pfmem_start; /* allocated Prefetchable Memory start */ uint16_t php_pfmem_size; /* allocated Prefetchable size in 64k */ diff --git a/usr/src/uts/i86pc/os/pci_bios.c b/usr/src/uts/i86pc/os/pci_bios.c index a24064b8cb43..84653435ad43 100644 --- a/usr/src/uts/i86pc/os/pci_bios.c +++ b/usr/src/uts/i86pc/os/pci_bios.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2022 Oxide Computer Company */ #include @@ -218,3 +219,23 @@ pci_slot_names_prop(int bus, char *buf, int len) *(buf + plen) = 0; return (plen); } + +/* + * This is used to discover additional PCI buses that may exist in the system in + * addition to the ACPI _BBN method. Historically these were discovered by + * asking if there was a valid slot property, e.g. pci_slot_names_prop() + * returned valid data. In this case we return any entry that has a bus number + * and a non-zero slot value. We rely on the core PCI code to do dedup for us. + */ +void +pci_bios_bus_iter(pci_prd_root_complex_f cbfunc, void *arg) +{ + int i; + for (i = 0; i < pci_irq_nroutes; i++) { + if (pci_irq_routes[i].pir_slot != 0) { + if (!cbfunc(pci_irq_routes[i].pir_bus, arg)) { + return; + } + } + } +} diff --git a/usr/src/uts/i86pc/pci_prd/Makefile b/usr/src/uts/i86pc/pci_prd/Makefile new file mode 100644 index 000000000000..ca262cc4a49c --- /dev/null +++ b/usr/src/uts/i86pc/pci_prd/Makefile @@ -0,0 +1,66 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2022 Oxide Computer Company +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = pci_prd +OBJECTS = $(PCI_PRD_OBJS:%=$(OBJS_DIR)/%) +ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/i86pc/Makefile.i86pc + +# +# Define targets +# +ALL_TARGET = $(BINARY) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +LDFLAGS += -Nmisc/acpica + +# +# Overrides +# + +ALL_BUILDS = $(ALL_BUILDSONLY64) +DEF_BUILDS = $(DEF_BUILDSONLY64) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/i86pc/Makefile.targ diff --git a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h index 6cec63bcfdbb..05e0710bbeaa 100644 --- a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h +++ b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h @@ -21,16 +21,18 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2021 Oxide Computer Company + * Copyright 2022 Oxide Computer Company */ #ifndef _SYS_PCI_CFGSPACE_IMPL_H #define _SYS_PCI_CFGSPACE_IMPL_H /* - * Routines to support particular PCI chipsets + * Routines to support particular PCI chipsets and the PCI BIOS. */ +#include + #ifdef __cplusplus extern "C" { #endif @@ -183,6 +185,11 @@ typedef struct pci_irq_route_hdr { } pci_irq_route_hdr_t; #pragma pack() +extern int pci_irq_nroutes; + +extern int pci_slot_names_prop(int, char *, int); +extern void pci_bios_bus_iter(pci_prd_root_complex_f, void *); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index 2e7455a93af2..7f464e2ec887 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -141,7 +141,7 @@ PCIEB_OBJS += pcieb_x86.o PIT_BEEP_OBJS += pit_beep.o POWER_OBJS += power.o PCI_AUTOCONFIG_OBJS += pci_autoconfig.o pci_boot.o pcie_nvidia.o \ - pci_memlist.o pci_resource.o + pci_memlist.o RADEON_OBJS += r300_cmdbuf.o radeon_cp.o radeon_drv.o \ radeon_state.o radeon_irq.o radeon_mem.o SD_OBJS += sd.o sd_xbuf.o diff --git a/usr/src/uts/intel/io/pci/pci_autoconfig.c b/usr/src/uts/intel/io/pci/pci_autoconfig.c index 713493eedb96..af7ba637d8d8 100644 --- a/usr/src/uts/intel/io/pci/pci_autoconfig.c +++ b/usr/src/uts/intel/io/pci/pci_autoconfig.c @@ -21,6 +21,7 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2022 Oxide Computer Company */ /* @@ -40,8 +41,10 @@ #include #include #include +#include extern int pci_boot_debug; +extern int pci_boot_maxbus; /* * Interface routines @@ -49,7 +52,7 @@ extern int pci_boot_debug; void pci_enumerate(int); void pci_setup_tree(void); void pci_reprogram(void); -void bus_res_fini(void); +dev_info_t *pci_boot_bus_to_dip(uint32_t); static struct modlmisc modlmisc = { &mod_miscops, "PCI BIOS interface" @@ -59,13 +62,23 @@ static struct modlinkage modlinkage = { MODREV_1, (void *)&modlmisc, NULL }; +static pci_prd_upcalls_t pci_upcalls = { + .pru_bus2dip_f = pci_boot_bus_to_dip +}; + int _init(void) { int err; - if ((err = mod_install(&modlinkage)) != 0) + if ((err = pci_prd_init(&pci_upcalls)) != 0) { + return (err); + } + + if ((err = mod_install(&modlinkage)) != 0) { + pci_prd_fini(); return (err); + } impl_bus_add_probe(pci_enumerate); return (0); @@ -80,7 +93,7 @@ _fini(void) return (err); impl_bus_delete_probe(pci_enumerate); - bus_res_fini(); + pci_prd_fini(); return (0); } @@ -102,6 +115,14 @@ pci_enumerate(int reprogram) extern void add_pci_fixes(void); extern void undo_pci_fixes(void); + /* + * On our first pass through here actually determine what the maximum + * bus that we should use is. + */ + if (reprogram == 0) { + pci_boot_maxbus = pci_prd_max_bus(); + } + add_pci_fixes(); if (reprogram) { diff --git a/usr/src/uts/intel/io/pci/pci_boot.c b/usr/src/uts/intel/io/pci/pci_boot.c index f2cff30ed3d1..25bae81079e2 100644 --- a/usr/src/uts/intel/io/pci/pci_boot.c +++ b/usr/src/uts/intel/io/pci/pci_boot.c @@ -23,6 +23,7 @@ * Copyright 2019 Joyent, Inc. * Copyright 2019 Western Digital Corporation * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2022 Oxide Computer Company */ /* @@ -101,18 +102,21 @@ * add_pci_fixes() * As for first pass. * pci_reprogram() - * pci_scan_bbn() - * The ACPI namespace is scanned for top-level - * instances of _BBN in order to enumerate the - * root-bridges in the system. If a root bridge is - * found that has not been previously discovered - * (existence inferred through its children) then - * it is added to the system. + * pci_prd_root_complex_iter() + * The platform is asked to tell us of all root + * complexes that it knows about (e.g. using the + * _BBN method via ACPI). This will include buses + * that we've already discovered and those that we + * potentially haven't. Anything that has not been + * previously discovered (or inferred to exist) is + * then added to the system. * * populate_bus_res() * Find resources associated with this root bus - * from either ACPI or BIOS tables. See - * find_bus_res() in pci_resource.c + * based on what the platform provideds through the + * pci platform interfaces defined in + * sys/plat/pci_prd.h. On i86pc this is driven by + * ACPI and BIOS tables. * * fix_ppb_res() * Reprogram pci(e) bridges which have not already @@ -158,7 +162,6 @@ #include #include #include -#include #include #include #include @@ -172,6 +175,7 @@ #include #include #include +#include #define pci_getb (*pci_getb_func) #define pci_getw (*pci_getw_func) @@ -242,16 +246,13 @@ struct pci_devfunc { extern int apic_nvidia_io_max; extern int pseudo_isa; -extern int pci_bios_maxbus; static uchar_t max_dev_pci = 32; /* PCI standard */ +int pci_boot_maxbus; int pci_boot_debug = 0; int pci_debug_bus_start = -1; int pci_debug_bus_end = -1; -extern struct memlist *find_bus_res(int, int); static struct pci_fixundo *undolist = NULL; static int num_root_bus = 0; /* count of root buses */ -extern volatile int acpi_resource_discovery; -extern uint64_t mcfg_mem_base; extern void pci_cfgacc_add_workaround(uint16_t, uchar_t, uchar_t); extern dev_info_t *pcie_get_rc_dip(dev_info_t *); @@ -269,12 +270,11 @@ static void add_ppb_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int, ushort_t); static void add_model_prop(dev_info_t *, uint_t); static void add_bus_range_prop(int); -static void add_bus_slot_names_prop(int); static void add_ranges_prop(int, int); static void add_bus_available_prop(int); static int get_pci_cap(uchar_t bus, uchar_t dev, uchar_t func, uint8_t cap_id); static void fix_ppb_res(uchar_t, boolean_t); -static void alloc_res_array(); +static void alloc_res_array(void); static void create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid, ushort_t deviceid); static void pciex_slot_names_prop(dev_info_t *, ushort_t); @@ -283,7 +283,6 @@ static void memlist_remove_list(struct memlist **list, struct memlist *remove_list); static void ck804_fix_aer_ptr(dev_info_t *, pcie_req_id_t); -static void pci_scan_bbn(void); static int pci_unitaddr_cache_valid(void); static int pci_bus_unitaddr(int); static void pci_unitaddr_cache_create(void); @@ -292,8 +291,6 @@ static int pci_cache_unpack_nvlist(nvf_handle_t, nvlist_t *, char *); static int pci_cache_pack_nvlist(nvf_handle_t, nvlist_t **); static void pci_cache_free_list(nvf_handle_t); -extern int pci_slot_names_prop(int, char *, int); - /* set non-zero to force PCI peer-bus renumbering */ int pci_bus_always_renumber = 0; @@ -326,6 +323,13 @@ typedef struct { nvf_handle_t puafd_handle; int pua_cache_valid = 0; +dev_info_t * +pci_boot_bus_to_dip(uint32_t busno) +{ + ASSERT3U(busno, <=, pci_boot_maxbus); + return (pci_bus_res[busno].dip); +} + static void dump_memlists_impl(const char *tag, int bus) { @@ -356,80 +360,21 @@ dump_memlists_impl(const char *tag, int bus) } } -/*ARGSUSED*/ -static ACPI_STATUS -pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv) +static boolean_t +pci_rc_scan_cb(uint32_t busno, void *arg) { - ACPI_DEVICE_INFO *adi; - int busnum; - - /* - * Use AcpiGetObjectInfo() to find the device _HID - * If not a PCI root-bus, ignore this device and continue - * the walk - */ - if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi))) - return (AE_OK); - - if (!(adi->Valid & ACPI_VALID_HID)) { - AcpiOsFree(adi); - return (AE_OK); - } - - if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING, - sizeof (PCI_ROOT_HID_STRING)) && - strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING, - sizeof (PCI_EXPRESS_ROOT_HID_STRING))) { - AcpiOsFree(adi); - return (AE_OK); + if (busno > pci_boot_maxbus) { + dcmn_err(CE_NOTE, "platform root complex scan returned bus " + "with invalid bus id: 0x%x", busno); + return (B_TRUE); } - AcpiOsFree(adi); - - /* - * acpica_get_busno() will check the presence of _BBN and - * fail if not present. It will then use the _CRS method to - * retrieve the actual bus number assigned, it will fall back - * to _BBN should the _CRS method fail. - */ - if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) { - /* - * Ignore invalid _BBN return values here (rather - * than panic) and emit a warning; something else - * may suffer failure as a result of the broken BIOS. - */ - if ((busnum < 0) || (busnum > pci_bios_maxbus)) { - dcmn_err(CE_NOTE, - "pci_process_acpi_device: invalid _BBN 0x%x", - busnum); - return (AE_CTRL_DEPTH); - } - - /* PCI with valid _BBN */ - if (pci_bus_res[busnum].par_bus == (uchar_t)-1 && - pci_bus_res[busnum].dip == NULL) - create_root_bus_dip((uchar_t)busnum); - return (AE_CTRL_DEPTH); + if (pci_bus_res[busno].par_bus == (uchar_t)-1 && + pci_bus_res[busno].dip == NULL) { + create_root_bus_dip((uchar_t)busno); } - /* PCI and no _BBN, continue walk */ - return (AE_OK); -} - -/* - * Scan the ACPI namespace for all top-level instances of _BBN - * in order to discover childless root-bridges (which enumeration - * may not find; root-bridges are inferred by the existence of - * children). This scan should find all root-bridges that have - * been enumerated, and any childless root-bridges not enumerated. - * Root-bridge for bus 0 may not have a _BBN object. - */ -static void -pci_scan_bbn() -{ - void *rv; - - (void) AcpiGetDevices(NULL, pci_process_acpi_device, NULL, &rv); + return (B_TRUE); } static void @@ -596,7 +541,7 @@ pci_unitaddr_cache_create(void) index = 0; listp = nvf_list(puafd_handle); - for (i = 0; i <= pci_bios_maxbus; i++) { + for (i = 0; i <= pci_boot_maxbus; i++) { /* skip non-root (peer) PCI busses */ if ((pci_bus_res[i].par_bus != (uchar_t)-1) || (pci_bus_res[i].dip == NULL)) @@ -622,7 +567,7 @@ pci_setup_tree(void) uint_t i, root_bus_addr = 0; alloc_res_array(); - for (i = 0; i <= pci_bios_maxbus; i++) { + for (i = 0; i <= pci_boot_maxbus; i++) { pci_bus_res[i].par_bus = (uchar_t)-1; pci_bus_res[i].root_addr = (uchar_t)-1; pci_bus_res[i].sub_bus = i; @@ -635,7 +580,7 @@ pci_setup_tree(void) /* * Now enumerate peer busses * - * We loop till pci_bios_maxbus. On most systems, there is + * We loop till pci_boot_maxbus. On most systems, there is * one more bus at the high end, which implements the ISA * compatibility bus. We don't care about that. * @@ -646,144 +591,11 @@ pci_setup_tree(void) * However, we stop enumerating phantom peers with no * device below. */ - for (i = 1; i <= pci_bios_maxbus; i++) { + for (i = 1; i <= pci_boot_maxbus; i++) { if (pci_bus_res[i].dip == NULL) { pci_bus_res[i].root_addr = root_bus_addr++; } enumerate_bus_devs(i, CONFIG_INFO); - - /* add slot-names property for named pci hot-plug slots */ - add_bus_slot_names_prop(i); - } -} - -/* - * >0 = present, 0 = not present, <0 = error - */ -static int -pci_bbn_present(int bus) -{ - ACPI_HANDLE hdl; - int rv; - - /* no dip means no _BBN */ - if (pci_bus_res[bus].dip == NULL) - return (0); - - rv = -1; /* default return value in case of error below */ - if (ACPI_SUCCESS(acpica_get_handle(pci_bus_res[bus].dip, &hdl))) { - switch (AcpiEvaluateObject(hdl, "_BBN", NULL, NULL)) { - case AE_OK: - rv = 1; - break; - case AE_NOT_FOUND: - rv = 0; - break; - default: - break; - } - } - - return (rv); -} - -/* - * Return non-zero if any PCI bus in the system has an associated - * _BBN object, 0 otherwise. - */ -static int -pci_roots_have_bbn(void) -{ - int i; - - /* - * Scan the PCI busses and look for at least 1 _BBN - */ - for (i = 0; i <= pci_bios_maxbus; i++) { - /* skip non-root (peer) PCI busses */ - if (pci_bus_res[i].par_bus != (uchar_t)-1) - continue; - - if (pci_bbn_present(i) > 0) - return (1); - } - return (0); - -} - -/* - * return non-zero if the machine is one on which we renumber - * the internal pci unit-addresses - */ -static int -pci_bus_renumber() -{ - ACPI_TABLE_HEADER *fadt; - - if (pci_bus_always_renumber) - return (1); - - /* get the FADT */ - if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) != - AE_OK) - return (0); - - /* compare OEM Table ID to "SUNm31" */ - if (strncmp("SUNm31", fadt->OemId, 6)) - return (0); - else - return (1); -} - -/* - * Initial enumeration of the physical PCI bus hierarchy can - * leave 'gaps' in the order of peer PCI bus unit-addresses. - * Systems with more than one peer PCI bus *must* have an ACPI - * _BBN object associated with each peer bus; use the presence - * of this object to remove gaps in the numbering of the peer - * PCI bus unit-addresses - only peer busses with an associated - * _BBN are counted. - */ -static void -pci_renumber_root_busses(void) -{ - int pci_regs[] = {0, 0, 0}; - int i, root_addr = 0; - - /* - * Currently, we only enable the re-numbering on specific - * Sun machines; this is a work-around for the more complicated - * issue of upgrade changing physical device paths - */ - if (!pci_bus_renumber()) - return; - - /* - * If we find no _BBN objects at all, we either don't need - * to do anything or can't do anything anyway - */ - if (!pci_roots_have_bbn()) - return; - - for (i = 0; i <= pci_bios_maxbus; i++) { - /* skip non-root (peer) PCI busses */ - if (pci_bus_res[i].par_bus != (uchar_t)-1) - continue; - - if (pci_bbn_present(i) < 1) { - pci_bus_res[i].root_addr = (uchar_t)-1; - continue; - } - - ASSERT(pci_bus_res[i].dip != NULL); - if (pci_bus_res[i].root_addr != root_addr) { - /* update reg property for node */ - pci_bus_res[i].root_addr = root_addr; - pci_regs[0] = pci_bus_res[i].root_addr; - (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, - pci_bus_res[i].dip, "reg", (int *)pci_regs, 3); - } - root_addr++; } } @@ -810,12 +622,12 @@ remove_subtractive_res() int i, j; struct memlist *list; - for (i = 0; i <= pci_bios_maxbus; i++) { + for (i = 0; i <= pci_boot_maxbus; i++) { if (pci_bus_res[i].subtractive) { /* remove used io ports */ list = pci_bus_res[i].io_used; while (list) { - for (j = 0; j <= pci_bios_maxbus; j++) + for (j = 0; j <= pci_boot_maxbus; j++) (void) memlist_remove( &pci_bus_res[j].io_avail, list->ml_address, list->ml_size); @@ -824,7 +636,7 @@ remove_subtractive_res() /* remove used mem resource */ list = pci_bus_res[i].mem_used; while (list) { - for (j = 0; j <= pci_bios_maxbus; j++) { + for (j = 0; j <= pci_boot_maxbus; j++) { (void) memlist_remove( &pci_bus_res[j].mem_avail, list->ml_address, list->ml_size); @@ -837,7 +649,7 @@ remove_subtractive_res() /* remove used prefetchable mem resource */ list = pci_bus_res[i].pmem_used; while (list) { - for (j = 0; j <= pci_bios_maxbus; j++) { + for (j = 0; j <= pci_boot_maxbus; j++) { (void) memlist_remove( &pci_bus_res[j].pmem_avail, list->ml_address, list->ml_size); @@ -905,7 +717,7 @@ get_parbus_res(uchar_t parbus, uchar_t bus, uint64_t size, uint64_t align, * accounted for in this case. */ if ((pci_bus_res[parbus].par_bus == (uchar_t)-1) && - (num_root_bus > 1) && (acpi_resource_discovery <= 0)) { + (num_root_bus > 1) && !pci_prd_multi_root_ok()) { return (0); } @@ -1593,10 +1405,16 @@ pci_reprogram(void) int bus; /* - * Scan ACPI namespace for _BBN objects, make sure that - * childless root-bridges appear in devinfo tree + * Ask platform code for all of the root complexes it knows about in + * case we have missed anything in the scan. This is to ensure that we + * have them show up in the devinfo tree. This scan should find any + * existing entries as well. After this, go through each bus and + * ask the platform if it wants to change the name of the slot. */ - pci_scan_bbn(); + pci_prd_root_complex_iter(pci_rc_scan_cb, NULL); + for (bus = 0; bus <= pci_boot_maxbus; bus++) { + pci_prd_slot_name(bus, pci_bus_res[bus].dip); + } pci_unitaddr_cache_init(); /* @@ -1607,7 +1425,7 @@ pci_reprogram(void) int new_addr; int index = 0; - for (bus = 0; bus <= pci_bios_maxbus; bus++) { + for (bus = 0; bus <= pci_boot_maxbus; bus++) { /* skip non-root (peer) PCI busses */ if ((pci_bus_res[bus].par_bus != (uchar_t)-1) || (pci_bus_res[bus].dip == NULL)) @@ -1626,14 +1444,13 @@ pci_reprogram(void) } } else { /* perform legacy processing */ - pci_renumber_root_busses(); pci_unitaddr_cache_create(); } /* * Do root-bus resource discovery */ - for (bus = 0; bus <= pci_bios_maxbus; bus++) { + for (bus = 0; bus <= pci_boot_maxbus; bus++) { /* skip non-root (peer) PCI busses */ if (pci_bus_res[bus].par_bus != (uchar_t)-1) continue; @@ -1683,7 +1500,7 @@ pci_reprogram(void) memlist_free_all(&isa_res.mem_used); /* add bus-range property for root/peer bus nodes */ - for (i = 0; i <= pci_bios_maxbus; i++) { + for (i = 0; i <= pci_boot_maxbus; i++) { /* create bus-range property on root/peer buses */ if (pci_bus_res[i].par_bus == (uchar_t)-1) add_bus_range_prop(i); @@ -1705,10 +1522,10 @@ pci_reprogram(void) /* reprogram the non-subtractive PPB */ if (pci_reconfig) - for (i = 0; i <= pci_bios_maxbus; i++) + for (i = 0; i <= pci_boot_maxbus; i++) fix_ppb_res(i, B_FALSE); - for (i = 0; i <= pci_bios_maxbus; i++) { + for (i = 0; i <= pci_boot_maxbus; i++) { /* configure devices not configured by BIOS */ if (pci_reconfig) { /* @@ -1722,7 +1539,7 @@ pci_reprogram(void) } /* All dev programmed, so we can create available prop */ - for (i = 0; i <= pci_bios_maxbus; i++) + for (i = 0; i <= pci_boot_maxbus; i++) add_bus_available_prop(i); } @@ -1734,10 +1551,11 @@ populate_bus_res(uchar_t bus) { /* scan BIOS structures */ - pci_bus_res[bus].pmem_avail = find_bus_res(bus, PREFETCH_TYPE); - pci_bus_res[bus].mem_avail = find_bus_res(bus, MEM_TYPE); - pci_bus_res[bus].io_avail = find_bus_res(bus, IO_TYPE); - pci_bus_res[bus].bus_avail = find_bus_res(bus, BUSRANGE_TYPE); + pci_bus_res[bus].pmem_avail = pci_prd_find_resource(bus, + PCI_PRD_R_PREFETCH); + pci_bus_res[bus].mem_avail = pci_prd_find_resource(bus, PCI_PRD_R_MMIO); + pci_bus_res[bus].io_avail = pci_prd_find_resource(bus, PCI_PRD_R_IO); + pci_bus_res[bus].bus_avail = pci_prd_find_resource(bus, PCI_PRD_R_BUS); /* * attempt to initialize sub_bus from the largest range-end @@ -2054,7 +1872,7 @@ add_pci_fixes(void) { int i; - for (i = 0; i <= pci_bios_maxbus; i++) { + for (i = 0; i <= pci_boot_maxbus; i++) { /* * For each bus, apply needed fixes to the appropriate devices. * This must be done before the main enumeration loop because @@ -3197,8 +3015,8 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func, * Some BIOSes lie about max pci busses, we allow for * such mistakes here */ - if (subbus > pci_bios_maxbus) { - pci_bios_maxbus = subbus; + if (subbus > pci_boot_maxbus) { + pci_boot_maxbus = subbus; alloc_res_array(); } @@ -3435,66 +3253,6 @@ add_bus_range_prop(int bus) "bus-range", (int *)bus_range, 2); } -/* - * Add slot-names property for any named pci hot-plug slots - */ -static void -add_bus_slot_names_prop(int bus) -{ - char slotprop[256]; - int len; - extern int pci_irq_nroutes; - char *slotcap_name; - - /* - * If no irq routing table, then go with the slot-names as set up - * in pciex_slot_names_prop() from slot capability register (if any). - */ - if (pci_irq_nroutes == 0) - return; - - /* - * Otherise delete the slot-names we already have and use the irq - * routing table values as returned by pci_slot_names_prop() instead, - * but keep any property of value "pcie0" as that can't be represented - * in the irq routing table. - */ - if (pci_bus_res[bus].dip != NULL) { - if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pci_bus_res[bus].dip, - DDI_PROP_DONTPASS, "slot-names", &slotcap_name) != - DDI_SUCCESS || strcmp(slotcap_name, "pcie0") != 0) - (void) ndi_prop_remove(DDI_DEV_T_NONE, - pci_bus_res[bus].dip, "slot-names"); - } - - len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop)); - if (len > 0) { - /* - * Only create a peer bus node if this bus may be a peer bus. - * It may be a peer bus if the dip is NULL and if par_bus is - * -1 (par_bus is -1 if this bus was not found to be - * subordinate to any PCI-PCI bridge). - * If it's not a peer bus, then the ACPI BBN-handling code - * will remove it later. - */ - if (pci_bus_res[bus].par_bus == (uchar_t)-1 && - pci_bus_res[bus].dip == NULL) { - - create_root_bus_dip(bus); - } - if (pci_bus_res[bus].dip != NULL) { - ASSERT((len % sizeof (int)) == 0); - (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, - pci_bus_res[bus].dip, "slot-names", - (int *)slotprop, len / sizeof (int)); - } else { - cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI " - "IRQ routing table; Not adding slot-names " - "property for incorrect bus %d", bus); - } - } -} - /* * Handle both PCI root and PCI-PCI bridge range properties; * non-zero 'ppb' argument select PCI-PCI bridges versus root. @@ -3652,11 +3410,11 @@ add_bus_available_prop(int bus) static void alloc_res_array(void) { - static int array_size = 0; - int old_size; + static uint_t array_size = 0; + uint_t old_size; void *old_res; - if (array_size > pci_bios_maxbus + 1) + if (array_size > pci_boot_maxbus + 1) return; /* array is big enough */ old_size = array_size; @@ -3665,7 +3423,7 @@ alloc_res_array(void) if (array_size == 0) array_size = 16; /* start with a reasonable number */ - while (array_size <= pci_bios_maxbus + 1) + while (array_size <= pci_boot_maxbus + 1) array_size <<= 1; pci_bus_res = (struct pci_bus_resource *)kmem_zalloc( array_size * sizeof (struct pci_bus_resource), KM_SLEEP); diff --git a/usr/src/uts/intel/io/pci/pci_memlist.c b/usr/src/uts/intel/io/pci/pci_memlist.c index 578659142027..4da76951e9bc 100644 --- a/usr/src/uts/intel/io/pci/pci_memlist.c +++ b/usr/src/uts/intel/io/pci/pci_memlist.c @@ -40,8 +40,8 @@ #include #include -extern int pci_boot_debug; -#define dprintf if (pci_boot_debug) printf +int pci_memlist_debug; +#define dprintf if (pci_memlist_debug) printf void memlist_dump(struct memlist *listp) diff --git a/usr/src/uts/intel/pci_autoconfig/Makefile b/usr/src/uts/intel/pci_autoconfig/Makefile index 74498aea9447..f3c034cb0370 100644 --- a/usr/src/uts/intel/pci_autoconfig/Makefile +++ b/usr/src/uts/intel/pci_autoconfig/Makefile @@ -57,9 +57,9 @@ ALL_TARGET = $(BINARY) INSTALL_TARGET = $(BINARY) $(ROOTMODULE) # -# Depends on acpica ACPI CA interpreter and PCI-E framework +# Depends on the platform's resource discovery and PCI-E framework # -LDFLAGS += -Nmisc/acpica -Nmisc/pcie +LDFLAGS += -Nmisc/pcie -Nmisc/pci_prd # # Default build targets.