include: gcc 7's cpp has problems with the line continuations in .x files
[unleashed.git] / kernel / os / sunpci.c
blob5389ad2a222699dac5bad77c349fc7331dd90122
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
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>
33 int pci_enable_wakeup = 1;
35 int
36 pci_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle)
38 caddr_t cfgaddr;
39 ddi_device_acc_attr_t attr;
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;
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;
51 return (ddi_regs_map_setup(dip, 0, &cfgaddr, 0, 0, &attr, handle));
54 void
55 pci_config_teardown(ddi_acc_handle_t *handle)
57 ddi_regs_map_free(handle);
60 uint8_t
61 pci_config_get8(ddi_acc_handle_t handle, off_t offset)
63 caddr_t cfgaddr;
64 ddi_acc_hdl_t *hp;
66 hp = impl_acc_hdl_get(handle);
67 cfgaddr = hp->ah_addr + offset;
68 return (ddi_get8(handle, (uint8_t *)cfgaddr));
71 uint16_t
72 pci_config_get16(ddi_acc_handle_t handle, off_t offset)
74 caddr_t cfgaddr;
75 ddi_acc_hdl_t *hp;
77 hp = impl_acc_hdl_get(handle);
78 cfgaddr = hp->ah_addr + offset;
79 return (ddi_get16(handle, (uint16_t *)cfgaddr));
82 uint32_t
83 pci_config_get32(ddi_acc_handle_t handle, off_t offset)
85 caddr_t cfgaddr;
86 ddi_acc_hdl_t *hp;
88 hp = impl_acc_hdl_get(handle);
89 cfgaddr = hp->ah_addr + offset;
90 return (ddi_get32(handle, (uint32_t *)cfgaddr));
93 uint64_t
94 pci_config_get64(ddi_acc_handle_t handle, off_t offset)
96 caddr_t cfgaddr;
97 ddi_acc_hdl_t *hp;
99 hp = impl_acc_hdl_get(handle);
100 cfgaddr = hp->ah_addr + offset;
101 return (ddi_get64(handle, (uint64_t *)cfgaddr));
104 void
105 pci_config_put8(ddi_acc_handle_t handle, off_t offset, uint8_t value)
107 caddr_t cfgaddr;
108 ddi_acc_hdl_t *hp;
110 hp = impl_acc_hdl_get(handle);
111 cfgaddr = hp->ah_addr + offset;
112 ddi_put8(handle, (uint8_t *)cfgaddr, value);
115 void
116 pci_config_put16(ddi_acc_handle_t handle, off_t offset, uint16_t value)
118 caddr_t cfgaddr;
119 ddi_acc_hdl_t *hp;
121 hp = impl_acc_hdl_get(handle);
122 cfgaddr = hp->ah_addr + offset;
123 ddi_put16(handle, (uint16_t *)cfgaddr, value);
126 void
127 pci_config_put32(ddi_acc_handle_t handle, off_t offset, uint32_t value)
129 caddr_t cfgaddr;
130 ddi_acc_hdl_t *hp;
132 hp = impl_acc_hdl_get(handle);
133 cfgaddr = hp->ah_addr + offset;
134 ddi_put32(handle, (uint32_t *)cfgaddr, value);
137 void
138 pci_config_put64(ddi_acc_handle_t handle, off_t offset, uint64_t value)
140 caddr_t cfgaddr;
141 ddi_acc_hdl_t *hp;
143 hp = impl_acc_hdl_get(handle);
144 cfgaddr = hp->ah_addr + offset;
145 ddi_put64(handle, (uint64_t *)cfgaddr, value);
149 * We need to separate the old interfaces from the new ones and leave them
150 * in here for a while. Previous versions of the OS defined the new interfaces
151 * to the old interfaces. This way we can fix things up so that we can
152 * eventually remove these interfaces.
153 * e.g. A 3rd party module/driver using pci_config_get8 and built against S10
154 * or earlier will actually have a reference to pci_config_getb in the binary.
156 #ifdef _ILP32
157 uint8_t
158 pci_config_getb(ddi_acc_handle_t handle, off_t offset)
160 caddr_t cfgaddr;
161 ddi_acc_hdl_t *hp;
163 hp = impl_acc_hdl_get(handle);
164 cfgaddr = hp->ah_addr + offset;
165 return (ddi_get8(handle, (uint8_t *)cfgaddr));
168 uint16_t
169 pci_config_getw(ddi_acc_handle_t handle, off_t offset)
171 caddr_t cfgaddr;
172 ddi_acc_hdl_t *hp;
174 hp = impl_acc_hdl_get(handle);
175 cfgaddr = hp->ah_addr + offset;
176 return (ddi_get16(handle, (uint16_t *)cfgaddr));
179 uint32_t
180 pci_config_getl(ddi_acc_handle_t handle, off_t offset)
182 caddr_t cfgaddr;
183 ddi_acc_hdl_t *hp;
185 hp = impl_acc_hdl_get(handle);
186 cfgaddr = hp->ah_addr + offset;
187 return (ddi_get32(handle, (uint32_t *)cfgaddr));
190 uint64_t
191 pci_config_getll(ddi_acc_handle_t handle, off_t offset)
193 caddr_t cfgaddr;
194 ddi_acc_hdl_t *hp;
196 hp = impl_acc_hdl_get(handle);
197 cfgaddr = hp->ah_addr + offset;
198 return (ddi_get64(handle, (uint64_t *)cfgaddr));
201 void
202 pci_config_putb(ddi_acc_handle_t handle, off_t offset, uint8_t value)
204 caddr_t cfgaddr;
205 ddi_acc_hdl_t *hp;
207 hp = impl_acc_hdl_get(handle);
208 cfgaddr = hp->ah_addr + offset;
209 ddi_put8(handle, (uint8_t *)cfgaddr, value);
212 void
213 pci_config_putw(ddi_acc_handle_t handle, off_t offset, uint16_t value)
215 caddr_t cfgaddr;
216 ddi_acc_hdl_t *hp;
218 hp = impl_acc_hdl_get(handle);
219 cfgaddr = hp->ah_addr + offset;
220 ddi_put16(handle, (uint16_t *)cfgaddr, value);
223 void
224 pci_config_putl(ddi_acc_handle_t handle, off_t offset, uint32_t value)
226 caddr_t cfgaddr;
227 ddi_acc_hdl_t *hp;
229 hp = impl_acc_hdl_get(handle);
230 cfgaddr = hp->ah_addr + offset;
231 ddi_put32(handle, (uint32_t *)cfgaddr, value);
234 void
235 pci_config_putll(ddi_acc_handle_t handle, off_t offset, uint64_t value)
237 caddr_t cfgaddr;
238 ddi_acc_hdl_t *hp;
240 hp = impl_acc_hdl_get(handle);
241 cfgaddr = hp->ah_addr + offset;
242 ddi_put64(handle, (uint64_t *)cfgaddr, value);
244 #endif /* _ILP32 */
246 /*ARGSUSED*/
248 pci_report_pmcap(dev_info_t *dip, int cap, void *arg)
250 return (DDI_SUCCESS);
254 * Note about saving and restoring config space.
255 * PCI devices have only upto 256 bytes of config space while PCI Express
256 * devices can have upto 4k config space. In case of PCI Express device,
257 * we save all 4k config space and restore it even if it doesn't make use
258 * of all 4k. But some devices don't respond to reads to non-existent
259 * registers within the config space. To avoid any panics, we use ddi_peek
260 * to do the reads. A bit mask is used to indicate which words of the
261 * config space are accessible. While restoring the config space, only those
262 * readable words are restored. We do all this in 32 bit size words.
264 #define INDEX_SHIFT 3
265 #define BITMASK 0x7
267 static uint32_t pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
268 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp);
269 static void pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
270 pci_cap_save_desc_t *cap_descp, uint32_t elements);
271 static uint32_t pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
272 uint32_t *regbuf, uint32_t nwords);
273 static uint32_t pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
274 uint32_t *regbuf, uint32_t notused);
275 static uint32_t pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
276 uint32_t *regbuf, uint32_t notused);
277 static uint32_t pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
278 uint32_t *regbuf, uint32_t notused);
279 static uint32_t pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
280 uint32_t *regbuf, uint32_t notused);
281 static uint32_t pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
282 uint32_t *regbuf, uint32_t notused);
283 static void pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
284 uint32_t *regbuf, uint32_t nwords);
285 static uint32_t cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf,
286 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace);
287 static void pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf,
288 uint16_t pmcap_offset);
291 * Table below specifies the number of registers to be saved for each PCI
292 * capability. pci_generic_save saves the number of words specified in the
293 * table. Any special considerations will be taken care by the capability
294 * specific save function e.g. use pci_msi_save to save registers associated
295 * with MSI capability. PCI_UNKNOWN_SIZE indicates that number of registers
296 * to be saved is variable and will be determined by the specific save function.
297 * Currently we save/restore all the registers associated with the capability
298 * including read only registers. Regsiters are saved and restored in 32 bit
299 * size words.
301 static pci_cap_entry_t pci_cap_table[] = {
302 {PCI_CAP_ID_PM, 0, 0, PCI_PMCAP_NDWORDS, pci_generic_save},
303 {PCI_CAP_ID_AGP, 0, 0, PCI_AGP_NDWORDS, pci_generic_save},
304 {PCI_CAP_ID_SLOT_ID, 0, 0, PCI_SLOTID_NDWORDS, pci_generic_save},
305 {PCI_CAP_ID_MSI_X, 0, 0, PCI_MSIX_NDWORDS, pci_generic_save},
306 {PCI_CAP_ID_MSI, 0, 0, PCI_CAP_SZUNKNOWN, pci_msi_save},
307 {PCI_CAP_ID_PCIX, 0, 0, PCI_CAP_SZUNKNOWN, pci_pcix_save},
308 {PCI_CAP_ID_PCI_E, 0, 0, PCI_CAP_SZUNKNOWN, pci_pcie_save},
310 {PCI_CAP_ID_HT, PCI_HTCAP_SLPRI_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK,
311 PCI_HTCAP_SLPRI_NDWORDS, pci_generic_save},
313 {PCI_CAP_ID_HT, PCI_HTCAP_HOSTSEC_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK,
314 PCI_HTCAP_HOSTSEC_NDWORDS, pci_generic_save},
316 {PCI_CAP_ID_HT, PCI_HTCAP_INTCONF_TYPE, PCI_HTCAP_TYPE_MASK,
317 PCI_HTCAP_INTCONF_NDWORDS, pci_generic_save},
319 {PCI_CAP_ID_HT, PCI_HTCAP_REVID_TYPE, PCI_HTCAP_TYPE_MASK,
320 PCI_HTCAP_REVID_NDWORDS, pci_generic_save},
322 {PCI_CAP_ID_HT, PCI_HTCAP_UNITID_CLUMP_TYPE, PCI_HTCAP_TYPE_MASK,
323 PCI_HTCAP_UNITID_CLUMP_NDWORDS, pci_generic_save},
325 {PCI_CAP_ID_HT, PCI_HTCAP_ECFG_TYPE, PCI_HTCAP_TYPE_MASK,
326 PCI_HTCAP_ECFG_NDWORDS, pci_generic_save},
328 {PCI_CAP_ID_HT, PCI_HTCAP_ADDRMAP_TYPE, PCI_HTCAP_TYPE_MASK,
329 PCI_CAP_SZUNKNOWN, pci_ht_addrmap_save},
331 {PCI_CAP_ID_HT, PCI_HTCAP_MSIMAP_TYPE, PCI_HTCAP_TYPE_MASK,
332 PCI_HTCAP_MSIMAP_NDWORDS, pci_generic_save},
334 {PCI_CAP_ID_HT, PCI_HTCAP_DIRROUTE_TYPE, PCI_HTCAP_TYPE_MASK,
335 PCI_HTCAP_DIRROUTE_NDWORDS, pci_generic_save},
337 {PCI_CAP_ID_HT, PCI_HTCAP_VCSET_TYPE, PCI_HTCAP_TYPE_MASK,
338 PCI_HTCAP_VCSET_NDWORDS, pci_generic_save},
340 {PCI_CAP_ID_HT, PCI_HTCAP_RETRYMODE_TYPE, PCI_HTCAP_TYPE_MASK,
341 PCI_HTCAP_RETRYMODE_NDWORDS, pci_generic_save},
343 {PCI_CAP_ID_HT, PCI_HTCAP_GEN3_TYPE, PCI_HTCAP_TYPE_MASK,
344 PCI_HTCAP_GEN3_NDWORDS, pci_generic_save},
346 {PCI_CAP_ID_HT, PCI_HTCAP_FUNCEXT_TYPE, PCI_HTCAP_TYPE_MASK,
347 PCI_CAP_SZUNKNOWN, pci_ht_funcext_save},
349 {PCI_CAP_ID_HT, PCI_HTCAP_PM_TYPE, PCI_HTCAP_TYPE_MASK,
350 PCI_HTCAP_PM_NDWORDS, pci_generic_save},
353 * {PCI_CAP_ID_cPCI_CRC, 0, NULL},
354 * {PCI_CAP_ID_VPD, 0, NULL},
355 * {PCI_CAP_ID_cPCI_HS, 0, NULL},
356 * {PCI_CAP_ID_PCI_HOTPLUG, 0, NULL},
357 * {PCI_CAP_ID_AGP_8X, 0, NULL},
358 * {PCI_CAP_ID_SECURE_DEV, 0, NULL},
360 {PCI_CAP_NEXT_PTR_NULL, 0, 0}
365 * Save the configuration registers for cdip as a property
366 * so that it persists after detach/uninitchild.
369 pci_save_config_regs(dev_info_t *dip)
371 ddi_acc_handle_t confhdl;
372 pci_config_header_state_t *chsp;
373 pci_cap_save_desc_t *pci_cap_descp;
374 int ret;
375 uint32_t i, ncaps, nwords;
376 uint32_t *regbuf, *p;
377 uint8_t *maskbuf;
378 size_t maskbufsz, regbufsz, capbufsz;
379 ddi_device_acc_attr_t attr;
380 caddr_t cfgaddr;
381 off_t offset = 0;
382 uint8_t cap_ptr, cap_id;
383 int pcie = 0;
384 uint16_t status;
386 PMD(PMD_SX, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip),
387 ddi_get_instance(dip)))
389 /* Set up cautious config access handle */
390 attr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
391 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
392 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
393 attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
394 if (ddi_regs_map_setup(dip, 0, &cfgaddr, 0, 0, &attr, &confhdl)
395 != DDI_SUCCESS) {
396 cmn_err(CE_WARN, "%s%d can't setup cautious config handle",
397 ddi_driver_name(dip), ddi_get_instance(dip));
399 return (DDI_FAILURE);
403 * Determine if it implements capabilities
405 status = pci_config_get16(confhdl, PCI_CONF_STAT);
406 if (!(status & 0x10)) {
407 goto no_cap;
410 * Determine if it is a pci express device. If it is, save entire
411 * 4k config space treating it as a array of 32 bit integers.
412 * If it is not, do it in a usual PCI way.
414 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR);
416 * Walk the capabilities searching for pci express capability
418 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
419 cap_id = pci_config_get8(confhdl,
420 cap_ptr + PCI_CAP_ID);
421 if (cap_id == PCI_CAP_ID_PCI_E) {
422 pcie = 1;
423 break;
425 cap_ptr = pci_config_get8(confhdl,
426 cap_ptr + PCI_CAP_NEXT_PTR);
428 no_cap:
429 if (pcie) {
430 /* PCI express device. Can have data in all 4k space */
431 regbuf = kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE,
432 KM_SLEEP);
433 p = regbuf;
435 * Allocate space for mask.
436 * mask size is 128 bytes (4096 / 4 / 8 )
438 maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >>
439 INDEX_SHIFT);
440 maskbuf = kmem_zalloc(maskbufsz, KM_SLEEP);
441 for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) {
443 * ddi_peek doesn't work on x86, so we use cautious pci
444 * config access instead.
446 *p = pci_config_get32(confhdl, offset);
447 if (*p != -1) {
448 /* it is readable register. set the bit */
449 maskbuf[i >> INDEX_SHIFT] |=
450 (uint8_t)(1 << (i & BITMASK));
452 p++;
453 offset += sizeof (uint32_t);
456 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
457 SAVED_CONFIG_REGS_MASK, (uchar_t *)maskbuf,
458 maskbufsz)) != DDI_PROP_SUCCESS) {
459 cmn_err(CE_WARN, "couldn't create %s property while"
460 "saving config space for %s@%d\n",
461 SAVED_CONFIG_REGS_MASK, ddi_driver_name(dip),
462 ddi_get_instance(dip));
463 } else if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE,
464 dip, SAVED_CONFIG_REGS, (uchar_t *)regbuf,
465 (size_t)PCIE_CONF_HDR_SIZE)) != DDI_PROP_SUCCESS) {
466 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
467 SAVED_CONFIG_REGS_MASK);
468 cmn_err(CE_WARN, "%s%d can't update prop %s",
469 ddi_driver_name(dip), ddi_get_instance(dip),
470 SAVED_CONFIG_REGS);
473 kmem_free(maskbuf, (size_t)maskbufsz);
474 kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE);
475 } else {
476 regbuf = kmem_zalloc((size_t)PCI_CONF_HDR_SIZE,
477 KM_SLEEP);
478 chsp = (pci_config_header_state_t *)regbuf;
480 chsp->chs_command = pci_config_get16(confhdl, PCI_CONF_COMM);
481 chsp->chs_header_type = pci_config_get8(confhdl,
482 PCI_CONF_HEADER);
483 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) ==
484 PCI_HEADER_ONE)
485 chsp->chs_bridge_control =
486 pci_config_get16(confhdl, PCI_BCNF_BCNTRL);
487 chsp->chs_cache_line_size = pci_config_get8(confhdl,
488 PCI_CONF_CACHE_LINESZ);
489 chsp->chs_latency_timer = pci_config_get8(confhdl,
490 PCI_CONF_LATENCY_TIMER);
491 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) ==
492 PCI_HEADER_ONE) {
493 chsp->chs_sec_latency_timer =
494 pci_config_get8(confhdl, PCI_BCNF_LATENCY_TIMER);
497 chsp->chs_base0 = pci_config_get32(confhdl, PCI_CONF_BASE0);
498 chsp->chs_base1 = pci_config_get32(confhdl, PCI_CONF_BASE1);
499 chsp->chs_base2 = pci_config_get32(confhdl, PCI_CONF_BASE2);
500 chsp->chs_base3 = pci_config_get32(confhdl, PCI_CONF_BASE3);
501 chsp->chs_base4 = pci_config_get32(confhdl, PCI_CONF_BASE4);
502 chsp->chs_base5 = pci_config_get32(confhdl, PCI_CONF_BASE5);
505 * Allocate maximum space required for capability descriptions.
506 * The maximum number of capabilties saved is the number of
507 * capabilities listed in the pci_cap_table.
509 ncaps = (sizeof (pci_cap_table) / sizeof (pci_cap_entry_t));
510 capbufsz = ncaps * sizeof (pci_cap_save_desc_t);
511 pci_cap_descp = (pci_cap_save_desc_t *)kmem_zalloc(
512 capbufsz, KM_SLEEP);
513 p = (uint32_t *)((caddr_t)regbuf +
514 sizeof (pci_config_header_state_t));
515 nwords = pci_save_caps(confhdl, p, pci_cap_descp, &ncaps);
516 regbufsz = sizeof (pci_config_header_state_t) +
517 nwords * sizeof (uint32_t);
519 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
520 SAVED_CONFIG_REGS, (uchar_t *)regbuf, regbufsz)) !=
521 DDI_PROP_SUCCESS) {
522 cmn_err(CE_WARN, "%s%d can't update prop %s",
523 ddi_driver_name(dip), ddi_get_instance(dip),
524 SAVED_CONFIG_REGS);
525 } else if (ncaps) {
526 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
527 SAVED_CONFIG_REGS_CAPINFO, (uchar_t *)pci_cap_descp,
528 ncaps * sizeof (pci_cap_save_desc_t));
529 if (ret != DDI_PROP_SUCCESS)
530 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
531 SAVED_CONFIG_REGS);
533 kmem_free(regbuf, (size_t)PCI_CONF_HDR_SIZE);
534 kmem_free(pci_cap_descp, capbufsz);
536 pci_config_teardown(&confhdl);
538 if (ret != DDI_PROP_SUCCESS)
539 return (DDI_FAILURE);
541 return (DDI_SUCCESS);
545 * Saves registers associated with PCI capabilities.
546 * Returns number of 32 bit words saved.
547 * Number of capabilities saved is returned in ncapsp.
549 static uint32_t
550 pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
551 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp)
553 return (cap_walk_and_save(confhdl, regbuf, cap_descp, ncapsp, 0));
556 static uint32_t
557 cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf,
558 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace)
560 pci_cap_entry_t *pci_cap_entp;
561 uint16_t cap_id, offset, status;
562 uint32_t words_saved = 0, nwords = 0;
563 uint16_t cap_ptr = PCI_CAP_NEXT_PTR_NULL;
564 uint16_t cap_reg;
566 *ncapsp = 0;
569 * Determine if it implements capabilities
571 status = pci_config_get16(confhdl, PCI_CONF_STAT);
572 if (!(status & 0x10)) {
573 return (words_saved);
576 if (!xspace)
577 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR);
579 * Walk the capabilities
581 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
582 cap_id = CAP_ID(confhdl, cap_ptr, xspace);
584 /* Search for this cap id in our table */
585 if (!xspace) {
586 pci_cap_entp = pci_cap_table;
587 cap_reg = pci_config_get16(confhdl,
588 cap_ptr + PCI_CAP_ID_REGS_OFF);
591 while (pci_cap_entp->cap_id != PCI_CAP_NEXT_PTR_NULL) {
592 if (pci_cap_entp->cap_id == cap_id &&
593 (cap_reg & pci_cap_entp->cap_mask) ==
594 pci_cap_entp->cap_reg)
595 break;
597 pci_cap_entp++;
600 offset = cap_ptr;
601 cap_ptr = NEXT_CAP(confhdl, cap_ptr, xspace);
603 * If this cap id is not found in the table, there is nothing
604 * to save.
606 if (pci_cap_entp->cap_id == PCI_CAP_NEXT_PTR_NULL)
607 continue;
608 if (pci_cap_entp->cap_save_func) {
609 if ((nwords = pci_cap_entp->cap_save_func(confhdl,
610 offset, regbuf, pci_cap_entp->cap_ndwords))) {
611 cap_descp->cap_nregs = nwords;
612 cap_descp->cap_offset = offset;
613 cap_descp->cap_id = cap_id;
614 regbuf += nwords;
615 cap_descp++;
616 words_saved += nwords;
617 (*ncapsp)++;
622 return (words_saved);
625 static void
626 pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
627 uint32_t *regbuf, uint32_t nwords)
629 int i;
631 for (i = 0; i < nwords; i++) {
632 *regbuf = pci_config_get32(confhdl, cap_ptr);
633 regbuf++;
634 cap_ptr += 4;
638 static uint32_t
639 pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
640 uint32_t nwords)
642 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
643 return (nwords);
646 /*ARGSUSED*/
647 static uint32_t
648 pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
649 uint32_t notused)
651 uint32_t nwords = PCI_MSI_MIN_WORDS;
652 uint16_t msi_ctrl;
654 /* Figure out how many registers to be saved */
655 msi_ctrl = pci_config_get16(confhdl, cap_ptr + PCI_MSI_CTRL);
656 /* If 64 bit address capable add one word */
657 if (msi_ctrl & PCI_MSI_64BIT_MASK)
658 nwords++;
659 /* If per vector masking capable, add two more words */
660 if (msi_ctrl & PCI_MSI_PVM_MASK)
661 nwords += 2;
662 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
664 return (nwords);
667 /*ARGSUSED*/
668 static uint32_t
669 pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
670 uint32_t notused)
672 uint32_t nwords = PCI_PCIX_MIN_WORDS;
673 uint16_t pcix_command;
675 /* Figure out how many registers to be saved */
676 pcix_command = pci_config_get16(confhdl, cap_ptr + PCI_PCIX_COMMAND);
677 /* If it is version 1 or version 2, add 4 words */
678 if (((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_1) ||
679 ((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2))
680 nwords += 4;
681 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
683 return (nwords);
686 /*ARGSUSED*/
687 static uint32_t
688 pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf,
689 uint32_t notused)
691 return (0);
694 /*ARGSUSED*/
695 static uint32_t
696 pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
697 uint32_t *regbuf, uint32_t notused)
699 uint32_t nwords = 0;
700 uint16_t reg;
702 reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF);
704 switch ((reg & PCI_HTCAP_ADDRMAP_MAPTYPE_MASK) >>
705 PCI_HTCAP_ADDRMAP_MAPTYPE_SHIFT) {
706 case PCI_HTCAP_ADDRMAP_40BIT_ID:
707 /* HT3.1 spec, ch 7.7, 40-bit dma */
708 nwords = 3 + ((reg & PCI_HTCAP_ADDRMAP_NUMMAP_MASK) * 2);
709 break;
710 case PCI_HTCAP_ADDRMAP_64BIT_ID:
711 /* HT3.1 spec, ch 7.8, 64-bit dma */
712 nwords = 4;
713 break;
714 default:
715 nwords = 0;
718 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
719 return (nwords);
722 /*ARGSUSED*/
723 static uint32_t
724 pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr,
725 uint32_t *regbuf, uint32_t notused)
727 uint32_t nwords;
728 uint16_t reg;
730 reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF);
732 /* HT3.1 spec, ch 7.17 */
733 nwords = 1 + (reg & PCI_HTCAP_FUNCEXT_LEN_MASK);
735 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords);
736 return (nwords);
739 static void
740 pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf,
741 uint16_t pmcap_offset)
743 uint16_t pmcsr;
744 uint16_t pmcsr_offset = pmcap_offset + PCI_PMCSR;
745 uint32_t *saved_pmcsrp = (uint32_t *)((caddr_t)regbuf + PCI_PMCSR);
748 * Copy the power state bits from the PMCSR to our saved copy.
749 * This is to make sure that we don't change the D state when
750 * we restore config space of the device.
752 pmcsr = pci_config_get16(confhdl, pmcsr_offset);
753 (*saved_pmcsrp) &= ~PCI_PMCSR_STATE_MASK;
754 (*saved_pmcsrp) |= (pmcsr & PCI_PMCSR_STATE_MASK);
757 static void
758 pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf,
759 pci_cap_save_desc_t *cap_descp, uint32_t elements)
761 int i, j;
762 uint16_t offset;
764 for (i = 0; i < (elements / sizeof (pci_cap_save_desc_t)); i++) {
765 offset = cap_descp->cap_offset;
766 if (cap_descp->cap_id == PCI_CAP_ID_PM)
767 pci_pmcap_check(confhdl, regbuf, offset);
768 for (j = 0; j < cap_descp->cap_nregs; j++) {
769 pci_config_put32(confhdl, offset, *regbuf);
770 regbuf++;
771 offset += 4;
773 cap_descp++;
778 * Restore config_regs from a single devinfo node.
781 pci_restore_config_regs(dev_info_t *dip)
783 ddi_acc_handle_t confhdl;
784 pci_config_header_state_t *chs_p;
785 pci_cap_save_desc_t *cap_descp;
786 uint32_t elements, i;
787 uint8_t *maskbuf;
788 uint32_t *regbuf, *p;
789 off_t offset = 0;
791 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) {
792 cmn_err(CE_WARN, "%s%d can't get config handle",
793 ddi_driver_name(dip), ddi_get_instance(dip));
794 return (DDI_FAILURE);
797 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
798 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS_MASK,
799 (uchar_t **)&maskbuf, &elements) == DDI_PROP_SUCCESS) {
801 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
802 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS,
803 (uchar_t **)&regbuf, &elements) != DDI_PROP_SUCCESS) {
804 goto restoreconfig_err;
806 ASSERT(elements == PCIE_CONF_HDR_SIZE);
807 /* pcie device and has 4k config space saved */
808 p = regbuf;
809 for (i = 0; i < PCIE_CONF_HDR_SIZE / sizeof (uint32_t); i++) {
810 /* If the word is readable then restore it */
811 if (maskbuf[i >> INDEX_SHIFT] &
812 (uint8_t)(1 << (i & BITMASK)))
813 pci_config_put32(confhdl, offset, *p);
814 p++;
815 offset += sizeof (uint32_t);
817 ddi_prop_free(regbuf);
818 ddi_prop_free(maskbuf);
819 if (ndi_prop_remove(DDI_DEV_T_NONE, dip,
820 SAVED_CONFIG_REGS_MASK) != DDI_PROP_SUCCESS) {
821 cmn_err(CE_WARN, "%s%d can't remove prop %s",
822 ddi_driver_name(dip), ddi_get_instance(dip),
823 SAVED_CONFIG_REGS_MASK);
825 } else {
826 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
827 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS,
828 (uchar_t **)&regbuf, &elements) != DDI_PROP_SUCCESS) {
830 pci_config_teardown(&confhdl);
831 return (DDI_SUCCESS);
834 chs_p = (pci_config_header_state_t *)regbuf;
835 pci_config_put16(confhdl, PCI_CONF_COMM,
836 chs_p->chs_command);
837 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) ==
838 PCI_HEADER_ONE) {
839 pci_config_put16(confhdl, PCI_BCNF_BCNTRL,
840 chs_p->chs_bridge_control);
842 pci_config_put8(confhdl, PCI_CONF_CACHE_LINESZ,
843 chs_p->chs_cache_line_size);
844 pci_config_put8(confhdl, PCI_CONF_LATENCY_TIMER,
845 chs_p->chs_latency_timer);
846 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) ==
847 PCI_HEADER_ONE)
848 pci_config_put8(confhdl, PCI_BCNF_LATENCY_TIMER,
849 chs_p->chs_sec_latency_timer);
851 pci_config_put32(confhdl, PCI_CONF_BASE0, chs_p->chs_base0);
852 pci_config_put32(confhdl, PCI_CONF_BASE1, chs_p->chs_base1);
853 pci_config_put32(confhdl, PCI_CONF_BASE2, chs_p->chs_base2);
854 pci_config_put32(confhdl, PCI_CONF_BASE3, chs_p->chs_base3);
855 pci_config_put32(confhdl, PCI_CONF_BASE4, chs_p->chs_base4);
856 pci_config_put32(confhdl, PCI_CONF_BASE5, chs_p->chs_base5);
858 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
859 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
860 SAVED_CONFIG_REGS_CAPINFO,
861 (uchar_t **)&cap_descp, &elements) == DDI_PROP_SUCCESS) {
863 * PCI capability related regsiters are saved.
864 * Restore them based on the description.
866 p = (uint32_t *)((caddr_t)regbuf +
867 sizeof (pci_config_header_state_t));
868 pci_restore_caps(confhdl, p, cap_descp, elements);
869 ddi_prop_free(cap_descp);
872 ddi_prop_free(regbuf);
876 * Make sure registers are flushed
878 (void) pci_config_get32(confhdl, PCI_CONF_BASE5);
881 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS) !=
882 DDI_PROP_SUCCESS) {
883 cmn_err(CE_WARN, "%s%d can't remove prop %s",
884 ddi_driver_name(dip), ddi_get_instance(dip),
885 SAVED_CONFIG_REGS);
888 pci_config_teardown(&confhdl);
890 return (DDI_SUCCESS);
892 restoreconfig_err:
893 ddi_prop_free(maskbuf);
894 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK) !=
895 DDI_PROP_SUCCESS) {
896 cmn_err(CE_WARN, "%s%d can't remove prop %s",
897 ddi_driver_name(dip), ddi_get_instance(dip),
898 SAVED_CONFIG_REGS_MASK);
900 pci_config_teardown(&confhdl);
901 return (DDI_FAILURE);
904 /*ARGSUSED*/
905 static int
906 pci_lookup_pmcap(dev_info_t *dip, ddi_acc_handle_t conf_hdl,
907 uint16_t *pmcap_offsetp)
909 uint8_t cap_ptr;
910 uint8_t cap_id;
911 uint8_t header_type;
912 uint16_t status;
914 header_type = pci_config_get8(conf_hdl, PCI_CONF_HEADER);
915 header_type &= PCI_HEADER_TYPE_M;
917 /* we don't deal with bridges, etc here */
918 if (header_type != PCI_HEADER_ZERO) {
919 return (DDI_FAILURE);
922 status = pci_config_get16(conf_hdl, PCI_CONF_STAT);
923 if ((status & PCI_STAT_CAP) == 0) {
924 return (DDI_FAILURE);
927 cap_ptr = pci_config_get8(conf_hdl, PCI_CONF_CAP_PTR);
930 * Walk the capabilities searching for a PM entry.
932 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
933 cap_id = pci_config_get8(conf_hdl, cap_ptr + PCI_CAP_ID);
934 if (cap_id == PCI_CAP_ID_PM) {
935 break;
937 cap_ptr = pci_config_get8(conf_hdl,
938 cap_ptr + PCI_CAP_NEXT_PTR);
941 if (cap_ptr == PCI_CAP_NEXT_PTR_NULL) {
942 return (DDI_FAILURE);
944 *pmcap_offsetp = cap_ptr;
945 return (DDI_SUCCESS);
949 * Do common pci-specific suspend actions:
950 * - enable wakeup if appropriate for the device
951 * - put device in lowest D-state that supports wakeup, or D3 if none
952 * - turn off bus mastering in control register
953 * For lack of per-dip storage (parent private date is pretty busy)
954 * we use properties to store the necessary context
955 * To avoid grotting through pci config space on every suspend,
956 * we leave the prop in existence after resume, cause we know that
957 * the detach framework code will dispose of it for us.
960 typedef struct pci_pm_context {
961 int ppc_flags;
962 uint16_t ppc_cap_offset; /* offset in config space to pm cap */
963 uint16_t ppc_pmcsr; /* need this too */
964 uint16_t ppc_suspend_level;
965 } pci_pm_context_t;
967 #define SAVED_PM_CONTEXT "pci-pm-context"
969 /* values for ppc_flags */
970 #define PPCF_NOPMCAP 1
973 * Handle pci-specific suspend processing
974 * PM CSR and PCI CMD are saved by pci_save_config_regs().
975 * If device can wake up system via PME, enable it to do so
976 * Set device power level to lowest that can generate PME, or D3 if none can
977 * Turn off bus master enable in pci command register
979 #if defined(__x86)
980 extern int acpi_ddi_setwake(dev_info_t *dip, int level);
981 #endif
984 pci_post_suspend(dev_info_t *dip)
986 pci_pm_context_t *p;
987 uint16_t pmcap, pmcsr, pcicmd;
988 uint_t length;
989 int ret;
990 int fromprop = 1; /* source of memory *p */
991 ddi_acc_handle_t hdl;
993 PMD(PMD_SX, ("pci_post_suspend %s:%d\n",
994 ddi_driver_name(dip), ddi_get_instance(dip)))
996 if (pci_save_config_regs(dip) != DDI_SUCCESS) {
997 return (DDI_FAILURE);
1000 if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) {
1001 return (DDI_FAILURE);
1004 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
1005 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1006 SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) {
1007 p = (pci_pm_context_t *)kmem_zalloc(sizeof (*p), KM_SLEEP);
1008 fromprop = 0;
1009 if (pci_lookup_pmcap(dip, hdl,
1010 &p->ppc_cap_offset) != DDI_SUCCESS) {
1011 p->ppc_flags |= PPCF_NOPMCAP;
1012 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
1013 SAVED_PM_CONTEXT, (uchar_t *)p,
1014 sizeof (pci_pm_context_t));
1015 if (ret != DDI_PROP_SUCCESS) {
1016 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
1017 SAVED_PM_CONTEXT);
1018 ret = DDI_FAILURE;
1019 } else {
1020 ret = DDI_SUCCESS;
1022 goto done;
1025 * Upon suspend, set the power level to the lowest that can
1026 * wake the system. If none can, then set to lowest.
1027 * XXX later we will need to check policy to see if this
1028 * XXX device has had wakeup disabled
1030 pmcap = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCAP);
1031 if ((pmcap & (PCI_PMCAP_D3COLD_PME | PCI_PMCAP_D3HOT_PME)) != 0)
1032 p->ppc_suspend_level =
1033 (PCI_PMCSR_PME_EN | PCI_PMCSR_D3HOT);
1034 else if ((pmcap & PCI_PMCAP_D2_PME) != 0)
1035 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D2;
1036 else if ((pmcap & PCI_PMCAP_D1_PME) != 0)
1037 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D1;
1038 else if ((pmcap & PCI_PMCAP_D0_PME) != 0)
1039 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D0;
1040 else
1041 p->ppc_suspend_level = PCI_PMCSR_D3HOT;
1044 * we defer updating the property to catch the saved
1045 * register values as well
1048 /* If we set this in kmem_zalloc'd memory, we already returned above */
1049 if ((p->ppc_flags & PPCF_NOPMCAP) != 0) {
1050 goto done;
1053 pmcsr = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCSR);
1054 p->ppc_pmcsr = pmcsr;
1055 pmcsr &= (PCI_PMCSR_STATE_MASK);
1056 pmcsr |= (PCI_PMCSR_PME_STAT | p->ppc_suspend_level);
1059 * Push out saved register values
1061 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT,
1062 (uchar_t *)p, sizeof (pci_pm_context_t));
1063 if (ret == DDI_PROP_SUCCESS) {
1064 goto done;
1066 /* Failed; put things back the way we found them */
1067 (void) pci_restore_config_regs(dip);
1068 if (fromprop)
1069 ddi_prop_free(p);
1070 else
1071 kmem_free(p, sizeof (*p));
1072 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT);
1073 pci_config_teardown(&hdl);
1074 return (DDI_FAILURE);
1076 done:
1079 * According to 8.2.2 of "PCI Bus Power Management Interface
1080 * Specification Revision 1.2":
1081 * "When placing a function into D3, the operating system software is
1082 * required to disable I/O and memory space as well as bus mastering via
1083 * the PCI Command register."
1086 pcicmd = pci_config_get16(hdl, PCI_CONF_COMM);
1087 pcicmd &= ~(PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_IO);
1088 pci_config_put16(hdl, PCI_CONF_COMM, pcicmd);
1091 #if defined(__x86)
1092 if (pci_enable_wakeup &&
1093 (p->ppc_suspend_level & PCI_PMCSR_PME_EN) != 0) {
1094 ret = acpi_ddi_setwake(dip, 3);
1096 if (ret) {
1097 PMD(PMD_SX, ("pci_post_suspend, setwake %s@%s rets "
1098 "%x\n", PM_NAME(dip), PM_ADDR(dip), ret));
1101 #endif
1103 if (p) {
1106 * Some BIOS (e.g. Toshiba M10) expects pci-ide to be in D0
1107 * state when we set SLP_EN, otherwise it takes 5 minutes for
1108 * the BIOS to put the system into S3.
1110 if (strcmp(ddi_node_name(dip), "pci-ide") == 0) {
1111 pmcsr = 0;
1115 * pmcsr is the last write-operation to the device's PCI
1116 * config space, because we found that there are
1117 * some faulty devices whose PCI config space may not
1118 * respond correctly once in D3 state.
1120 if ((p->ppc_flags & PPCF_NOPMCAP) == 0 && pci_enable_wakeup) {
1121 pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR,
1122 PCI_PMCSR_PME_STAT);
1123 pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR,
1124 pmcsr);
1127 if (fromprop)
1128 ddi_prop_free(p);
1129 else
1130 kmem_free(p, sizeof (*p));
1133 pci_config_teardown(&hdl);
1135 return (DDI_SUCCESS);
1139 * The inverse of pci_post_suspend; handle pci-specific resume processing
1140 * First, turn device back on, then restore config space.
1144 pci_pre_resume(dev_info_t *dip)
1146 ddi_acc_handle_t hdl;
1147 pci_pm_context_t *p;
1148 /* E_FUNC_SET_NOT_USED */
1149 uint16_t pmcap, pmcsr;
1150 int flags;
1151 uint_t length;
1152 clock_t drv_usectohz(clock_t microsecs);
1154 PMD(PMD_SX, ("pci_pre_resume %s:%d\n", ddi_driver_name(dip),
1155 ddi_get_instance(dip)))
1156 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
1157 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1158 SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) {
1159 return (DDI_FAILURE);
1161 flags = p->ppc_flags;
1162 pmcap = p->ppc_cap_offset;
1163 pmcsr = p->ppc_pmcsr;
1165 #if defined(__x86)
1167 * Turn platform wake enable back off
1169 if (pci_enable_wakeup &&
1170 (p->ppc_suspend_level & PCI_PMCSR_PME_EN) != 0) {
1171 int retval;
1173 retval = acpi_ddi_setwake(dip, 0); /* 0 for now */
1174 if (retval) {
1175 PMD(PMD_SX, ("pci_pre_resume, setwake %s@%s rets "
1176 "%x\n", PM_NAME(dip), PM_ADDR(dip), retval));
1179 #endif
1181 ddi_prop_free(p);
1183 if ((flags & PPCF_NOPMCAP) != 0)
1184 goto done;
1186 if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) {
1187 return (DDI_FAILURE);
1189 pci_config_put16(hdl, pmcap + PCI_PMCSR, pmcsr);
1190 delay(drv_usectohz(10000)); /* PCI PM spec D3->D0 (10ms) */
1191 pci_config_teardown(&hdl);
1192 done:
1193 (void) pci_restore_config_regs(dip); /* fudges D-state! */
1194 return (DDI_SUCCESS);