summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/io/pci/pci_boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/intel/io/pci/pci_boot.c')
-rw-r--r--usr/src/uts/intel/io/pci/pci_boot.c87
1 files changed, 86 insertions, 1 deletions
diff --git a/usr/src/uts/intel/io/pci/pci_boot.c b/usr/src/uts/intel/io/pci/pci_boot.c
index 3a3f468f71..a50d147f25 100644
--- a/usr/src/uts/intel/io/pci/pci_boot.c
+++ b/usr/src/uts/intel/io/pci/pci_boot.c
@@ -29,10 +29,11 @@
#include <sys/sunndi.h>
#include <sys/pci.h>
#include <sys/pci_impl.h>
-#include <sys/pci_cfgspace.h>
+#include <sys/pcie_impl.h>
#include <sys/memlist.h>
#include <sys/bootconf.h>
#include <io/pci/mps_table.h>
+#include <sys/pci_cfgacc.h>
#include <sys/pci_cfgspace.h>
#include <sys/pci_cfgspace_impl.h>
#include <sys/psw.h>
@@ -45,6 +46,7 @@
#include <sys/intel_iommu.h>
#include <sys/iommulib.h>
#include <sys/devcache.h>
+#include <sys/pci_cfgacc_x86.h>
#define pci_getb (*pci_getb_func)
#define pci_getw (*pci_getw_func)
@@ -107,6 +109,9 @@ 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 *);
/*
* Module prototypes
@@ -134,6 +139,8 @@ static void pciex_slot_names_prop(dev_info_t *, ushort_t);
static void populate_bus_res(uchar_t bus);
static void memlist_remove_list(struct memlist **list,
struct memlist *remove_list);
+static boolean_t is_pcie_platform(void);
+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);
@@ -453,6 +460,13 @@ pci_setup_tree(void)
{
uint_t i, root_bus_addr = 0;
+ /*
+ * enable mem-mapped pci config space accessing,
+ * if failed to do so during early boot
+ */
+ if ((mcfg_mem_base == NULL) && is_pcie_platform())
+ mcfg_mem_base = 0xE0000000;
+
alloc_res_array();
for (i = 0; i <= pci_bios_maxbus; i++) {
pci_bus_res[i].par_bus = (uchar_t)-1;
@@ -1864,6 +1878,7 @@ process_devfunc(uchar_t bus, uchar_t dev, uchar_t func, uchar_t header,
ushort_t is_pci_bridge = 0;
struct pci_devfunc *devlist = NULL, *entry = NULL;
gfx_entry_t *gfxp;
+ pcie_req_id_t bdf;
ushort_t deviceid = pci_getw(bus, dev, func, PCI_CONF_DEVID);
@@ -1925,6 +1940,28 @@ process_devfunc(uchar_t bus, uchar_t dev, uchar_t func, uchar_t header,
&is_pci_bridge) == B_TRUE)
pciex = 1;
+ bdf = PCI_GETBDF(bus, dev, func);
+ /*
+ * Record BAD AMD bridges which don't support MMIO config access.
+ */
+ if (IS_BAD_AMD_NTBRIDGE(vendorid, deviceid) ||
+ IS_AMD_8132_CHIP(vendorid, deviceid)) {
+ uchar_t secbus = 0;
+ uchar_t subbus = 0;
+
+ if ((basecl == PCI_CLASS_BRIDGE) &&
+ (subcl == PCI_BRIDGE_PCI)) {
+ secbus = pci_getb(bus, dev, func, PCI_BCNF_SECBUS);
+ subbus = pci_getb(bus, dev, func, PCI_BCNF_SUBBUS);
+ }
+ pci_cfgacc_add_workaround(bdf, secbus, subbus);
+ }
+
+ if (mcfg_mem_base != NULL) {
+ ck804_fix_aer_ptr(dip, bdf);
+ (void) pcie_init_bus(dip, bdf, PCIE_BUS_INITIAL);
+ }
+
/* add properties */
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id", deviceid);
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id", vendorid);
@@ -3289,3 +3326,51 @@ pciex_slot_names_prop(dev_info_t *dip, ushort_t slot_num)
(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "slot-names",
(int *)slotprop, len / sizeof (int));
}
+
+/*
+ * This is currently a hack, a better way is needed to determine if it
+ * is a PCIE platform.
+ */
+static boolean_t
+is_pcie_platform()
+{
+ uint8_t bus;
+
+ for (bus = 0; bus < pci_bios_maxbus; bus++) {
+ if (look_for_any_pciex_device(bus))
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Enable reporting of AER capability next pointer.
+ * This needs to be done only for CK8-04 devices
+ * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
+ * NOTE: BIOS is disabling this, it needs to be enabled temporarily
+ *
+ * This function is adapted from npe_ck804_fix_aer_ptr(), and is
+ * called from pci_boot.c.
+ */
+static void
+ck804_fix_aer_ptr(dev_info_t *dip, pcie_req_id_t bdf)
+{
+ dev_info_t *rcdip;
+ ushort_t cya1;
+
+ rcdip = pcie_get_rc_dip(dip);
+ ASSERT(rcdip != NULL);
+
+ if ((pci_cfgacc_get16(rcdip, bdf, PCI_CONF_VENID) ==
+ NVIDIA_VENDOR_ID) &&
+ (pci_cfgacc_get16(rcdip, bdf, PCI_CONF_DEVID) ==
+ NVIDIA_CK804_DEVICE_ID) &&
+ (pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID) >=
+ NVIDIA_CK804_AER_VALID_REVID)) {
+ cya1 = pci_cfgacc_get16(rcdip, bdf, NVIDIA_CK804_VEND_CYA1_OFF);
+ if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
+ (void) pci_cfgacc_put16(rcdip, bdf,
+ NVIDIA_CK804_VEND_CYA1_OFF,
+ cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
+ }
+}