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 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/types.h>
26 #include <sys/sunndi.h>
27 #include <sys/sysmacros.h>
28 #include <sys/pci.h>
29 #include <sys/pcie.h>
30 #include <sys/pci_impl.h>
31 #include <sys/epm.h>
32
33 int pci_enable_wakeup = 1;
34
35 int
pci_config_setup(dev_info_t * dip,ddi_acc_handle_t * handle)36 pci_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
37 {
38 caddr_t cfgaddr;
39 ddi_device_acc_attr_t attr;
40
41 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
42 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
43 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
44
45 /* Check for fault management capabilities */
46 if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(dip))) {
47 attr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
48 attr.devacc_attr_access = DDI_FLAGERR_ACC;
49 }
50
51 return (ddi_regs_map_setup(dip, 0, &cfgaddr, 0, 0, &attr, handle));
52 }
53
54 void
pci_config_teardown(ddi_acc_handle_t * handle)55 pci_config_teardown(ddi_acc_handle_t *handle)
56 {
57 ddi_regs_map_free(handle);
58 }
59
60 uint8_t
pci_config_get8(ddi_acc_handle_t handle,off_t offset)61 pci_config_get8(ddi_acc_handle_t handle, off_t offset)
62 {
63 caddr_t cfgaddr;
64 ddi_acc_hdl_t *hp;
65
66 hp = impl_acc_hdl_get(handle);
67 cfgaddr = hp->ah_addr + offset;
68 return (ddi_get8(handle, (uint8_t *)cfgaddr));
69 }
70
71 uint16_t
pci_config_get16(ddi_acc_handle_t handle,off_t offset)72 pci_config_get16(ddi_acc_handle_t handle, off_t offset)
73 {
74 caddr_t cfgaddr;
75 ddi_acc_hdl_t *hp;
76
77 hp = impl_acc_hdl_get(handle);
78 cfgaddr = hp->ah_addr + offset;
79 return (ddi_get16(handle, (uint16_t *)cfgaddr));
80 }
81
82 uint32_t
pci_config_get32(ddi_acc_handle_t handle,off_t offset)83 pci_config_get32(ddi_acc_handle_t handle, off_t offset)
84 {
85 caddr_t cfgaddr;
86 ddi_acc_hdl_t *hp;
87
88 hp = impl_acc_hdl_get(handle);
89 cfgaddr = hp->ah_addr + offset;
90 return (ddi_get32(handle, (uint32_t *)cfgaddr));
91 }
92
93 uint64_t
pci_config_get64(ddi_acc_handle_t handle,off_t offset)94 pci_config_get64(ddi_acc_handle_t handle, off_t offset)
95 {
96 caddr_t cfgaddr;
97 ddi_acc_hdl_t *hp;
98
99 hp = impl_acc_hdl_get(handle);
100 cfgaddr = hp->ah_addr + offset;
101 return (ddi_get64(handle, (uint64_t *)cfgaddr));
102 }
103
104 void
pci_config_put8(ddi_acc_handle_t handle,off_t offset,uint8_t value)105 pci_config_put8(ddi_acc_handle_t handle, off_t offset, uint8_t value)
106 {
107 caddr_t cfgaddr;
108 ddi_acc_hdl_t *hp;
109
110 hp = impl_acc_hdl_get(handle);
111 cfgaddr = hp->ah_addr + offset;
112 ddi_put8(handle, (uint8_t *)cfgaddr, value);
113 }
114
115 void
pci_config_put16(ddi_acc_handle_t handle,off_t offset,uint16_t value)116 pci_config_put16(ddi_acc_handle_t handle, off_t offset, uint16_t value)
117 {
118 caddr_t cfgaddr;
119 ddi_acc_hdl_t *hp;
120
121 hp = impl_acc_hdl_get(handle);
122 cfgaddr = hp->ah_addr + offset;
123 ddi_put16(handle, (uint16_t *)cfgaddr, value);
124 }
125
126 void
pci_config_put32(ddi_acc_handle_t handle,off_t offset,uint32_t value)127 pci_config_put32(ddi_acc_handle_t handle, off_t offset, uint32_t value)
128 {
129 caddr_t cfgaddr;
130 ddi_acc_hdl_t *hp;
131
132 hp = impl_acc_hdl_get(handle);
133 cfgaddr = hp->ah_addr + offset;
134 ddi_put32(handle, (uint32_t *)cfgaddr, value);
135 }
136
137 void
pci_config_put64(ddi_acc_handle_t handle,off_t offset,uint64_t value)138 pci_config_put64(ddi_acc_handle_t handle, off_t offset, uint64_t value)
139 {
140 caddr_t cfgaddr;
141 ddi_acc_hdl_t *hp;
142
143 hp = impl_acc_hdl_get(handle);
144 cfgaddr = hp->ah_addr + offset;
145 ddi_put64(handle, (uint64_t *)cfgaddr, value);
146 }
147
148 /*ARGSUSED*/
149 int
pci_report_pmcap(dev_info_t * dip,int cap,void * arg)150 pci_report_pmcap(dev_info_t *dip, int cap, void *arg)
151 {
152 return (DDI_SUCCESS);
153 }
154
155 /*
156 * Note about saving and restoring config space.
157 * PCI devices have only upto 256 bytes of config space while PCI Express
158 * devices can have upto 4k config space. In case of PCI Express device,
159 * we save all 4k config space and restore it even if it doesn't make use
160 * of all 4k. But some devices don't respond to reads to non-existent
161 * registers within the config space. To avoid any panics, we use ddi_peek
162 * to do the reads. A bit mask is used to indicate which words of the
163 * config space are accessible. While restoring the config space, only those
164 * readable words are restored. We do all this in 32 bit size words.
165 */
166 #define INDEX_SHIFT 3
167 #define BITMASK 0x7
168
169 static uint32_t pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
170 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp);
171 static void pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
172 pci_cap_save_desc_t *cap_descp, uint32_t elements);
173 static uint32_t pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
174 uint32_t *regbuf, uint32_t nwords);
175 static uint32_t pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
176 uint32_t *regbuf, uint32_t notused);
177 static uint32_t pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
178 uint32_t *regbuf, uint32_t notused);
179 static uint32_t pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
180 uint32_t *regbuf, uint32_t notused);
181 static uint32_t pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
182 uint32_t *regbuf, uint32_t notused);
183 static uint32_t pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
184 uint32_t *regbuf, uint32_t notused);
185 static void pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
186 uint32_t *regbuf, uint32_t nwords);
187 static uint32_t cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf,
188 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace);
189 static void pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf,
190 uint16_t pmcap_offset);
191
192 /*
193 * Table below specifies the number of registers to be saved for each PCI
194 * capability. pci_generic_save saves the number of words specified in the
195 * table. Any special considerations will be taken care by the capability
196 * specific save function e.g. use pci_msi_save to save registers associated
197 * with MSI capability. PCI_UNKNOWN_SIZE indicates that number of registers
198 * to be saved is variable and will be determined by the specific save function.
199 * Currently we save/restore all the registers associated with the capability
200 * including read only registers. Regsiters are saved and restored in 32 bit
201 * size words.
202 */
203 static pci_cap_entry_t pci_cap_table[] = {
204 {PCI_CAP_ID_PM, 0, 0, PCI_PMCAP_NDWORDS, pci_generic_save},
205 {PCI_CAP_ID_AGP, 0, 0, PCI_AGP_NDWORDS, pci_generic_save},
206 {PCI_CAP_ID_SLOT_ID, 0, 0, PCI_SLOTID_NDWORDS, pci_generic_save},
207 {PCI_CAP_ID_MSI_X, 0, 0, PCI_MSIX_NDWORDS, pci_generic_save},
208 {PCI_CAP_ID_MSI, 0, 0, PCI_CAP_SZUNKNOWN, pci_msi_save},
209 {PCI_CAP_ID_PCIX, 0, 0, PCI_CAP_SZUNKNOWN, pci_pcix_save},
210 {PCI_CAP_ID_PCI_E, 0, 0, PCI_CAP_SZUNKNOWN, pci_pcie_save},
211
212 {PCI_CAP_ID_HT, PCI_HTCAP_SLPRI_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK,
213 PCI_HTCAP_SLPRI_NDWORDS, pci_generic_save},
214
215 {PCI_CAP_ID_HT, PCI_HTCAP_HOSTSEC_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK,
216 PCI_HTCAP_HOSTSEC_NDWORDS, pci_generic_save},
217
218 {PCI_CAP_ID_HT, PCI_HTCAP_INTCONF_TYPE, PCI_HTCAP_TYPE_MASK,
219 PCI_HTCAP_INTCONF_NDWORDS, pci_generic_save},
220
221 {PCI_CAP_ID_HT, PCI_HTCAP_REVID_TYPE, PCI_HTCAP_TYPE_MASK,
222 PCI_HTCAP_REVID_NDWORDS, pci_generic_save},
223
224 {PCI_CAP_ID_HT, PCI_HTCAP_UNITID_CLUMP_TYPE, PCI_HTCAP_TYPE_MASK,
225 PCI_HTCAP_UNITID_CLUMP_NDWORDS, pci_generic_save},
226
227 {PCI_CAP_ID_HT, PCI_HTCAP_ECFG_TYPE, PCI_HTCAP_TYPE_MASK,
228 PCI_HTCAP_ECFG_NDWORDS, pci_generic_save},
229
230 {PCI_CAP_ID_HT, PCI_HTCAP_ADDRMAP_TYPE, PCI_HTCAP_TYPE_MASK,
231 PCI_CAP_SZUNKNOWN, pci_ht_addrmap_save},
232
233 {PCI_CAP_ID_HT, PCI_HTCAP_MSIMAP_TYPE, PCI_HTCAP_TYPE_MASK,
234 PCI_HTCAP_MSIMAP_NDWORDS, pci_generic_save},
235
236 {PCI_CAP_ID_HT, PCI_HTCAP_DIRROUTE_TYPE, PCI_HTCAP_TYPE_MASK,
237 PCI_HTCAP_DIRROUTE_NDWORDS, pci_generic_save},
238
239 {PCI_CAP_ID_HT, PCI_HTCAP_VCSET_TYPE, PCI_HTCAP_TYPE_MASK,
240 PCI_HTCAP_VCSET_NDWORDS, pci_generic_save},
241
242 {PCI_CAP_ID_HT, PCI_HTCAP_RETRYMODE_TYPE, PCI_HTCAP_TYPE_MASK,
243 PCI_HTCAP_RETRYMODE_NDWORDS, pci_generic_save},
244
245 {PCI_CAP_ID_HT, PCI_HTCAP_GEN3_TYPE, PCI_HTCAP_TYPE_MASK,
246 PCI_HTCAP_GEN3_NDWORDS, pci_generic_save},
247
248 {PCI_CAP_ID_HT, PCI_HTCAP_FUNCEXT_TYPE, PCI_HTCAP_TYPE_MASK,
249 PCI_CAP_SZUNKNOWN, pci_ht_funcext_save},
250
251 {PCI_CAP_ID_HT, PCI_HTCAP_PM_TYPE, PCI_HTCAP_TYPE_MASK,
252 PCI_HTCAP_PM_NDWORDS, pci_generic_save},
253
254 /*
255 * {PCI_CAP_ID_cPCI_CRC, 0, NULL},
256 * {PCI_CAP_ID_VPD, 0, NULL},
257 * {PCI_CAP_ID_cPCI_HS, 0, NULL},
258 * {PCI_CAP_ID_PCI_HOTPLUG, 0, NULL},
259 * {PCI_CAP_ID_AGP_8X, 0, NULL},
260 * {PCI_CAP_ID_SECURE_DEV, 0, NULL},
261 */
262 {PCI_CAP_NEXT_PTR_NULL, 0, 0}
263 };
264
265
266 /*
267 * Save the configuration registers for cdip as a property
268 * so that it persists after detach/uninitchild.
269 */
270 int
pci_save_config_regs(dev_info_t * dip)271 pci_save_config_regs(dev_info_t *dip)
272 {
273 ddi_acc_handle_t confhdl;
274 pci_config_header_state_t *chsp;
275 pci_cap_save_desc_t *pci_cap_descp;
276 int ret;
277 uint32_t i, ncaps, nwords;
278 uint32_t *regbuf, *p;
279 uint8_t *maskbuf;
280 size_t maskbufsz, regbufsz, capbufsz;
281 #ifdef __sparc
282 ddi_acc_hdl_t *hp;
283 #else
284 ddi_device_acc_attr_t attr;
285 caddr_t cfgaddr;
286 #endif
287 off_t offset = 0;
288 uint8_t cap_ptr, cap_id;
289 int pcie = 0;
290 uint16_t status;
291
292 PMD(PMD_SX, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip),
293 ddi_get_instance(dip)))
294
295 #ifdef __sparc
296 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) {
297 cmn_err(CE_WARN, "%s%d can't get config handle",
298 ddi_driver_name(dip), ddi_get_instance(dip));
299
300 return (DDI_FAILURE);
301 }
302 #else
303 /* Set up cautious config access handle */
304 attr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
305 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
306 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
307 attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
308 if (ddi_regs_map_setup(dip, 0, &cfgaddr, 0, 0, &attr, &confhdl)
309 != DDI_SUCCESS) {
310 cmn_err(CE_WARN, "%s%d can't setup cautious config handle",
311 ddi_driver_name(dip), ddi_get_instance(dip));
312
313 return (DDI_FAILURE);
314 }
315 #endif
316
317 /*
318 * Determine if it implements capabilities
319 */
320 status = pci_config_get16(confhdl, PCI_CONF_STAT);
321 if (!(status & 0x10)) {
322 goto no_cap;
323 }
324 /*
325 * Determine if it is a pci express device. If it is, save entire
326 * 4k config space treating it as a array of 32 bit integers.
327 * If it is not, do it in a usual PCI way.
328 */
329 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR);
330 /*
331 * Walk the capabilities searching for pci express capability
332 */
333 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
334 cap_id = pci_config_get8(confhdl,
335 cap_ptr + PCI_CAP_ID);
336 if (cap_id == PCI_CAP_ID_PCI_E) {
337 pcie = 1;
338 break;
339 }
340 cap_ptr = pci_config_get8(confhdl,
341 cap_ptr + PCI_CAP_NEXT_PTR);
342 }
343 no_cap:
344 if (pcie) {
345 /* PCI express device. Can have data in all 4k space */
346 regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE,
347 KM_SLEEP);
348 p = regbuf;
349 /*
350 * Allocate space for mask.
351 * mask size is 128 bytes (4096 / 4 / 8 )
352 */
353 maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >>
354 INDEX_SHIFT);
355 maskbuf = (uint8_t *)kmem_zalloc(maskbufsz, KM_SLEEP);
356 #ifdef __sparc
357 hp = impl_acc_hdl_get(confhdl);
358 #endif
359 for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) {
360 #ifdef __sparc
361 ret = ddi_peek32(dip, (int32_t *)(hp->ah_addr + offset),
362 (int32_t *)p);
363 if (ret == DDI_SUCCESS) {
364 #else
365 /*
366 * ddi_peek doesn't work on x86, so we use cautious pci
367 * config access instead.
368 */
369 *p = pci_config_get32(confhdl, offset);
370 if (*p != -1) {
371 #endif
372 /* it is readable register. set the bit */
373 maskbuf[i >> INDEX_SHIFT] |=
374 (uint8_t)(1 << (i & BITMASK));
375 }
376 p++;
377 offset += sizeof (uint32_t);
378 }
379
380 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
381 SAVED_CONFIG_REGS_MASK, (uchar_t *)maskbuf,
382 maskbufsz)) != DDI_PROP_SUCCESS) {
383 cmn_err(CE_WARN, "couldn't create %s property while"
384 "saving config space for %s@%d\n",
385 SAVED_CONFIG_REGS_MASK, ddi_driver_name(dip),
386 ddi_get_instance(dip));
387 } else if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE,
388 dip, SAVED_CONFIG_REGS, (uchar_t *)regbuf,
389 (size_t)PCIE_CONF_HDR_SIZE)) != DDI_PROP_SUCCESS) {
390 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
391 SAVED_CONFIG_REGS_MASK);
392 cmn_err(CE_WARN, "%s%d can't update prop %s",
393 ddi_driver_name(dip), ddi_get_instance(dip),
394 SAVED_CONFIG_REGS);
395 }
396
397 kmem_free(maskbuf, (size_t)maskbufsz);
398 kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE);
399 } else {
400 regbuf = (uint32_t *)kmem_zalloc((size_t)PCI_CONF_HDR_SIZE,
401 KM_SLEEP);
402 chsp = (pci_config_header_state_t *)regbuf;
403
404 chsp->chs_command = pci_config_get16(confhdl, PCI_CONF_COMM);
405 chsp->chs_header_type = pci_config_get8(confhdl,
406 PCI_CONF_HEADER);
407 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) ==
408 PCI_HEADER_ONE)
409 chsp->chs_bridge_control =
410 pci_config_get16(confhdl, PCI_BCNF_BCNTRL);
411 chsp->chs_cache_line_size = pci_config_get8(confhdl,
412 PCI_CONF_CACHE_LINESZ);
413 chsp->chs_latency_timer = pci_config_get8(confhdl,
414 PCI_CONF_LATENCY_TIMER);
415 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) ==
416 PCI_HEADER_ONE) {
417 chsp->chs_sec_latency_timer =
418 pci_config_get8(confhdl, PCI_BCNF_LATENCY_TIMER);
419 }
420
421 chsp->chs_base0 = pci_config_get32(confhdl, PCI_CONF_BASE0);
422 chsp->chs_base1 = pci_config_get32(confhdl, PCI_CONF_BASE1);
423 chsp->chs_base2 = pci_config_get32(confhdl, PCI_CONF_BASE2);
424 chsp->chs_base3 = pci_config_get32(confhdl, PCI_CONF_BASE3);
425 chsp->chs_base4 = pci_config_get32(confhdl, PCI_CONF_BASE4);
426 chsp->chs_base5 = pci_config_get32(confhdl, PCI_CONF_BASE5);
427
428 /*
429 * Allocate maximum space required for capability descriptions.
430 * The maximum number of capabilties saved is the number of
431 * capabilities listed in the pci_cap_table.
432 */
433 ncaps = (sizeof (pci_cap_table) / sizeof (pci_cap_entry_t));
434 capbufsz = ncaps * sizeof (pci_cap_save_desc_t);
435 pci_cap_descp = (pci_cap_save_desc_t *)kmem_zalloc(
436 capbufsz, KM_SLEEP);
437 p = (uint32_t *)((caddr_t)regbuf +
438 sizeof (pci_config_header_state_t));
439 nwords = pci_save_caps(confhdl, p, pci_cap_descp, &ncaps);
440 regbufsz = sizeof (pci_config_header_state_t) +
441 nwords * sizeof (uint32_t);
442
443 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
444 SAVED_CONFIG_REGS, (uchar_t *)regbuf, regbufsz)) !=
445 DDI_PROP_SUCCESS) {
446 cmn_err(CE_WARN, "%s%d can't update prop %s",
447 ddi_driver_name(dip), ddi_get_instance(dip),
448 SAVED_CONFIG_REGS);
449 } else if (ncaps) {
450 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
451 SAVED_CONFIG_REGS_CAPINFO, (uchar_t *)pci_cap_descp,
452 ncaps * sizeof (pci_cap_save_desc_t));
453 if (ret != DDI_PROP_SUCCESS)
454 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
455 SAVED_CONFIG_REGS);
456 }
457 kmem_free(regbuf, (size_t)PCI_CONF_HDR_SIZE);
458 kmem_free(pci_cap_descp, capbufsz);
459 }
460 pci_config_teardown(&confhdl);
461
462 if (ret != DDI_PROP_SUCCESS)
463 return (DDI_FAILURE);
464
465 return (DDI_SUCCESS);
466 }
467
468 /*
469 * Saves registers associated with PCI capabilities.
470 * Returns number of 32 bit words saved.
471 * Number of capabilities saved is returned in ncapsp.
472 */
473 static uint32_t
474 pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
475 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp)
476 {
477 return (cap_walk_and_save(confhdl, regbuf, cap_descp, ncapsp, 0));
478 }
479
480 static uint32_t
481 cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf,
482 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace)
483 {
484 pci_cap_entry_t *pci_cap_entp;
485 uint16_t cap_id, offset, status;
486 uint32_t words_saved = 0, nwords = 0;
487 uint16_t cap_ptr = PCI_CAP_NEXT_PTR_NULL;
488 uint16_t cap_reg;
489
490 *ncapsp = 0;
491
492 /*
493 * Determine if it implements capabilities
494 */
495 status = pci_config_get16(confhdl, PCI_CONF_STAT);
496 if (!(status & 0x10)) {
497 return (words_saved);
498 }
499
500 if (!xspace)
501 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR);
502 /*
503 * Walk the capabilities
504 */
505 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
506 cap_id = CAP_ID(confhdl, cap_ptr, xspace);
507
508 /* Search for this cap id in our table */
509 if (!xspace) {
510 pci_cap_entp = pci_cap_table;
511 cap_reg = pci_config_get16(confhdl,
512 cap_ptr + PCI_CAP_ID_REGS_OFF);
513 }
514
515 while (pci_cap_entp->cap_id != PCI_CAP_NEXT_PTR_NULL) {
516 if (pci_cap_entp->cap_id == cap_id &&
517 (cap_reg & pci_cap_entp->cap_mask) ==
518 pci_cap_entp->cap_reg)
519 break;
520
521 pci_cap_entp++;
522 }
523
524 offset = cap_ptr;
525 cap_ptr = NEXT_CAP(confhdl, cap_ptr, xspace);
526 /*
527 * If this cap id is not found in the table, there is nothing
528 * to save.
529 */
530 if (pci_cap_entp->cap_id == PCI_CAP_NEXT_PTR_NULL)
531 continue;
532 if (pci_cap_entp->cap_save_func) {
533 if ((nwords = pci_cap_entp->cap_save_func(confhdl,
534 offset, regbuf, pci_cap_entp->cap_ndwords))) {
535 cap_descp->cap_nregs = nwords;
536 cap_descp->cap_offset = offset;
537 cap_descp->cap_id = cap_id;
538 regbuf += nwords;
539 cap_descp++;
540 words_saved += nwords;
541 (*ncapsp)++;
542 }
543 }
544
545 }
546 return (words_saved);
547 }
548
549 static void
550 pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
551 uint32_t *regbuf, uint32_t nwords)
552 {
553 int i;
554
555 for (i = 0; i < nwords; i++) {
556 *regbuf = pci_config_get32(confhdl, cap_ptr);
557 regbuf++;
558 cap_ptr += 4;
559 }
560 }
561
562 static uint32_t
563 pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
564 uint32_t nwords)
565 {
566 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
567 return (nwords);
568 }
569
570 /*ARGSUSED*/
571 static uint32_t
572 pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
573 uint32_t notused)
574 {
575 uint32_t nwords = PCI_MSI_MIN_WORDS;
576 uint16_t msi_ctrl;
577
578 /* Figure out how many registers to be saved */
579 msi_ctrl = pci_config_get16(confhdl, cap_ptr + PCI_MSI_CTRL);
580 /* If 64 bit address capable add one word */
581 if (msi_ctrl & PCI_MSI_64BIT_MASK)
582 nwords++;
583 /* If per vector masking capable, add two more words */
584 if (msi_ctrl & PCI_MSI_PVM_MASK)
585 nwords += 2;
586 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
587
588 return (nwords);
589 }
590
591 /*ARGSUSED*/
592 static uint32_t
593 pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
594 uint32_t notused)
595 {
596 uint32_t nwords = PCI_PCIX_MIN_WORDS;
597 uint16_t pcix_command;
598
599 /* Figure out how many registers to be saved */
600 pcix_command = pci_config_get16(confhdl, cap_ptr + PCI_PCIX_COMMAND);
601 /* If it is version 1 or version 2, add 4 words */
602 if (((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_1) ||
603 ((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2))
604 nwords += 4;
605 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
606
607 return (nwords);
608 }
609
610 /*ARGSUSED*/
611 static uint32_t
612 pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
613 uint32_t notused)
614 {
615 return (0);
616 }
617
618 /*ARGSUSED*/
619 static uint32_t
620 pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
621 uint32_t *regbuf, uint32_t notused)
622 {
623 uint32_t nwords = 0;
624 uint16_t reg;
625
626 reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF);
627
628 switch ((reg & PCI_HTCAP_ADDRMAP_MAPTYPE_MASK) >>
629 PCI_HTCAP_ADDRMAP_MAPTYPE_SHIFT) {
630 case PCI_HTCAP_ADDRMAP_40BIT_ID:
631 /* HT3.1 spec, ch 7.7, 40-bit dma */
632 nwords = 3 + ((reg & PCI_HTCAP_ADDRMAP_NUMMAP_MASK) * 2);
633 break;
634 case PCI_HTCAP_ADDRMAP_64BIT_ID:
635 /* HT3.1 spec, ch 7.8, 64-bit dma */
636 nwords = 4;
637 break;
638 default:
639 nwords = 0;
640 }
641
642 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
643 return (nwords);
644 }
645
646 /*ARGSUSED*/
647 static uint32_t
648 pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
649 uint32_t *regbuf, uint32_t notused)
650 {
651 uint32_t nwords;
652 uint16_t reg;
653
654 reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF);
655
656 /* HT3.1 spec, ch 7.17 */
657 nwords = 1 + (reg & PCI_HTCAP_FUNCEXT_LEN_MASK);
658
659 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
660 return (nwords);
661 }
662
663 static void
664 pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf,
665 uint16_t pmcap_offset)
666 {
667 uint16_t pmcsr;
668 uint16_t pmcsr_offset = pmcap_offset + PCI_PMCSR;
669 uint32_t *saved_pmcsrp = (uint32_t *)((caddr_t)regbuf + PCI_PMCSR);
670
671 /*
672 * Copy the power state bits from the PMCSR to our saved copy.
673 * This is to make sure that we don't change the D state when
674 * we restore config space of the device.
675 */
676 pmcsr = pci_config_get16(confhdl, pmcsr_offset);
677 (*saved_pmcsrp) &= ~PCI_PMCSR_STATE_MASK;
678 (*saved_pmcsrp) |= (pmcsr & PCI_PMCSR_STATE_MASK);
679 }
680
681 static void
682 pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
683 pci_cap_save_desc_t *cap_descp, uint32_t elements)
684 {
685 int i, j;
686 uint16_t offset;
687
688 for (i = 0; i < (elements / sizeof (pci_cap_save_desc_t)); i++) {
689 offset = cap_descp->cap_offset;
690 if (cap_descp->cap_id == PCI_CAP_ID_PM)
691 pci_pmcap_check(confhdl, regbuf, offset);
692 for (j = 0; j < cap_descp->cap_nregs; j++) {
693 pci_config_put32(confhdl, offset, *regbuf);
694 regbuf++;
695 offset += 4;
696 }
697 cap_descp++;
698 }
699 }
700
701 /*
702 * Restore config_regs from a single devinfo node.
703 */
704 int
705 pci_restore_config_regs(dev_info_t *dip)
706 {
707 ddi_acc_handle_t confhdl;
708 pci_config_header_state_t *chs_p;
709 pci_cap_save_desc_t *cap_descp;
710 uint32_t elements, i;
711 uint8_t *maskbuf;
712 uint32_t *regbuf, *p;
713 off_t offset = 0;
714
715 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) {
716 cmn_err(CE_WARN, "%s%d can't get config handle",
717 ddi_driver_name(dip), ddi_get_instance(dip));
718 return (DDI_FAILURE);
719 }
720
721 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
722 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS_MASK,
723 (uchar_t **)&maskbuf, &elements) == DDI_PROP_SUCCESS) {
724
725 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
726 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS,
727 (uchar_t **)®buf, &elements) != DDI_PROP_SUCCESS) {
728 goto restoreconfig_err;
729 }
730 ASSERT(elements == PCIE_CONF_HDR_SIZE);
731 /* pcie device and has 4k config space saved */
732 p = regbuf;
733 for (i = 0; i < PCIE_CONF_HDR_SIZE / sizeof (uint32_t); i++) {
734 /* If the word is readable then restore it */
735 if (maskbuf[i >> INDEX_SHIFT] &
736 (uint8_t)(1 << (i & BITMASK)))
737 pci_config_put32(confhdl, offset, *p);
738 p++;
739 offset += sizeof (uint32_t);
740 }
741 ddi_prop_free(regbuf);
742 ddi_prop_free(maskbuf);
743 if (ndi_prop_remove(DDI_DEV_T_NONE, dip,
744 SAVED_CONFIG_REGS_MASK) != DDI_PROP_SUCCESS) {
745 cmn_err(CE_WARN, "%s%d can't remove prop %s",
746 ddi_driver_name(dip), ddi_get_instance(dip),
747 SAVED_CONFIG_REGS_MASK);
748 }
749 } else {
750 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
751 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS,
752 (uchar_t **)®buf, &elements) != DDI_PROP_SUCCESS) {
753
754 pci_config_teardown(&confhdl);
755 return (DDI_SUCCESS);
756 }
757
758 chs_p = (pci_config_header_state_t *)regbuf;
759 pci_config_put16(confhdl, PCI_CONF_COMM,
760 chs_p->chs_command);
761 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) ==
762 PCI_HEADER_ONE) {
763 pci_config_put16(confhdl, PCI_BCNF_BCNTRL,
764 chs_p->chs_bridge_control);
765 }
766 pci_config_put8(confhdl, PCI_CONF_CACHE_LINESZ,
767 chs_p->chs_cache_line_size);
768 pci_config_put8(confhdl, PCI_CONF_LATENCY_TIMER,
769 chs_p->chs_latency_timer);
770 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) ==
771 PCI_HEADER_ONE)
772 pci_config_put8(confhdl, PCI_BCNF_LATENCY_TIMER,
773 chs_p->chs_sec_latency_timer);
774
775 pci_config_put32(confhdl, PCI_CONF_BASE0, chs_p->chs_base0);
776 pci_config_put32(confhdl, PCI_CONF_BASE1, chs_p->chs_base1);
777 pci_config_put32(confhdl, PCI_CONF_BASE2, chs_p->chs_base2);
778 pci_config_put32(confhdl, PCI_CONF_BASE3, chs_p->chs_base3);
779 pci_config_put32(confhdl, PCI_CONF_BASE4, chs_p->chs_base4);
780 pci_config_put32(confhdl, PCI_CONF_BASE5, chs_p->chs_base5);
781
782 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
783 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
784 SAVED_CONFIG_REGS_CAPINFO,
785 (uchar_t **)&cap_descp, &elements) == DDI_PROP_SUCCESS) {
786 /*
787 * PCI capability related regsiters are saved.
788 * Restore them based on the description.
789 */
790 p = (uint32_t *)((caddr_t)regbuf +
791 sizeof (pci_config_header_state_t));
792 pci_restore_caps(confhdl, p, cap_descp, elements);
793 ddi_prop_free(cap_descp);
794 }
795
796 ddi_prop_free(regbuf);
797 }
798
799 /*
800 * Make sure registers are flushed
801 */
802 (void) pci_config_get32(confhdl, PCI_CONF_BASE5);
803
804
805 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS) !=
806 DDI_PROP_SUCCESS) {
807 cmn_err(CE_WARN, "%s%d can't remove prop %s",
808 ddi_driver_name(dip), ddi_get_instance(dip),
809 SAVED_CONFIG_REGS);
810 }
811
812 pci_config_teardown(&confhdl);
813
814 return (DDI_SUCCESS);
815
816 restoreconfig_err:
817 ddi_prop_free(maskbuf);
818 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK) !=
819 DDI_PROP_SUCCESS) {
820 cmn_err(CE_WARN, "%s%d can't remove prop %s",
821 ddi_driver_name(dip), ddi_get_instance(dip),
822 SAVED_CONFIG_REGS_MASK);
823 }
824 pci_config_teardown(&confhdl);
825 return (DDI_FAILURE);
826 }
827
828 /*ARGSUSED*/
829 static int
830 pci_lookup_pmcap(dev_info_t *dip, ddi_acc_handle_t conf_hdl,
831 uint16_t *pmcap_offsetp)
832 {
833 uint8_t cap_ptr;
834 uint8_t cap_id;
835 uint8_t header_type;
836 uint16_t status;
837
838 header_type = pci_config_get8(conf_hdl, PCI_CONF_HEADER);
839 header_type &= PCI_HEADER_TYPE_M;
840
841 /* we don't deal with bridges, etc here */
842 if (header_type != PCI_HEADER_ZERO) {
843 return (DDI_FAILURE);
844 }
845
846 status = pci_config_get16(conf_hdl, PCI_CONF_STAT);
847 if ((status & PCI_STAT_CAP) == 0) {
848 return (DDI_FAILURE);
849 }
850
851 cap_ptr = pci_config_get8(conf_hdl, PCI_CONF_CAP_PTR);
852
853 /*
854 * Walk the capabilities searching for a PM entry.
855 */
856 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
857 cap_id = pci_config_get8(conf_hdl, cap_ptr + PCI_CAP_ID);
858 if (cap_id == PCI_CAP_ID_PM) {
859 break;
860 }
861 cap_ptr = pci_config_get8(conf_hdl,
862 cap_ptr + PCI_CAP_NEXT_PTR);
863 }
864
865 if (cap_ptr == PCI_CAP_NEXT_PTR_NULL) {
866 return (DDI_FAILURE);
867 }
868 *pmcap_offsetp = cap_ptr;
869 return (DDI_SUCCESS);
870 }
871
872 /*
873 * Do common pci-specific suspend actions:
874 * - enable wakeup if appropriate for the device
875 * - put device in lowest D-state that supports wakeup, or D3 if none
876 * - turn off bus mastering in control register
877 * For lack of per-dip storage (parent private date is pretty busy)
878 * we use properties to store the necessary context
879 * To avoid grotting through pci config space on every suspend,
880 * we leave the prop in existence after resume, cause we know that
881 * the detach framework code will dispose of it for us.
882 */
883
884 typedef struct pci_pm_context {
885 int ppc_flags;
886 uint16_t ppc_cap_offset; /* offset in config space to pm cap */
887 uint16_t ppc_pmcsr; /* need this too */
888 uint16_t ppc_suspend_level;
889 } pci_pm_context_t;
890
891 #define SAVED_PM_CONTEXT "pci-pm-context"
892
893 /* values for ppc_flags */
894 #define PPCF_NOPMCAP 1
895
896 /*
897 * Handle pci-specific suspend processing
898 * PM CSR and PCI CMD are saved by pci_save_config_regs().
899 * If device can wake up system via PME, enable it to do so
900 * Set device power level to lowest that can generate PME, or D3 if none can
901 * Turn off bus master enable in pci command register
902 */
903 #if defined(__x86)
904 extern int acpi_ddi_setwake(dev_info_t *dip, int level);
905 #endif
906
907 int
908 pci_post_suspend(dev_info_t *dip)
909 {
910 pci_pm_context_t *p;
911 uint16_t pmcap, pmcsr, pcicmd;
912 uint_t length;
913 int ret;
914 int fromprop = 1; /* source of memory *p */
915 ddi_acc_handle_t hdl;
916
917 PMD(PMD_SX, ("pci_post_suspend %s:%d\n",
918 ddi_driver_name(dip), ddi_get_instance(dip)))
919
920 if (pci_save_config_regs(dip) != DDI_SUCCESS) {
921 return (DDI_FAILURE);
922 }
923
924 if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) {
925 return (DDI_FAILURE);
926 }
927
928 pmcsr = 0;
929 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
930 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
931 SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) {
932 p = (pci_pm_context_t *)kmem_zalloc(sizeof (*p), KM_SLEEP);
933 fromprop = 0;
934 if (pci_lookup_pmcap(dip, hdl,
935 &p->ppc_cap_offset) != DDI_SUCCESS) {
936 p->ppc_flags |= PPCF_NOPMCAP;
937 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
938 SAVED_PM_CONTEXT, (uchar_t *)p,
939 sizeof (pci_pm_context_t));
940 if (ret != DDI_PROP_SUCCESS) {
941 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
942 SAVED_PM_CONTEXT);
943 ret = DDI_FAILURE;
944 } else {
945 ret = DDI_SUCCESS;
946 }
947 goto done;
948 }
949 /*
950 * Upon suspend, set the power level to the lowest that can
951 * wake the system. If none can, then set to lowest.
952 * XXX later we will need to check policy to see if this
953 * XXX device has had wakeup disabled
954 */
955 pmcap = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCAP);
956 if ((pmcap & (PCI_PMCAP_D3COLD_PME | PCI_PMCAP_D3HOT_PME)) != 0)
957 p->ppc_suspend_level =
958 (PCI_PMCSR_PME_EN | PCI_PMCSR_D3HOT);
959 else if ((pmcap & PCI_PMCAP_D2_PME) != 0)
960 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D2;
961 else if ((pmcap & PCI_PMCAP_D1_PME) != 0)
962 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D1;
963 else if ((pmcap & PCI_PMCAP_D0_PME) != 0)
964 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D0;
965 else
966 p->ppc_suspend_level = PCI_PMCSR_D3HOT;
967
968 /*
969 * we defer updating the property to catch the saved
970 * register values as well
971 */
972 }
973 /* If we set this in kmem_zalloc'd memory, we already returned above */
974 if ((p->ppc_flags & PPCF_NOPMCAP) != 0) {
975 goto done;
976 }
977
978 pmcsr = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCSR);
979 p->ppc_pmcsr = pmcsr;
980 pmcsr &= (PCI_PMCSR_STATE_MASK);
981 pmcsr |= (PCI_PMCSR_PME_STAT | p->ppc_suspend_level);
982
983 /*
984 * Push out saved register values
985 */
986 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT,
987 (uchar_t *)p, sizeof (pci_pm_context_t));
988 if (ret == DDI_PROP_SUCCESS) {
989 goto done;
990 }
991 /* Failed; put things back the way we found them */
992 (void) pci_restore_config_regs(dip);
993 if (fromprop)
994 ddi_prop_free(p);
995 else
996 kmem_free(p, sizeof (*p));
997 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT);
998 pci_config_teardown(&hdl);
999 return (DDI_FAILURE);
1000
1001 done:
1002
1003 /*
1004 * According to 8.2.2 of "PCI Bus Power Management Interface
1005 * Specification Revision 1.2":
1006 * "When placing a function into D3, the operating system software is
1007 * required to disable I/O and memory space as well as bus mastering via
1008 * the PCI Command register."
1009 */
1010
1011 pcicmd = pci_config_get16(hdl, PCI_CONF_COMM);
1012 pcicmd &= ~(PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_IO);
1013 pci_config_put16(hdl, PCI_CONF_COMM, pcicmd);
1014
1015
1016 #if defined(__x86)
1017 if (pci_enable_wakeup &&
1018 (p->ppc_suspend_level & PCI_PMCSR_PME_EN) != 0) {
1019 ret = acpi_ddi_setwake(dip, 3);
1020
1021 if (ret) {
1022 PMD(PMD_SX, ("pci_post_suspend, setwake %s@%s rets "
1023 "%x\n", PM_NAME(dip), PM_ADDR(dip), ret));
1024 }
1025 }
1026 #endif
1027
1028 if (p) {
1029
1030 /*
1031 * Some BIOS (e.g. Toshiba M10) expects pci-ide to be in D0
1032 * state when we set SLP_EN, otherwise it takes 5 minutes for
1033 * the BIOS to put the system into S3.
1034 */
1035 if (strcmp(ddi_node_name(dip), "pci-ide") == 0) {
1036 pmcsr = 0;
1037 }
1038
1039 /*
1040 * pmcsr is the last write-operation to the device's PCI
1041 * config space, because we found that there are
1042 * some faulty devices whose PCI config space may not
1043 * respond correctly once in D3 state.
1044 */
1045 if ((p->ppc_flags & PPCF_NOPMCAP) == 0 && pci_enable_wakeup) {
1046 pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR,
1047 PCI_PMCSR_PME_STAT);
1048 pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR,
1049 pmcsr);
1050 }
1051
1052 if (fromprop)
1053 ddi_prop_free(p);
1054 else
1055 kmem_free(p, sizeof (*p));
1056 }
1057
1058 pci_config_teardown(&hdl);
1059
1060 return (DDI_SUCCESS);
1061 }
1062
1063 /*
1064 * The inverse of pci_post_suspend; handle pci-specific resume processing
1065 * First, turn device back on, then restore config space.
1066 */
1067
1068 int
1069 pci_pre_resume(dev_info_t *dip)
1070 {
1071 ddi_acc_handle_t hdl;
1072 pci_pm_context_t *p;
1073 /* E_FUNC_SET_NOT_USED */
1074 uint16_t pmcap, pmcsr;
1075 int flags;
1076 uint_t length;
1077 clock_t drv_usectohz(clock_t microsecs);
1078
1079 PMD(PMD_SX, ("pci_pre_resume %s:%d\n", ddi_driver_name(dip),
1080 ddi_get_instance(dip)))
1081 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
1082 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1083 SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) {
1084 return (DDI_FAILURE);
1085 }
1086 flags = p->ppc_flags;
1087 pmcap = p->ppc_cap_offset;
1088 pmcsr = p->ppc_pmcsr;
1089
1090 #if defined(__x86)
1091 /*
1092 * Turn platform wake enable back off
1093 */
1094 if (pci_enable_wakeup &&
1095 (p->ppc_suspend_level & PCI_PMCSR_PME_EN) != 0) {
1096 int retval;
1097
1098 retval = acpi_ddi_setwake(dip, 0); /* 0 for now */
1099 if (retval) {
1100 PMD(PMD_SX, ("pci_pre_resume, setwake %s@%s rets "
1101 "%x\n", PM_NAME(dip), PM_ADDR(dip), retval));
1102 }
1103 }
1104 #endif
1105
1106 ddi_prop_free(p);
1107
1108 if ((flags & PPCF_NOPMCAP) != 0)
1109 goto done;
1110
1111 if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) {
1112 return (DDI_FAILURE);
1113 }
1114 pci_config_put16(hdl, pmcap + PCI_PMCSR, pmcsr);
1115 delay(drv_usectohz(10000)); /* PCI PM spec D3->D0 (10ms) */
1116 pci_config_teardown(&hdl);
1117 done:
1118 (void) pci_restore_config_regs(dip); /* fudges D-state! */
1119 return (DDI_SUCCESS);
1120 }
1121