xref: /illumos-gate/usr/src/uts/i86pc/io/pciex/npe_misc.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
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 <sys/x86_archext.h>
40 #include <io/pciex/pcie_nvidia.h>
41 #include <io/pciex/pcie_nb5000.h>
42 
43 /*
44  * Prototype declaration
45  */
46 void	npe_query_acpi_mcfg(dev_info_t *dip);
47 void	npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
48 int	npe_disable_empty_bridges_workaround(dev_info_t *child);
49 void	npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl);
50 void	npe_intel_error_mask(ddi_acc_handle_t cfg_hdl);
51 boolean_t npe_is_child_pci(dev_info_t *dip);
52 boolean_t check_and_set_mmcfg(dev_info_t *dip);
53 
54 /*
55  * Default ecfga base address
56  */
57 int64_t npe_default_ecfga_base = 0xE0000000;
58 
59 extern uint32_t	npe_aer_uce_mask;
60 extern boolean_t pcie_full_scan;
61 
62 /* AMD's northbridges vendor-id and device-ids */
63 #define	AMD_NTBRDIGE_VID		0x1022	/* AMD vendor-id */
64 #define	AMD_HT_NTBRIDGE_DID		0x1100	/* HT Configuration */
65 #define	AMD_AM_NTBRIDGE_DID		0x1101	/* Address Map */
66 #define	AMD_DC_NTBRIDGE_DID		0x1102	/* DRAM Controller */
67 #define	AMD_MC_NTBRIDGE_DID		0x1103	/* Misc Controller */
68 #define	AMD_K10_NTBRIDGE_DID_0		0x1200
69 #define	AMD_K10_NTBRIDGE_DID_1		0x1201
70 #define	AMD_K10_NTBRIDGE_DID_2		0x1202
71 #define	AMD_K10_NTBRIDGE_DID_3		0x1203
72 #define	AMD_K10_NTBRIDGE_DID_4		0x1204
73 
74 /*
75  * Check if the given device is an AMD northbridge
76  */
77 #define	IS_BAD_AMD_NTBRIDGE(vid, did) \
78 	    (((vid) == AMD_NTBRDIGE_VID) && \
79 	    (((did) == AMD_HT_NTBRIDGE_DID) || \
80 	    ((did) == AMD_AM_NTBRIDGE_DID) || \
81 	    ((did) == AMD_DC_NTBRIDGE_DID) || \
82 	    ((did) == AMD_MC_NTBRIDGE_DID)))
83 
84 #define	IS_K10_AMD_NTBRIDGE(vid, did) \
85 	    (((vid) == AMD_NTBRDIGE_VID) && \
86 	    (((did) == AMD_K10_NTBRIDGE_DID_0) || \
87 	    ((did) == AMD_K10_NTBRIDGE_DID_1) || \
88 	    ((did) == AMD_K10_NTBRIDGE_DID_2) || \
89 	    ((did) == AMD_K10_NTBRIDGE_DID_3) || \
90 	    ((did) == AMD_K10_NTBRIDGE_DID_4)))
91 
92 #define	MSR_AMD_NB_MMIO_CFG_BADDR	0xc0010058
93 #define	AMD_MMIO_CFG_BADDR_ADDR_MASK	0xFFFFFFF00000ULL
94 #define	AMD_MMIO_CFG_BADDR_ENA_MASK	0x000000000001ULL
95 #define	AMD_MMIO_CFG_BADDR_ENA_ON	0x000000000001ULL
96 #define	AMD_MMIO_CFG_BADDR_ENA_OFF	0x000000000000ULL
97 
98 
99 /*
100  * Query the MCFG table using ACPI.  If MCFG is found, setup the
101  * 'ecfga-base-address' (Enhanced Configuration Access base address)
102  * property accordingly.  Otherwise, set the value of the property
103  * to the default value.
104  */
105 void
106 npe_query_acpi_mcfg(dev_info_t *dip)
107 {
108 	MCFG_TABLE *mcfgp;
109 	CFG_BASE_ADDR_ALLOC *cfg_baap;
110 	char *cfg_baa_endp;
111 	uint64_t ecfga_base;
112 
113 	/* Query the MCFG table using ACPI */
114 	if (AcpiGetTable(ACPI_SIG_MCFG, 1, (ACPI_TABLE_HEADER **)&mcfgp) ==
115 	    AE_OK) {
116 
117 		cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
118 		cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
119 
120 		while ((char *)cfg_baap < cfg_baa_endp) {
121 			ecfga_base = cfg_baap->base_addr;
122 			if (ecfga_base != (uint64_t)0) {
123 				/*
124 				 * Setup the 'ecfga-base-address' property to
125 				 * the base_addr found in the MCFG and return.
126 				 */
127 				(void) ndi_prop_update_int64(DDI_DEV_T_NONE,
128 				    dip, "ecfga-base-address", ecfga_base);
129 				return;
130 			}
131 			cfg_baap++;
132 		}
133 	}
134 	/*
135 	 * If MCFG is not found or ecfga_base is not found in MCFG table,
136 	 * set the 'ecfga-base-address' property to the default value.
137 	 */
138 	(void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
139 	    "ecfga-base-address", npe_default_ecfga_base);
140 }
141 
142 
143 /*
144  * Enable reporting of AER capability next pointer.
145  * This needs to be done only for CK8-04 devices
146  * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
147  * NOTE: BIOS is disabling this, it needs to be enabled temporarily
148  */
149 void
150 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
151 {
152 	ushort_t cya1;
153 
154 	if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
155 	    (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
156 	    NVIDIA_CK804_DEVICE_ID) &&
157 	    (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
158 	    NVIDIA_CK804_AER_VALID_REVID)) {
159 		cya1 =  pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
160 		if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
161 			(void) pci_config_put16(cfg_hdl,
162 			    NVIDIA_CK804_VEND_CYA1_OFF,
163 			    cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
164 	}
165 }
166 
167 /*
168  * If the bridge is empty, disable it
169  */
170 int
171 npe_disable_empty_bridges_workaround(dev_info_t *child)
172 {
173 	/*
174 	 * Do not bind drivers to empty bridges.
175 	 * Fail above, if the bridge is found to be hotplug capable
176 	 */
177 	if (ddi_driver_major(child) == ddi_name_to_major("pcie_pci") &&
178 	    ddi_get_child(child) == NULL &&
179 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
180 	    "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
181 		return (1);
182 
183 	return (0);
184 }
185 
186 void
187 npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl) {
188 	uint32_t regs;
189 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
190 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
191 
192 	if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
193 		/* Disable ECRC for all devices */
194 		regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
195 		    PCIE_AER_UCE_ECRC;
196 		pcie_set_aer_uce_mask(regs);
197 
198 		/*
199 		 * Turn full scan on since the Error Source ID register may not
200 		 * have the correct ID.
201 		 */
202 		pcie_full_scan = B_TRUE;
203 	}
204 }
205 
206 void
207 npe_intel_error_mask(ddi_acc_handle_t cfg_hdl) {
208 	uint32_t regs;
209 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
210 
211 	if (vendor_id == INTEL_VENDOR_ID) {
212 		/*
213 		 * Due to an errata in Intel's ESB2 southbridge, all ECRCs
214 		 * generation/checking need to be disabled.  There is a
215 		 * workaround by setting a proprietary bit in the ESB2, but it
216 		 * is not well documented or understood.  If that bit is set in
217 		 * the future, then ECRC generation/checking should be enabled
218 		 * again.
219 		 *
220 		 * Disable ECRC generation/checking by masking ECRC in the AER
221 		 * UE Mask.  The pcie misc module would then automatically
222 		 * disable ECRC generation/checking in the AER Control register.
223 		 */
224 		regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
225 		pcie_set_aer_uce_mask(regs);
226 	}
227 }
228 
229 /*
230  * Check's if this child is a PCI device.
231  * Child is a PCI device if:
232  * parent has a dev_type of "pci"
233  * -and-
234  * child does not have a dev_type of "pciex"
235  *
236  * If the parent is not of dev_type "pci", then assume it is "pciex" and all
237  * children should support using PCIe style MMCFG access.
238  *
239  * If parent's dev_type is "pci" and child is "pciex", then also enable using
240  * PCIe style MMCFG access.  This covers the case where NPE is "pci" and a PCIe
241  * RP is beneath.
242  */
243 boolean_t
244 npe_child_is_pci(dev_info_t *dip) {
245 	char *dev_type;
246 	boolean_t parent_is_pci, child_is_pciex;
247 
248 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip),
249 	    DDI_PROP_DONTPASS, "device_type", &dev_type) ==
250 	    DDI_PROP_SUCCESS) {
251 		parent_is_pci = (strcmp(dev_type, "pci") == 0);
252 		ddi_prop_free(dev_type);
253 	} else {
254 		parent_is_pci = B_FALSE;
255 	}
256 
257 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
258 	    "device_type", &dev_type) == DDI_PROP_SUCCESS) {
259 		child_is_pciex = (strcmp(dev_type, "pciex") == 0);
260 		ddi_prop_free(dev_type);
261 	} else {
262 		child_is_pciex = B_FALSE;
263 	}
264 
265 	return (parent_is_pci && !child_is_pciex);
266 }
267 
268 /*
269  * Checks to see if MMCFG is supported and enables it if necessary.
270  * Returns: TRUE is MMCFG is support, FLASE is not.
271  *
272  * In general if a device sits below a parent who's "dev_type" is "pciex" the
273  * support MMCFG.  Otherwise, default back to legacy IOCFG access.
274  *
275  * Enable Legacy PCI config space access for AMD K8 north bridges.
276  *	Host bridge: AMD HyperTransport Technology Configuration
277  *	Host bridge: AMD Address Map
278  *	Host bridge: AMD DRAM Controller
279  *	Host bridge: AMD Miscellaneous Control
280  * These devices do not support MMCFG access.
281  *
282  * Enable MMCFG via msr for AMD K10 north bridges
283  */
284 boolean_t
285 npe_check_and_set_mmcfg(dev_info_t *dip)
286 {
287 	int vendor_id, device_id;
288 	int64_t data;
289 
290 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
291 	    "vendor-id", -1);
292 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
293 	    "device-id", -1);
294 
295 	if (IS_K10_AMD_NTBRIDGE(vendor_id, device_id)) {
296 		data = ddi_prop_get_int64(DDI_DEV_T_ANY, dip, 0,
297 		    "ecfga-base-address", 0);
298 		data &= AMD_MMIO_CFG_BADDR_ADDR_MASK;
299 		data |= AMD_MMIO_CFG_BADDR_ENA_ON;
300 		wrmsr(MSR_AMD_NB_MMIO_CFG_BADDR, data);
301 	}
302 
303 	return !(npe_child_is_pci(dip) ||
304 	    IS_BAD_AMD_NTBRIDGE(vendor_id, device_id));
305 }
306