Print this page
acpica-unix2-20130823
PANKOVs restructure
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/pciex/npe_misc.c
+++ new/usr/src/uts/i86pc/io/pciex/npe_misc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2013 PALO, Richard. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Library file that has miscellaneous support for npe(7d)
28 29 */
29 30
30 31 #include <sys/conf.h>
31 32 #include <sys/pci.h>
32 33 #include <sys/sunndi.h>
33 -#include <sys/acpi/acpi.h>
34 -#include <sys/acpi/acpi_pci.h>
34 +#include <acpica/include/acpi.h>
35 35 #include <sys/acpica.h>
36 36 #include <sys/pci_cap.h>
37 37 #include <sys/pcie_impl.h>
38 38 #include <sys/x86_archext.h>
39 39 #include <io/pciex/pcie_nvidia.h>
40 40 #include <io/pciex/pcie_nb5000.h>
41 41 #include <sys/pci_cfgacc_x86.h>
42 42 #include <sys/cpuvar.h>
43 43
44 44 /*
45 45 * Prototype declaration
46 46 */
47 47 void npe_query_acpi_mcfg(dev_info_t *dip);
48 48 void npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl);
49 49 int npe_disable_empty_bridges_workaround(dev_info_t *child);
50 50 void npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl);
51 51 void npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl);
52 52 boolean_t npe_is_child_pci(dev_info_t *dip);
53 53 int npe_enable_htmsi(ddi_acc_handle_t cfg_hdl);
54 54 void npe_enable_htmsi_children(dev_info_t *dip);
55 55
56 56 int npe_enable_htmsi_flag = 1;
57 57
58 58 /*
59 59 * Default ecfga base address
60 60 */
61 61 int64_t npe_default_ecfga_base = 0xE0000000;
62 62
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
63 63 extern uint32_t npe_aer_uce_mask;
64 64
65 65 /*
66 66 * Query the MCFG table using ACPI. If MCFG is found, setup the
67 67 * 'ecfg' property accordingly. Otherwise, set the values
68 68 * to the default values.
69 69 */
70 70 void
71 71 npe_query_acpi_mcfg(dev_info_t *dip)
72 72 {
73 - MCFG_TABLE *mcfgp;
74 - CFG_BASE_ADDR_ALLOC *cfg_baap;
73 + ACPI_TABLE_HEADER *mcfgp;
74 + ACPI_MCFG_ALLOCATION *cfg_baap;
75 75 char *cfg_baa_endp;
76 76 int64_t ecfginfo[4];
77 77 int ecfg_found = 0;
78 78
79 79 /* Query the MCFG table using ACPI */
80 - if (AcpiGetTable(ACPI_SIG_MCFG, 1,
81 - (ACPI_TABLE_HEADER **)&mcfgp) == AE_OK) {
80 + if (AcpiGetTable(ACPI_SIG_MCFG, 1, &mcfgp) == AE_OK) {
82 81
83 - cfg_baap = (CFG_BASE_ADDR_ALLOC *)mcfgp->CfgBaseAddrAllocList;
84 - cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
82 + cfg_baap = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)mcfgp + 1);
83 + cfg_baa_endp = ((char *)mcfgp) + mcfgp->Length;
85 84
86 85 while ((char *)cfg_baap < cfg_baa_endp) {
87 - if (cfg_baap->base_addr != (uint64_t)0 &&
88 - cfg_baap->segment == 0) {
86 + if (cfg_baap->Address != (uint64_t)0 &&
87 + cfg_baap->PciSegment == 0) {
89 88 /*
90 89 * Set up the 'ecfg' property to hold
91 90 * base_addr, segment, and first/last bus.
92 91 * We only do the first entry that maps
93 92 * segment 0; nonzero segments are not yet
94 93 * known, or handled. If they appear,
95 94 * we'll need to figure out which bus node
96 95 * should have which entry by examining the
97 96 * ACPI _SEG method on each bus node.
98 97 */
99 - ecfginfo[0] = cfg_baap->base_addr;
100 - ecfginfo[1] = cfg_baap->segment;
101 - ecfginfo[2] = cfg_baap->start_bno;
102 - ecfginfo[3] = cfg_baap->end_bno;
98 + ecfginfo[0] = cfg_baap->Address;
99 + ecfginfo[1] = cfg_baap->PciSegment;
100 + ecfginfo[2] = cfg_baap->StartBusNumber;
101 + ecfginfo[3] = cfg_baap->EndBusNumber;
103 102 (void) ndi_prop_update_int64_array(
104 103 DDI_DEV_T_NONE, dip, "ecfg",
105 104 ecfginfo, 4);
106 105 ecfg_found = 1;
107 106 break;
108 107 }
109 108 cfg_baap++;
110 109 }
111 110 }
112 111 if (ecfg_found)
113 112 return;
114 113 /*
115 114 * If MCFG is not found or ecfga_base is not found in MCFG table,
116 115 * set the property to the default values.
117 116 */
118 117 ecfginfo[0] = npe_default_ecfga_base;
119 118 ecfginfo[1] = 0; /* segment 0 */
120 119 ecfginfo[2] = 0; /* first bus 0 */
121 120 ecfginfo[3] = 0xff; /* last bus ff */
122 121 (void) ndi_prop_update_int64_array(DDI_DEV_T_NONE, dip,
123 122 "ecfg", ecfginfo, 4);
124 123 }
125 124
126 125
127 126 /*
128 127 * Enable reporting of AER capability next pointer.
129 128 * This needs to be done only for CK8-04 devices
130 129 * by setting NV_XVR_VEND_CYA1 (offset 0xf40) bit 13
131 130 * NOTE: BIOS is disabling this, it needs to be enabled temporarily
132 131 */
133 132 void
134 133 npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl)
135 134 {
136 135 ushort_t cya1;
137 136
138 137 if ((pci_config_get16(cfg_hdl, PCI_CONF_VENID) == NVIDIA_VENDOR_ID) &&
139 138 (pci_config_get16(cfg_hdl, PCI_CONF_DEVID) ==
140 139 NVIDIA_CK804_DEVICE_ID) &&
141 140 (pci_config_get8(cfg_hdl, PCI_CONF_REVID) >=
142 141 NVIDIA_CK804_AER_VALID_REVID)) {
143 142 cya1 = pci_config_get16(cfg_hdl, NVIDIA_CK804_VEND_CYA1_OFF);
144 143 if (!(cya1 & ~NVIDIA_CK804_VEND_CYA1_ERPT_MASK))
145 144 (void) pci_config_put16(cfg_hdl,
146 145 NVIDIA_CK804_VEND_CYA1_OFF,
147 146 cya1 | NVIDIA_CK804_VEND_CYA1_ERPT_VAL);
148 147 }
149 148 }
150 149
151 150 /*
152 151 * If the bridge is empty, disable it
153 152 */
154 153 int
155 154 npe_disable_empty_bridges_workaround(dev_info_t *child)
156 155 {
157 156 /*
158 157 * Do not bind drivers to empty bridges.
159 158 * Fail above, if the bridge is found to be hotplug capable
160 159 */
161 160 if (ddi_driver_major(child) == ddi_name_to_major("pcieb") &&
162 161 ddi_get_child(child) == NULL &&
163 162 ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
164 163 "pci-hotplug-type", INBAND_HPC_NONE) == INBAND_HPC_NONE)
165 164 return (1);
166 165
167 166 return (0);
168 167 }
169 168
170 169 void
171 170 npe_nvidia_error_workaround(ddi_acc_handle_t cfg_hdl) {
172 171 uint32_t regs;
173 172 uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
174 173 uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
175 174
176 175 if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) {
177 176 /* Disable ECRC for all devices */
178 177 regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask |
179 178 PCIE_AER_UCE_ECRC;
180 179 pcie_set_aer_uce_mask(regs);
181 180
182 181 /*
183 182 * Turn full scan on since the Error Source ID register may not
184 183 * have the correct ID.
185 184 */
186 185 pcie_force_fullscan();
187 186 }
188 187 }
189 188
190 189 void
191 190 npe_intel_error_workaround(ddi_acc_handle_t cfg_hdl) {
192 191 uint32_t regs;
193 192 uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID);
194 193 uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID);
195 194
196 195 if (vendor_id == INTEL_VENDOR_ID) {
197 196 /*
198 197 * Due to an errata in Intel's ESB2 southbridge, all ECRCs
199 198 * generation/checking need to be disabled. There is a
200 199 * workaround by setting a proprietary bit in the ESB2, but it
201 200 * is not well documented or understood. If that bit is set in
202 201 * the future, then ECRC generation/checking should be enabled
203 202 * again.
204 203 *
205 204 * Disable ECRC generation/checking by masking ECRC in the AER
206 205 * UE Mask. The pcie misc module would then automatically
207 206 * disable ECRC generation/checking in the AER Control register.
208 207 */
209 208 regs = pcie_get_aer_uce_mask() | PCIE_AER_UCE_ECRC;
210 209 pcie_set_aer_uce_mask(regs);
211 210
212 211 if (INTEL_NB5500_PCIE_DEV_ID(dev_id) ||
213 212 INTEL_NB5520_PCIE_DEV_ID(dev_id)) {
214 213 /*
215 214 * Turn full scan on since the Error Source ID register
216 215 * may not have the correct ID. See Intel 5520 and
217 216 * Intel 5500 Chipsets errata #34 and #54 in the August
218 217 * 2009 specification update, document number
219 218 * 321329-006.
220 219 */
221 220 pcie_force_fullscan();
222 221 }
223 222 }
224 223 }
225 224
226 225 /*
227 226 * Check's if this child is a PCI device.
228 227 * Child is a PCI device if:
229 228 * parent has a dev_type of "pci"
230 229 * -and-
231 230 * child does not have a dev_type of "pciex"
232 231 *
233 232 * If the parent is not of dev_type "pci", then assume it is "pciex" and all
234 233 * children should support using PCIe style MMCFG access.
235 234 *
236 235 * If parent's dev_type is "pci" and child is "pciex", then also enable using
237 236 * PCIe style MMCFG access. This covers the case where NPE is "pci" and a PCIe
238 237 * RP is beneath.
239 238 */
240 239 boolean_t
241 240 npe_child_is_pci(dev_info_t *dip) {
242 241 char *dev_type;
243 242 boolean_t parent_is_pci, child_is_pciex;
244 243
245 244 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip),
246 245 DDI_PROP_DONTPASS, "device_type", &dev_type) ==
247 246 DDI_PROP_SUCCESS) {
248 247 parent_is_pci = (strcmp(dev_type, "pci") == 0);
249 248 ddi_prop_free(dev_type);
250 249 } else {
251 250 parent_is_pci = B_FALSE;
252 251 }
253 252
254 253 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
255 254 "device_type", &dev_type) == DDI_PROP_SUCCESS) {
256 255 child_is_pciex = (strcmp(dev_type, "pciex") == 0);
257 256 ddi_prop_free(dev_type);
258 257 } else {
259 258 child_is_pciex = B_FALSE;
260 259 }
261 260
262 261 return (parent_is_pci && !child_is_pciex);
263 262 }
264 263
265 264 /*
266 265 * Checks to see if MMCFG is supported.
267 266 * Returns: TRUE if MMCFG is supported, FALSE if not.
268 267 *
269 268 * If a device is attached to a parent whose "dev_type" is "pciex",
270 269 * the device will support MMCFG access. Otherwise, use legacy IOCFG access.
271 270 *
272 271 * Enable Legacy PCI config space access for AMD K8 north bridges.
273 272 * Host bridge: AMD HyperTransport Technology Configuration
274 273 * Host bridge: AMD Address Map
275 274 * Host bridge: AMD DRAM Controller
276 275 * Host bridge: AMD Miscellaneous Control
277 276 * These devices do not support MMCFG access.
278 277 */
279 278 boolean_t
280 279 npe_is_mmcfg_supported(dev_info_t *dip)
281 280 {
282 281 int vendor_id, device_id;
283 282
284 283 vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
285 284 "vendor-id", -1);
286 285 device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
287 286 "device-id", -1);
288 287
289 288 return !(npe_child_is_pci(dip) ||
290 289 IS_BAD_AMD_NTBRIDGE(vendor_id, device_id));
291 290 }
292 291
293 292 int
294 293 npe_enable_htmsi(ddi_acc_handle_t cfg_hdl)
295 294 {
296 295 uint16_t ptr;
297 296 uint16_t reg;
298 297
299 298 if (pci_htcap_locate(cfg_hdl, PCI_HTCAP_TYPE_MASK,
300 299 PCI_HTCAP_MSIMAP_TYPE, &ptr) != DDI_SUCCESS)
301 300 return (DDI_FAILURE);
302 301
303 302 reg = pci_config_get16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF);
304 303 reg |= PCI_HTCAP_MSIMAP_ENABLE;
305 304
306 305 pci_config_put16(cfg_hdl, ptr + PCI_CAP_ID_REGS_OFF, reg);
307 306 return (DDI_SUCCESS);
308 307 }
309 308
310 309 void
311 310 npe_enable_htmsi_children(dev_info_t *dip)
312 311 {
313 312 dev_info_t *cdip = ddi_get_child(dip);
314 313 ddi_acc_handle_t cfg_hdl;
315 314
316 315 if (!npe_enable_htmsi_flag)
317 316 return;
318 317
319 318 /*
320 319 * Hypertransport MSI remapping only applies to AMD CPUs using
321 320 * Hypertransport (K8 and above) and not other platforms with non-AMD
322 321 * CPUs that may be using Hypertransport internally in the chipset(s)
323 322 */
324 323 if (!(cpuid_getvendor(CPU) == X86_VENDOR_AMD &&
325 324 cpuid_getfamily(CPU) >= 0xf))
326 325 return;
327 326
328 327 for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
329 328 if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS) {
330 329 cmn_err(CE_NOTE, "!npe_enable_htmsi_children: "
331 330 "pci_config_setup failed for %s",
332 331 ddi_node_name(cdip));
333 332 return;
334 333 }
335 334
336 335 (void) npe_enable_htmsi(cfg_hdl);
337 336 pci_config_teardown(&cfg_hdl);
338 337 }
339 338 }
340 339
341 340 /*
342 341 * save config regs for HyperTransport devices without drivers of classes:
343 342 * memory controller and hostbridge
344 343 */
345 344 int
346 345 npe_save_htconfig_children(dev_info_t *dip)
347 346 {
348 347 dev_info_t *cdip = ddi_get_child(dip);
349 348 ddi_acc_handle_t cfg_hdl;
350 349 uint16_t ptr;
351 350 int rval = DDI_SUCCESS;
352 351 uint8_t cl, scl;
353 352
354 353 for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
355 354 if (ddi_driver_major(cdip) != DDI_MAJOR_T_NONE)
356 355 continue;
357 356
358 357 if (pci_config_setup(cdip, &cfg_hdl) != DDI_SUCCESS)
359 358 return (DDI_FAILURE);
360 359
361 360 cl = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
362 361 scl = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
363 362
364 363 if (((cl == PCI_CLASS_MEM && scl == PCI_MEM_RAM) ||
365 364 (cl == PCI_CLASS_BRIDGE && scl == PCI_BRIDGE_HOST)) &&
366 365 pci_htcap_locate(cfg_hdl, 0, 0, &ptr) == DDI_SUCCESS) {
367 366
368 367 if (pci_save_config_regs(cdip) != DDI_SUCCESS) {
369 368 cmn_err(CE_WARN, "Failed to save HT config "
370 369 "regs for %s\n", ddi_node_name(cdip));
371 370 rval = DDI_FAILURE;
372 371
373 372 } else if (ddi_prop_update_int(DDI_DEV_T_NONE, cdip,
374 373 "htconfig-saved", 1) != DDI_SUCCESS) {
375 374 cmn_err(CE_WARN, "Failed to set htconfig-saved "
376 375 "property for %s\n", ddi_node_name(cdip));
377 376 rval = DDI_FAILURE;
378 377 }
379 378 }
380 379
381 380 pci_config_teardown(&cfg_hdl);
382 381 }
383 382
384 383 return (rval);
385 384 }
386 385
387 386 int
388 387 npe_restore_htconfig_children(dev_info_t *dip)
389 388 {
390 389 dev_info_t *cdip = ddi_get_child(dip);
391 390 int rval = DDI_SUCCESS;
392 391
393 392 for (; cdip != NULL; cdip = ddi_get_next_sibling(cdip)) {
394 393 if (ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
395 394 "htconfig-saved", 0) == 0)
396 395 continue;
397 396
398 397 if (pci_restore_config_regs(cdip) != DDI_SUCCESS) {
399 398 cmn_err(CE_WARN, "Failed to restore HT config "
400 399 "regs for %s\n", ddi_node_name(cdip));
401 400 rval = DDI_FAILURE;
402 401 }
403 402 }
404 403
405 404 return (rval);
406 405 }
↓ open down ↓ |
294 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX