xref: /illumos-gate/usr/src/uts/i86pc/io/pciex/npe_misc.c (revision 2654012f83cec5dc15b61dfe3e4a4915f186e7a6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *	Library file that has miscellaneous support for npe(7d)
29  */
30 
31 #include <sys/conf.h>
32 #include <sys/pci.h>
33 #include <sys/sunndi.h>
34 #include <sys/acpi/acpi.h>
35 #include <sys/acpi/acpi_pci.h>
36 #include <sys/acpica.h>
37 #include <sys/pci_cap.h>
38 #include <sys/pcie_impl.h>
39 #include <io/pciex/pcie_nvidia.h>
40 #include <io/pciex/pcie_nb5000.h>
41 
42 /*
43  * Prototype declaration
44  */
45 void	npe_query_acpi_mcfg(dev_info_t *dip);
46 void	npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
47 int	npe_disable_empty_bridges_workaround(dev_info_t *child);
48 void	npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl);
49 void	npe_intel_error_mask(ddi_acc_handle_t cfg_hdl);
50 
51 /*
52  * Default ecfga base address
53  */
54 int64_t npe_default_ecfga_base = 0xE0000000;
55 
56 extern uint32_t	npe_aer_uce_mask;
57 extern boolean_t pcie_full_scan;
58 
59 /*
60  * Query the MCFG table using ACPI.  If MCFG is found, setup the
61  * 'ecfga-base-address' (Enhanced Configuration Access base address)
62  * property accordingly.  Otherwise, set the value of the property
63  * to the default value.
64  */
65 void
66 npe_query_acpi_mcfg(dev_info_t *dip)
67 {
68 	MCFG_TABLE *mcfgp;
69 	CFG_BASE_ADDR_ALLOC *cfg_baap;
70 	char *cfg_baa_endp;
71 	uint64_t ecfga_base;
72 
73 	/* Query the MCFG table using ACPI */
74 	if (AcpiGetTable(ACPI_SIG_MCFG, 1, (ACPI_TABLE_HEADER **)&mcfgp) ==
75 	    AE_OK) {
76 
77 		cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
78 		cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
79 
80 		while ((char *)cfg_baap < cfg_baa_endp) {
81 			ecfga_base = cfg_baap->base_addr;
82 			if (ecfga_base != (uint64_t)0) {
83 				/*
84 				 * Setup the 'ecfga-base-address' property to
85 				 * the base_addr found in the MCFG and return.
86 				 */
87 				(void) ndi_prop_update_int64(DDI_DEV_T_NONE,
88 				    dip, "ecfga-base-address", ecfga_base);
89 				return;
90 			}
91 			cfg_baap++;
92 		}
93 	}
94 	/*
95 	 * If MCFG is not found or ecfga_base is not found in MCFG table,
96 	 * set the 'ecfga-base-address' property to the default value.
97 	 */
98 	(void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
99 	    "ecfga-base-address", npe_default_ecfga_base);
100 }
101 
102 
103 /*
104  * Enable reporting of AER capability next pointer.
105  * This needs to be done only for CK8-04 devices
106  * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
107  * NOTE: BIOS is disabling this, it needs to be enabled temporarily
108  */
109 void
110 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
111 {
112 	ushort_t cya1;
113 
114 	if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
115 	    (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
116 	    NVIDIA_CK804_DEVICE_ID) &&
117 	    (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
118 	    NVIDIA_CK804_AER_VALID_REVID)) {
119 		cya1 =  pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
120 		if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
121 			(void) pci_config_put16(cfg_hdl,
122 			    NVIDIA_CK804_VEND_CYA1_OFF,
123 			    cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
124 	}
125 }
126 
127 /*
128  * If the bridge is empty, disable it
129  */
130 int
131 npe_disable_empty_bridges_workaround(dev_info_t *child)
132 {
133 	/*
134 	 * Do not bind drivers to empty bridges.
135 	 * Fail above, if the bridge is found to be hotplug capable
136 	 */
137 	if (ddi_driver_major(child) == ddi_name_to_major("pcie_pci") &&
138 	    ddi_get_child(child) == NULL &&
139 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
140 	    "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
141 		return (1);
142 
143 	return (0);
144 }
145 
146 void
147 npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl) {
148 	uint32_t regs;
149 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
150 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
151 
152 	if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
153 		/* Disable ECRC for all devices */
154 		regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
155 		    PCIE_AER_UCE_ECRC;
156 		pcie_set_aer_uce_mask(regs);
157 
158 		/*
159 		 * Turn full scan on since the Error Source ID register may not
160 		 * have the correct ID.
161 		 */
162 		pcie_full_scan = B_TRUE;
163 	}
164 }
165 
166 void
167 npe_intel_error_mask(ddi_acc_handle_t cfg_hdl) {
168 	uint32_t regs;
169 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
170 
171 	if (vendor_id == INTEL_VENDOR_ID) {
172 		/*
173 		 * Due to an errata in Intel's ESB2 southbridge, all ECRCs
174 		 * generation/checking need to be disabled.  There is a
175 		 * workaround by setting a proprietary bit in the ESB2, but it
176 		 * is not well documented or understood.  If that bit is set in
177 		 * the future, then ECRC generation/checking should be enabled
178 		 * again.
179 		 *
180 		 * Disable ECRC generation/checking by masking ECRC in the AER
181 		 * UE Mask.  The pcie misc module would then automatically
182 		 * disable ECRC generation/checking in the AER Control register.
183 		 */
184 		regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
185 		pcie_set_aer_uce_mask(regs);
186 	}
187 }
188