xref: /illumos-gate/usr/src/uts/i86pc/io/pciex/npe_misc.c (revision 19397407)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *	Library file that has miscellaneous support for npe(7d)
31  */
32 
33 #include <sys/conf.h>
34 #include <sys/pci.h>
35 #include <sys/sunndi.h>
36 #include <sys/acpi/acpi.h>
37 #include <sys/acpi/acpi_pci.h>
38 #include <sys/acpica.h>
39 #include <sys/pci_cap.h>
40 #include <sys/pcie_impl.h>
41 #include <io/pciex/pcie_nvidia.h>
42 #include <io/pciex/pcie_nb5000.h>
43 
44 /*
45  * Prototype declaration
46  */
47 void	npe_query_acpi_mcfg(dev_info_t *dip);
48 void	npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
49 int	npe_disable_empty_bridges_workaround(dev_info_t *child);
50 void	npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl);
51 void	npe_intel_error_mask(ddi_acc_handle_t cfg_hdl);
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 extern boolean_t pcie_full_scan;
60 
61 /*
62  * Query the MCFG table using ACPI.  If MCFG is found, setup the
63  * 'ecfga-base-address' (Enhanced Configuration Access base address)
64  * property accordingly.  Otherwise, set the value of the property
65  * to the default value.
66  */
67 void
68 npe_query_acpi_mcfg(dev_info_t *dip)
69 {
70 	MCFG_TABLE *mcfgp;
71 	CFG_BASE_ADDR_ALLOC *cfg_baap;
72 	char *cfg_baa_endp;
73 	uint64_t ecfga_base;
74 
75 	/* Query the MCFG table using ACPI */
76 	if (AcpiGetFirmwareTable(MCFG_SIG, 1, ACPI_LOGICAL_ADDRESSING,
77 	    (ACPI_TABLE_HEADER **)&mcfgp) == AE_OK) {
78 
79 		cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
80 		cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
81 
82 		while ((char *)cfg_baap < cfg_baa_endp) {
83 			ecfga_base = ACPI_GET_ADDRESS(cfg_baap->base_addr);
84 			if (ecfga_base != (uint64_t)0) {
85 				/*
86 				 * Setup the 'ecfga-base-address' property to
87 				 * the base_addr found in the MCFG and return.
88 				 */
89 				(void) ndi_prop_update_int64(DDI_DEV_T_NONE,
90 				    dip, "ecfga-base-address", ecfga_base);
91 				return;
92 			}
93 			cfg_baap++;
94 		}
95 	}
96 	/*
97 	 * If MCFG is not found or ecfga_base is not found in MCFG table,
98 	 * set the 'ecfga-base-address' property to the default value.
99 	 */
100 	(void) ndi_prop_update_int64(DDI_DEV_T_NONE, dip,
101 	    "ecfga-base-address", npe_default_ecfga_base);
102 }
103 
104 
105 /*
106  * Enable reporting of AER capability next pointer.
107  * This needs to be done only for CK8-04 devices
108  * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
109  * NOTE: BIOS is disabling this, it needs to be enabled temporarily
110  */
111 void
112 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
113 {
114 	ushort_t cya1;
115 
116 	if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
117 	    (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
118 	    NVIDIA_CK804_DEVICE_ID) &&
119 	    (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
120 	    NVIDIA_CK804_AER_VALID_REVID)) {
121 		cya1 =  pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
122 		if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
123 			(void) pci_config_put16(cfg_hdl,
124 			    NVIDIA_CK804_VEND_CYA1_OFF,
125 			    cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
126 	}
127 }
128 
129 /*
130  * If the bridge is empty, disable it
131  */
132 int
133 npe_disable_empty_bridges_workaround(dev_info_t *child)
134 {
135 	/*
136 	 * Do not bind drivers to empty bridges.
137 	 * Fail above, if the bridge is found to be hotplug capable
138 	 */
139 	if (ddi_driver_major(child) == ddi_name_to_major("pcie_pci") &&
140 	    ddi_get_child(child) == NULL &&
141 	    ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
142 	    "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
143 		return (1);
144 
145 	return (0);
146 }
147 
148 void
149 npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl) {
150 	uint32_t regs;
151 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
152 	uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
153 
154 	if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
155 		/* Disable ECRC for all devices */
156 		regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
157 		    PCIE_AER_UCE_ECRC;
158 		pcie_set_aer_uce_mask(regs);
159 
160 		/*
161 		 * Turn full scan on since the Error Source ID register may not
162 		 * have the correct ID.
163 		 */
164 		pcie_full_scan = B_TRUE;
165 	}
166 }
167 
168 void
169 npe_intel_error_mask(ddi_acc_handle_t cfg_hdl) {
170 	uint32_t regs;
171 	uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
172 
173 	if (vendor_id == INTEL_VENDOR_ID) {
174 		/*
175 		 * Due to an errata in Intel's ESB2 southbridge, all ECRCs
176 		 * generation/checking need to be disabled.  There is a
177 		 * workaround by setting a proprietary bit in the ESB2, but it
178 		 * is not well documented or understood.  If that bit is set in
179 		 * the future, then ECRC generation/checking should be enabled
180 		 * again.
181 		 *
182 		 * Disable ECRC generation/checking by masking ECRC in the AER
183 		 * UE Mask.  The pcie misc module would then automatically
184 		 * disable ECRC generation/checking in the AER Control register.
185 		 */
186 		regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
187 		pcie_set_aer_uce_mask(regs);
188 	}
189 }
190