xref: /illumos-gate/usr/src/uts/i86pc/io/pciex/npe_misc.c (revision aedf2b3bb56b025fcaf87b49ec6c8aeea07f16d7)
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 2009 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_workaround(ddi_acc_handle_t cfg_hdl);
50 void	npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl);
51 boolean_t npe_is_child_pci(dev_info_t *dip);
52 
53 /*
54  * Default ecfga base address
55  */
56 int64_t npe_default_ecfga_base = 0xE0000000;
57 
58 extern uint32_t npe_aer_uce_mask;
59 
60 /* AMD's northbridges vendor-id and device-ids */
61 #define	AMD_NTBRDIGE_VID		0x1022	/* AMD vendor-id */
62 #define	AMD_HT_NTBRIDGE_DID		0x1100	/* HT Configuration */
63 #define	AMD_AM_NTBRIDGE_DID		0x1101	/* Address Map */
64 #define	AMD_DC_NTBRIDGE_DID		0x1102	/* DRAM Controller */
65 #define	AMD_MC_NTBRIDGE_DID		0x1103	/* Misc Controller */
66 #define	AMD_K10_NTBRIDGE_DID_0		0x1200
67 #define	AMD_K10_NTBRIDGE_DID_1		0x1201
68 #define	AMD_K10_NTBRIDGE_DID_2		0x1202
69 #define	AMD_K10_NTBRIDGE_DID_3		0x1203
70 #define	AMD_K10_NTBRIDGE_DID_4		0x1204
71 
72 /*
73  * Check if the given device is an AMD northbridge
74  */
75 #define	IS_BAD_AMD_NTBRIDGE(vid, did) \
76 	    (((vid) == AMD_NTBRDIGE_VID) && \
77 	    (((did) == AMD_HT_NTBRIDGE_DID) || \
78 	    ((did) == AMD_AM_NTBRIDGE_DID) || \
79 	    ((did) == AMD_DC_NTBRIDGE_DID) || \
80 	    ((did) == AMD_MC_NTBRIDGE_DID)))
81 
82 #define	IS_K10_AMD_NTBRIDGE(vid, did) \
83 	    (((vid) == AMD_NTBRDIGE_VID) && \
84 	    (((did) == AMD_K10_NTBRIDGE_DID_0) || \
85 	    ((did) == AMD_K10_NTBRIDGE_DID_1) || \
86 	    ((did) == AMD_K10_NTBRIDGE_DID_2) || \
87 	    ((did) == AMD_K10_NTBRIDGE_DID_3) || \
88 	    ((did) == AMD_K10_NTBRIDGE_DID_4)))
89 
90 #define	MSR_AMD_NB_MMIO_CFG_BADDR	0xc0010058
91 #define	AMD_MMIO_CFG_BADDR_ADDR_MASK	0xFFFFFFF00000ULL
92 #define	AMD_MMIO_CFG_BADDR_ENA_MASK	0x000000000001ULL
93 #define	AMD_MMIO_CFG_BADDR_ENA_ON	0x000000000001ULL
94 #define	AMD_MMIO_CFG_BADDR_ENA_OFF	0x000000000000ULL
95 
96 
97 /*
98  * Query the MCFG table using ACPI.  If MCFG is found, setup the
99  * 'ecfg' property accordingly.  Otherwise, set the values
100  * to the default values.
101  */
102 void
103 npe_query_acpi_mcfg(dev_info_t *dip)
104 {
105 	MCFG_TABLE *mcfgp;
106 	CFG_BASE_ADDR_ALLOC *cfg_baap;
107 	char *cfg_baa_endp;
108 	int64_t ecfginfo[4];
109 	int ecfg_found = 0;
110 
111 	/* Query the MCFG table using ACPI */
112 	if (AcpiGetTable(ACPI_SIG_MCFG, 1,
113 	    (ACPI_TABLE_HEADER **)&mcfgp) == AE_OK) {
114 
115 		cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
116 		cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
117 
118 		while ((char *)cfg_baap < cfg_baa_endp) {
119 			if (cfg_baap->base_addr != (uint64_t)0 &&
120 			    cfg_baap->segment == 0) {
121 				/*
122 				 * Set up the 'ecfg' property to hold
123 				 * base_addr, segment, and first/last bus.
124 				 * We only do the first entry that maps
125 				 * segment 0; nonzero segments are not yet
126 				 * known, or handled.  If they appear,
127 				 * we'll need to figure out which bus node
128 				 * should have which entry by examining the
129 				 * ACPI _SEG method on each bus node.
130 				 */
131 				ecfginfo[0] = cfg_baap->base_addr;
132 				ecfginfo[1] = cfg_baap->segment;
133 				ecfginfo[2] = cfg_baap->start_bno;
134 				ecfginfo[3] = cfg_baap->end_bno;
135 				(void) ndi_prop_update_int64_array(
136 				    DDI_DEV_T_NONE, dip, "ecfg",
137 				    ecfginfo, 4);
138 				ecfg_found = 1;
139 				break;
140 			}
141 			cfg_baap++;
142 		}
143 	}
144 	if (ecfg_found)
145 		return;
146 	/*
147 	 * If MCFG is not found or ecfga_base is not found in MCFG table,
148 	 * set the property to the default values.
149 	 */
150 	ecfginfo[0] = npe_default_ecfga_base;
151 	ecfginfo[1] = 0;		/* segment 0 */
152 	ecfginfo[2] = 0;		/* first bus 0 */
153 	ecfginfo[3] = 0xff;		/* last bus ff */
154 	(void) ndi_prop_update_int64_array(DDI_DEV_T_NONE, dip,
155 	    "ecfg", ecfginfo, 4);
156 }
157 
158 
159 /*
160  * Enable reporting of AER capability next pointer.
161  * This needs to be done only for CK8-04 devices
162  * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
163  * NOTE: BIOS is disabling this, it needs to be enabled temporarily
164  */
165 void
166 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
167 {
168 	ushort_t cya1;
169 
170 	if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
171 	    (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
172 	    NVIDIA_CK804_DEVICE_ID) &&
173 	    (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
174 	    NVIDIA_CK804_AER_VALID_REVID)) {
175 		cya1 =  pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
176 		if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
177 			(void) pci_config_put16(cfg_hdl,
178 			    NVIDIA_CK804_VEND_CYA1_OFF,
179 			    cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
180 	}
181 }
182 
183 /*
184  * If the bridge is empty, disable it
185  */
186 int
187 npe_disable_empty_bridges_workaround(dev_info_t *child)
188 {
189 	/*
190 	 * Do not bind drivers to empty bridges.
191 	 * Fail above, if the bridge is found to be hotplug capable
192 	 */
193 	if (ddi_driver_major(child) == ddi_name_to_major("pcieb") &&
194 	    ddi_get_child(child) == NULL &&
195 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
196 	    "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
197 		return (1);
198 
199 	return (0);
200 }
201 
202 void
203 npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl) {
204 	uint32_t regs;
205 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
206 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
207 
208 	if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
209 		/* Disable ECRC for all devices */
210 		regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
211 		    PCIE_AER_UCE_ECRC;
212 		pcie_set_aer_uce_mask(regs);
213 
214 		/*
215 		 * Turn full scan on since the Error Source ID register may not
216 		 * have the correct ID.
217 		 */
218 		pcie_force_fullscan();
219 	}
220 }
221 
222 void
223 npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl) {
224 	uint32_t regs;
225 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
226 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
227 
228 	if (vendor_id == INTEL_VENDOR_ID) {
229 		/*
230 		 * Due to an errata in Intel's ESB2 southbridge, all ECRCs
231 		 * generation/checking need to be disabled.  There is a
232 		 * workaround by setting a proprietary bit in the ESB2, but it
233 		 * is not well documented or understood.  If that bit is set in
234 		 * the future, then ECRC generation/checking should be enabled
235 		 * again.
236 		 *
237 		 * Disable ECRC generation/checking by masking ECRC in the AER
238 		 * UE Mask.  The pcie misc module would then automatically
239 		 * disable ECRC generation/checking in the AER Control register.
240 		 */
241 		regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
242 		pcie_set_aer_uce_mask(regs);
243 
244 		if (INTEL_NB5500_PCIE_DEV_ID(dev_id) ||
245 		    INTEL_NB5520_PCIE_DEV_ID(dev_id)) {
246 			/*
247 			 * Turn full scan on since the Error Source ID register
248 			 * may not have the correct ID. See Intel 5520 and
249 			 * Intel 5500 Chipsets errata #34 and #54 in the August
250 			 * 2009 specification update, document number
251 			 * 321329-006.
252 			 */
253 			pcie_force_fullscan();
254 		}
255 	}
256 }
257 
258 /*
259  * Check's if this child is a PCI device.
260  * Child is a PCI device if:
261  * parent has a dev_type of "pci"
262  * -and-
263  * child does not have a dev_type of "pciex"
264  *
265  * If the parent is not of dev_type "pci", then assume it is "pciex" and all
266  * children should support using PCIe style MMCFG access.
267  *
268  * If parent's dev_type is "pci" and child is "pciex", then also enable using
269  * PCIe style MMCFG access.  This covers the case where NPE is "pci" and a PCIe
270  * RP is beneath.
271  */
272 boolean_t
273 npe_child_is_pci(dev_info_t *dip) {
274 	char *dev_type;
275 	boolean_t parent_is_pci, child_is_pciex;
276 
277 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip),
278 	    DDI_PROP_DONTPASS, "device_type", &dev_type) ==
279 	    DDI_PROP_SUCCESS) {
280 		parent_is_pci = (strcmp(dev_type, "pci") == 0);
281 		ddi_prop_free(dev_type);
282 	} else {
283 		parent_is_pci = B_FALSE;
284 	}
285 
286 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
287 	    "device_type", &dev_type) == DDI_PROP_SUCCESS) {
288 		child_is_pciex = (strcmp(dev_type, "pciex") == 0);
289 		ddi_prop_free(dev_type);
290 	} else {
291 		child_is_pciex = B_FALSE;
292 	}
293 
294 	return (parent_is_pci && !child_is_pciex);
295 }
296 
297 /*
298  * Checks to see if MMCFG is supported.
299  * Returns: TRUE if MMCFG is supported, FALSE if not.
300  *
301  * If a device is attached to a parent whose "dev_type" is "pciex",
302  * the device will support MMCFG access.  Otherwise, use legacy IOCFG access.
303  *
304  * Enable Legacy PCI config space access for AMD K8 north bridges.
305  *	Host bridge: AMD HyperTransport Technology Configuration
306  *	Host bridge: AMD Address Map
307  *	Host bridge: AMD DRAM Controller
308  *	Host bridge: AMD Miscellaneous Control
309  * These devices do not support MMCFG access.
310  */
311 boolean_t
312 npe_is_mmcfg_supported(dev_info_t *dip)
313 {
314 	int vendor_id, device_id;
315 
316 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
317 	    "vendor-id", -1);
318 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
319 	    "device-id", -1);
320 
321 	return !(npe_child_is_pci(dip) ||
322 	    IS_BAD_AMD_NTBRIDGE(vendor_id, device_id));
323 }
324 
325 int
326 npe_enable_htmsi(ddi_acc_handle_t cfg_hdl)
327 {
328 	uint16_t ptr;
329 	uint16_t reg;
330 
331 	if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK,
332 	    PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS)
333 		return (DDI_FAILURE);
334 
335 	reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF);
336 	reg |= PCI_HTCAP_MSIMAP_ENABLE;
337 
338 	pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg);
339 	return (DDI_SUCCESS);
340 }
341 
342 void
343 npe_enable_htmsi_children(dev_info_t *dip)
344 {
345 	dev_info_t *cdip = ddi_get_child(dip);
346 	ddi_acc_handle_t cfg_hdl;
347 
348 	for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
349 		if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) {
350 			cmn_err(CE_NOTE, "!npe_enable_htmsi_children: "
351 			    "pci_config_setup failed for %s",
352 			    ddi_node_name(cdip));
353 		}
354 
355 		(void) npe_enable_htmsi(cfg_hdl);
356 		pci_config_teardown(&cfg_hdl);
357 	}
358 }
359 
360 /*
361  * save config regs for HyperTransport devices without drivers of classes:
362  * memory controller and hostbridge
363  */
364 int
365 npe_save_htconfig_children(dev_info_t *dip)
366 {
367 	dev_info_t *cdip = ddi_get_child(dip);
368 	ddi_acc_handle_t cfg_hdl;
369 	uint16_t ptr;
370 	int rval = DDI_SUCCESS;
371 	uint8_t cl, scl;
372 
373 	for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
374 		if (ddi_driver_major(cdip) != DDI_MAJOR_T_NONE)
375 			continue;
376 
377 		if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS)
378 			return (DDI_FAILURE);
379 
380 		cl = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
381 		scl = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
382 
383 		if (((cl == PCI_CLASS_MEM && scl == PCI_MEM_RAM) ||
384 		    (cl == PCI_CLASS_BRIDGE && scl == PCI_BRIDGE_HOST)) &&
385 		    pci_htcap_locate(cfg_hdl, 0, 0, &ptr) == DDI_SUCCESS) {
386 
387 			if (pci_save_config_regs(cdip) != DDI_SUCCESS) {
388 				cmn_err(CE_WARN, "Failed to save HT config "
389 				    "regs for %s\n", ddi_node_name(cdip));
390 				rval = DDI_FAILURE;
391 
392 			} else if (ddi_prop_update_int(DDI_DEV_T_NONE, cdip,
393 			    "htconfig-saved", 1) != DDI_SUCCESS) {
394 				cmn_err(CE_WARN, "Failed to set htconfig-saved "
395 				    "property for %s\n", ddi_node_name(cdip));
396 				rval = DDI_FAILURE;
397 			}
398 		}
399 
400 		pci_config_teardown(&cfg_hdl);
401 	}
402 
403 	return (rval);
404 }
405 
406 int
407 npe_restore_htconfig_children(dev_info_t *dip)
408 {
409 	dev_info_t *cdip = ddi_get_child(dip);
410 	int rval = DDI_SUCCESS;
411 
412 	for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
413 		if (ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
414 		    "htconfig-saved", 0) == 0)
415 			continue;
416 
417 		if (pci_restore_config_regs(cdip) != DDI_SUCCESS) {
418 			cmn_err(CE_WARN, "Failed to restore HT config "
419 			    "regs for %s\n", ddi_node_name(cdip));
420 			rval = DDI_FAILURE;
421 		}
422 	}
423 
424 	return (rval);
425 }
426