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]
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>
30 #include <sys/pci_impl.h>
33 int pci_enable_wakeup
= 1;
36 pci_config_setup(dev_info_t
*dip
, ddi_acc_handle_t
*handle
)
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
));
55 pci_config_teardown(ddi_acc_handle_t
*handle
)
57 ddi_regs_map_free(handle
);
61 pci_config_get8(ddi_acc_handle_t handle
, off_t offset
)
66 hp
= impl_acc_hdl_get(handle
);
67 cfgaddr
= hp
->ah_addr
+ offset
;
68 return (ddi_get8(handle
, (uint8_t *)cfgaddr
));
72 pci_config_get16(ddi_acc_handle_t handle
, off_t offset
)
77 hp
= impl_acc_hdl_get(handle
);
78 cfgaddr
= hp
->ah_addr
+ offset
;
79 return (ddi_get16(handle
, (uint16_t *)cfgaddr
));
83 pci_config_get32(ddi_acc_handle_t handle
, off_t offset
)
88 hp
= impl_acc_hdl_get(handle
);
89 cfgaddr
= hp
->ah_addr
+ offset
;
90 return (ddi_get32(handle
, (uint32_t *)cfgaddr
));
94 pci_config_get64(ddi_acc_handle_t handle
, off_t offset
)
99 hp
= impl_acc_hdl_get(handle
);
100 cfgaddr
= hp
->ah_addr
+ offset
;
101 return (ddi_get64(handle
, (uint64_t *)cfgaddr
));
105 pci_config_put8(ddi_acc_handle_t handle
, off_t offset
, uint8_t value
)
110 hp
= impl_acc_hdl_get(handle
);
111 cfgaddr
= hp
->ah_addr
+ offset
;
112 ddi_put8(handle
, (uint8_t *)cfgaddr
, value
);
116 pci_config_put16(ddi_acc_handle_t handle
, off_t offset
, uint16_t value
)
121 hp
= impl_acc_hdl_get(handle
);
122 cfgaddr
= hp
->ah_addr
+ offset
;
123 ddi_put16(handle
, (uint16_t *)cfgaddr
, value
);
127 pci_config_put32(ddi_acc_handle_t handle
, off_t offset
, uint32_t value
)
132 hp
= impl_acc_hdl_get(handle
);
133 cfgaddr
= hp
->ah_addr
+ offset
;
134 ddi_put32(handle
, (uint32_t *)cfgaddr
, value
);
138 pci_config_put64(ddi_acc_handle_t handle
, off_t offset
, uint64_t value
)
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.
158 pci_config_getb(ddi_acc_handle_t handle
, off_t offset
)
163 hp
= impl_acc_hdl_get(handle
);
164 cfgaddr
= hp
->ah_addr
+ offset
;
165 return (ddi_get8(handle
, (uint8_t *)cfgaddr
));
169 pci_config_getw(ddi_acc_handle_t handle
, off_t offset
)
174 hp
= impl_acc_hdl_get(handle
);
175 cfgaddr
= hp
->ah_addr
+ offset
;
176 return (ddi_get16(handle
, (uint16_t *)cfgaddr
));
180 pci_config_getl(ddi_acc_handle_t handle
, off_t offset
)
185 hp
= impl_acc_hdl_get(handle
);
186 cfgaddr
= hp
->ah_addr
+ offset
;
187 return (ddi_get32(handle
, (uint32_t *)cfgaddr
));
191 pci_config_getll(ddi_acc_handle_t handle
, off_t offset
)
196 hp
= impl_acc_hdl_get(handle
);
197 cfgaddr
= hp
->ah_addr
+ offset
;
198 return (ddi_get64(handle
, (uint64_t *)cfgaddr
));
202 pci_config_putb(ddi_acc_handle_t handle
, off_t offset
, uint8_t value
)
207 hp
= impl_acc_hdl_get(handle
);
208 cfgaddr
= hp
->ah_addr
+ offset
;
209 ddi_put8(handle
, (uint8_t *)cfgaddr
, value
);
213 pci_config_putw(ddi_acc_handle_t handle
, off_t offset
, uint16_t value
)
218 hp
= impl_acc_hdl_get(handle
);
219 cfgaddr
= hp
->ah_addr
+ offset
;
220 ddi_put16(handle
, (uint16_t *)cfgaddr
, value
);
224 pci_config_putl(ddi_acc_handle_t handle
, off_t offset
, uint32_t value
)
229 hp
= impl_acc_hdl_get(handle
);
230 cfgaddr
= hp
->ah_addr
+ offset
;
231 ddi_put32(handle
, (uint32_t *)cfgaddr
, value
);
235 pci_config_putll(ddi_acc_handle_t handle
, off_t offset
, uint64_t value
)
240 hp
= impl_acc_hdl_get(handle
);
241 cfgaddr
= hp
->ah_addr
+ offset
;
242 ddi_put64(handle
, (uint64_t *)cfgaddr
, value
);
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
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
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
;
375 uint32_t i
, ncaps
, nwords
;
376 uint32_t *regbuf
, *p
;
378 size_t maskbufsz
, regbufsz
, capbufsz
;
379 ddi_device_acc_attr_t attr
;
382 uint8_t cap_ptr
, cap_id
;
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
)
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)) {
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
) {
425 cap_ptr
= pci_config_get8(confhdl
,
426 cap_ptr
+ PCI_CAP_NEXT_PTR
);
430 /* PCI express device. Can have data in all 4k space */
431 regbuf
= kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE
,
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)) >>
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
);
448 /* it is readable register. set the bit */
449 maskbuf
[i
>> INDEX_SHIFT
] |=
450 (uint8_t)(1 << (i
& BITMASK
));
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
),
473 kmem_free(maskbuf
, (size_t)maskbufsz
);
474 kmem_free(regbuf
, (size_t)PCIE_CONF_HDR_SIZE
);
476 regbuf
= kmem_zalloc((size_t)PCI_CONF_HDR_SIZE
,
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
,
483 if ((chsp
->chs_header_type
& PCI_HEADER_TYPE_M
) ==
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
) ==
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(
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
)) !=
522 cmn_err(CE_WARN
, "%s%d can't update prop %s",
523 ddi_driver_name(dip
), ddi_get_instance(dip
),
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
,
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.
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));
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
;
569 * Determine if it implements capabilities
571 status
= pci_config_get16(confhdl
, PCI_CONF_STAT
);
572 if (!(status
& 0x10)) {
573 return (words_saved
);
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 */
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
)
601 cap_ptr
= NEXT_CAP(confhdl
, cap_ptr
, xspace
);
603 * If this cap id is not found in the table, there is nothing
606 if (pci_cap_entp
->cap_id
== PCI_CAP_NEXT_PTR_NULL
)
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
;
616 words_saved
+= nwords
;
622 return (words_saved
);
626 pci_fill_buf(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
,
627 uint32_t *regbuf
, uint32_t nwords
)
631 for (i
= 0; i
< nwords
; i
++) {
632 *regbuf
= pci_config_get32(confhdl
, cap_ptr
);
639 pci_generic_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
642 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
648 pci_msi_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
651 uint32_t nwords
= PCI_MSI_MIN_WORDS
;
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
)
659 /* If per vector masking capable, add two more words */
660 if (msi_ctrl
& PCI_MSI_PVM_MASK
)
662 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
669 pci_pcix_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
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
))
681 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
688 pci_pcie_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
696 pci_ht_addrmap_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
,
697 uint32_t *regbuf
, uint32_t notused
)
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);
710 case PCI_HTCAP_ADDRMAP_64BIT_ID
:
711 /* HT3.1 spec, ch 7.8, 64-bit dma */
718 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
724 pci_ht_funcext_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
,
725 uint32_t *regbuf
, uint32_t notused
)
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
);
740 pci_pmcap_check(ddi_acc_handle_t confhdl
, uint32_t *regbuf
,
741 uint16_t pmcap_offset
)
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
);
758 pci_restore_caps(ddi_acc_handle_t confhdl
, uint32_t *regbuf
,
759 pci_cap_save_desc_t
*cap_descp
, uint32_t elements
)
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
);
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
;
788 uint32_t *regbuf
, *p
;
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
**)®buf
, &elements
) != DDI_PROP_SUCCESS
) {
804 goto restoreconfig_err
;
806 ASSERT(elements
== PCIE_CONF_HDR_SIZE
);
807 /* pcie device and has 4k config space saved */
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
);
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
);
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
**)®buf
, &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
,
837 if ((chs_p
->chs_header_type
& PCI_HEADER_TYPE_M
) ==
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
) ==
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
) !=
883 cmn_err(CE_WARN
, "%s%d can't remove prop %s",
884 ddi_driver_name(dip
), ddi_get_instance(dip
),
888 pci_config_teardown(&confhdl
);
890 return (DDI_SUCCESS
);
893 ddi_prop_free(maskbuf
);
894 if (ndi_prop_remove(DDI_DEV_T_NONE
, dip
, SAVED_CONFIG_REGS_MASK
) !=
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
);
906 pci_lookup_pmcap(dev_info_t
*dip
, ddi_acc_handle_t conf_hdl
,
907 uint16_t *pmcap_offsetp
)
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
) {
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
{
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
;
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
980 extern int acpi_ddi_setwake(dev_info_t
*dip
, int level
);
984 pci_post_suspend(dev_info_t
*dip
)
987 uint16_t pmcap
, pmcsr
, pcicmd
;
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
);
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
,
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
;
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) {
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
) {
1066 /* Failed; put things back the way we found them */
1067 (void) pci_restore_config_regs(dip
);
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
);
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
);
1092 if (pci_enable_wakeup
&&
1093 (p
->ppc_suspend_level
& PCI_PMCSR_PME_EN
) != 0) {
1094 ret
= acpi_ddi_setwake(dip
, 3);
1097 PMD(PMD_SX
, ("pci_post_suspend, setwake %s@%s rets "
1098 "%x\n", PM_NAME(dip
), PM_ADDR(dip
), ret
));
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) {
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
,
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
;
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
;
1167 * Turn platform wake enable back off
1169 if (pci_enable_wakeup
&&
1170 (p
->ppc_suspend_level
& PCI_PMCSR_PME_EN
) != 0) {
1173 retval
= acpi_ddi_setwake(dip
, 0); /* 0 for now */
1175 PMD(PMD_SX
, ("pci_pre_resume, setwake %s@%s rets "
1176 "%x\n", PM_NAME(dip
), PM_ADDR(dip
), retval
));
1183 if ((flags
& PPCF_NOPMCAP
) != 0)
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
);
1193 (void) pci_restore_config_regs(dip
); /* fudges D-state! */
1194 return (DDI_SUCCESS
);