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
;
382 ddi_device_acc_attr_t attr
;
386 uint8_t cap_ptr
, cap_id
;
390 PMD(PMD_SX
, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip
),
391 ddi_get_instance(dip
)))
394 if (pci_config_setup(dip
, &confhdl
) != DDI_SUCCESS
) {
395 cmn_err(CE_WARN
, "%s%d can't get config handle",
396 ddi_driver_name(dip
), ddi_get_instance(dip
));
398 return (DDI_FAILURE
);
401 /* Set up cautious config access handle */
402 attr
.devacc_attr_version
= DDI_DEVICE_ATTR_V1
;
403 attr
.devacc_attr_endian_flags
= DDI_STRUCTURE_LE_ACC
;
404 attr
.devacc_attr_dataorder
= DDI_STRICTORDER_ACC
;
405 attr
.devacc_attr_access
= DDI_CAUTIOUS_ACC
;
406 if (ddi_regs_map_setup(dip
, 0, &cfgaddr
, 0, 0, &attr
, &confhdl
)
408 cmn_err(CE_WARN
, "%s%d can't setup cautious config handle",
409 ddi_driver_name(dip
), ddi_get_instance(dip
));
411 return (DDI_FAILURE
);
416 * Determine if it implements capabilities
418 status
= pci_config_get16(confhdl
, PCI_CONF_STAT
);
419 if (!(status
& 0x10)) {
423 * Determine if it is a pci express device. If it is, save entire
424 * 4k config space treating it as a array of 32 bit integers.
425 * If it is not, do it in a usual PCI way.
427 cap_ptr
= pci_config_get8(confhdl
, PCI_BCNF_CAP_PTR
);
429 * Walk the capabilities searching for pci express capability
431 while (cap_ptr
!= PCI_CAP_NEXT_PTR_NULL
) {
432 cap_id
= pci_config_get8(confhdl
,
433 cap_ptr
+ PCI_CAP_ID
);
434 if (cap_id
== PCI_CAP_ID_PCI_E
) {
438 cap_ptr
= pci_config_get8(confhdl
,
439 cap_ptr
+ PCI_CAP_NEXT_PTR
);
443 /* PCI express device. Can have data in all 4k space */
444 regbuf
= kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE
,
448 * Allocate space for mask.
449 * mask size is 128 bytes (4096 / 4 / 8 )
451 maskbufsz
= (size_t)((PCIE_CONF_HDR_SIZE
/ sizeof (uint32_t)) >>
453 maskbuf
= kmem_zalloc(maskbufsz
, KM_SLEEP
);
455 hp
= impl_acc_hdl_get(confhdl
);
457 for (i
= 0; i
< (PCIE_CONF_HDR_SIZE
/ sizeof (uint32_t)); i
++) {
459 ret
= ddi_peek32(dip
, (int32_t *)(hp
->ah_addr
+ offset
),
461 if (ret
== DDI_SUCCESS
) {
464 * ddi_peek doesn't work on x86, so we use cautious pci
465 * config access instead.
467 *p
= pci_config_get32(confhdl
, offset
);
470 /* it is readable register. set the bit */
471 maskbuf
[i
>> INDEX_SHIFT
] |=
472 (uint8_t)(1 << (i
& BITMASK
));
475 offset
+= sizeof (uint32_t);
478 if ((ret
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
,
479 SAVED_CONFIG_REGS_MASK
, (uchar_t
*)maskbuf
,
480 maskbufsz
)) != DDI_PROP_SUCCESS
) {
481 cmn_err(CE_WARN
, "couldn't create %s property while"
482 "saving config space for %s@%d\n",
483 SAVED_CONFIG_REGS_MASK
, ddi_driver_name(dip
),
484 ddi_get_instance(dip
));
485 } else if ((ret
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
,
486 dip
, SAVED_CONFIG_REGS
, (uchar_t
*)regbuf
,
487 (size_t)PCIE_CONF_HDR_SIZE
)) != DDI_PROP_SUCCESS
) {
488 (void) ddi_prop_remove(DDI_DEV_T_NONE
, dip
,
489 SAVED_CONFIG_REGS_MASK
);
490 cmn_err(CE_WARN
, "%s%d can't update prop %s",
491 ddi_driver_name(dip
), ddi_get_instance(dip
),
495 kmem_free(maskbuf
, (size_t)maskbufsz
);
496 kmem_free(regbuf
, (size_t)PCIE_CONF_HDR_SIZE
);
498 regbuf
= kmem_zalloc((size_t)PCI_CONF_HDR_SIZE
,
500 chsp
= (pci_config_header_state_t
*)regbuf
;
502 chsp
->chs_command
= pci_config_get16(confhdl
, PCI_CONF_COMM
);
503 chsp
->chs_header_type
= pci_config_get8(confhdl
,
505 if ((chsp
->chs_header_type
& PCI_HEADER_TYPE_M
) ==
507 chsp
->chs_bridge_control
=
508 pci_config_get16(confhdl
, PCI_BCNF_BCNTRL
);
509 chsp
->chs_cache_line_size
= pci_config_get8(confhdl
,
510 PCI_CONF_CACHE_LINESZ
);
511 chsp
->chs_latency_timer
= pci_config_get8(confhdl
,
512 PCI_CONF_LATENCY_TIMER
);
513 if ((chsp
->chs_header_type
& PCI_HEADER_TYPE_M
) ==
515 chsp
->chs_sec_latency_timer
=
516 pci_config_get8(confhdl
, PCI_BCNF_LATENCY_TIMER
);
519 chsp
->chs_base0
= pci_config_get32(confhdl
, PCI_CONF_BASE0
);
520 chsp
->chs_base1
= pci_config_get32(confhdl
, PCI_CONF_BASE1
);
521 chsp
->chs_base2
= pci_config_get32(confhdl
, PCI_CONF_BASE2
);
522 chsp
->chs_base3
= pci_config_get32(confhdl
, PCI_CONF_BASE3
);
523 chsp
->chs_base4
= pci_config_get32(confhdl
, PCI_CONF_BASE4
);
524 chsp
->chs_base5
= pci_config_get32(confhdl
, PCI_CONF_BASE5
);
527 * Allocate maximum space required for capability descriptions.
528 * The maximum number of capabilties saved is the number of
529 * capabilities listed in the pci_cap_table.
531 ncaps
= (sizeof (pci_cap_table
) / sizeof (pci_cap_entry_t
));
532 capbufsz
= ncaps
* sizeof (pci_cap_save_desc_t
);
533 pci_cap_descp
= (pci_cap_save_desc_t
*)kmem_zalloc(
535 p
= (uint32_t *)((caddr_t
)regbuf
+
536 sizeof (pci_config_header_state_t
));
537 nwords
= pci_save_caps(confhdl
, p
, pci_cap_descp
, &ncaps
);
538 regbufsz
= sizeof (pci_config_header_state_t
) +
539 nwords
* sizeof (uint32_t);
541 if ((ret
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
,
542 SAVED_CONFIG_REGS
, (uchar_t
*)regbuf
, regbufsz
)) !=
544 cmn_err(CE_WARN
, "%s%d can't update prop %s",
545 ddi_driver_name(dip
), ddi_get_instance(dip
),
548 ret
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
,
549 SAVED_CONFIG_REGS_CAPINFO
, (uchar_t
*)pci_cap_descp
,
550 ncaps
* sizeof (pci_cap_save_desc_t
));
551 if (ret
!= DDI_PROP_SUCCESS
)
552 (void) ddi_prop_remove(DDI_DEV_T_NONE
, dip
,
555 kmem_free(regbuf
, (size_t)PCI_CONF_HDR_SIZE
);
556 kmem_free(pci_cap_descp
, capbufsz
);
558 pci_config_teardown(&confhdl
);
560 if (ret
!= DDI_PROP_SUCCESS
)
561 return (DDI_FAILURE
);
563 return (DDI_SUCCESS
);
567 * Saves registers associated with PCI capabilities.
568 * Returns number of 32 bit words saved.
569 * Number of capabilities saved is returned in ncapsp.
572 pci_save_caps(ddi_acc_handle_t confhdl
, uint32_t *regbuf
,
573 pci_cap_save_desc_t
*cap_descp
, uint32_t *ncapsp
)
575 return (cap_walk_and_save(confhdl
, regbuf
, cap_descp
, ncapsp
, 0));
579 cap_walk_and_save(ddi_acc_handle_t confhdl
, uint32_t *regbuf
,
580 pci_cap_save_desc_t
*cap_descp
, uint32_t *ncapsp
, int xspace
)
582 pci_cap_entry_t
*pci_cap_entp
;
583 uint16_t cap_id
, offset
, status
;
584 uint32_t words_saved
= 0, nwords
= 0;
585 uint16_t cap_ptr
= PCI_CAP_NEXT_PTR_NULL
;
591 * Determine if it implements capabilities
593 status
= pci_config_get16(confhdl
, PCI_CONF_STAT
);
594 if (!(status
& 0x10)) {
595 return (words_saved
);
599 cap_ptr
= pci_config_get8(confhdl
, PCI_BCNF_CAP_PTR
);
601 * Walk the capabilities
603 while (cap_ptr
!= PCI_CAP_NEXT_PTR_NULL
) {
604 cap_id
= CAP_ID(confhdl
, cap_ptr
, xspace
);
606 /* Search for this cap id in our table */
608 pci_cap_entp
= pci_cap_table
;
609 cap_reg
= pci_config_get16(confhdl
,
610 cap_ptr
+ PCI_CAP_ID_REGS_OFF
);
613 while (pci_cap_entp
->cap_id
!= PCI_CAP_NEXT_PTR_NULL
) {
614 if (pci_cap_entp
->cap_id
== cap_id
&&
615 (cap_reg
& pci_cap_entp
->cap_mask
) ==
616 pci_cap_entp
->cap_reg
)
623 cap_ptr
= NEXT_CAP(confhdl
, cap_ptr
, xspace
);
625 * If this cap id is not found in the table, there is nothing
628 if (pci_cap_entp
->cap_id
== PCI_CAP_NEXT_PTR_NULL
)
630 if (pci_cap_entp
->cap_save_func
) {
631 if ((nwords
= pci_cap_entp
->cap_save_func(confhdl
,
632 offset
, regbuf
, pci_cap_entp
->cap_ndwords
))) {
633 cap_descp
->cap_nregs
= nwords
;
634 cap_descp
->cap_offset
= offset
;
635 cap_descp
->cap_id
= cap_id
;
638 words_saved
+= nwords
;
644 return (words_saved
);
648 pci_fill_buf(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
,
649 uint32_t *regbuf
, uint32_t nwords
)
653 for (i
= 0; i
< nwords
; i
++) {
654 *regbuf
= pci_config_get32(confhdl
, cap_ptr
);
661 pci_generic_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
664 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
670 pci_msi_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
673 uint32_t nwords
= PCI_MSI_MIN_WORDS
;
676 /* Figure out how many registers to be saved */
677 msi_ctrl
= pci_config_get16(confhdl
, cap_ptr
+ PCI_MSI_CTRL
);
678 /* If 64 bit address capable add one word */
679 if (msi_ctrl
& PCI_MSI_64BIT_MASK
)
681 /* If per vector masking capable, add two more words */
682 if (msi_ctrl
& PCI_MSI_PVM_MASK
)
684 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
691 pci_pcix_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
694 uint32_t nwords
= PCI_PCIX_MIN_WORDS
;
695 uint16_t pcix_command
;
697 /* Figure out how many registers to be saved */
698 pcix_command
= pci_config_get16(confhdl
, cap_ptr
+ PCI_PCIX_COMMAND
);
699 /* If it is version 1 or version 2, add 4 words */
700 if (((pcix_command
& PCI_PCIX_VER_MASK
) == PCI_PCIX_VER_1
) ||
701 ((pcix_command
& PCI_PCIX_VER_MASK
) == PCI_PCIX_VER_2
))
703 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
710 pci_pcie_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
, uint32_t *regbuf
,
718 pci_ht_addrmap_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
,
719 uint32_t *regbuf
, uint32_t notused
)
724 reg
= pci_config_get16(confhdl
, cap_ptr
+ PCI_CAP_ID_REGS_OFF
);
726 switch ((reg
& PCI_HTCAP_ADDRMAP_MAPTYPE_MASK
) >>
727 PCI_HTCAP_ADDRMAP_MAPTYPE_SHIFT
) {
728 case PCI_HTCAP_ADDRMAP_40BIT_ID
:
729 /* HT3.1 spec, ch 7.7, 40-bit dma */
730 nwords
= 3 + ((reg
& PCI_HTCAP_ADDRMAP_NUMMAP_MASK
) * 2);
732 case PCI_HTCAP_ADDRMAP_64BIT_ID
:
733 /* HT3.1 spec, ch 7.8, 64-bit dma */
740 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
746 pci_ht_funcext_save(ddi_acc_handle_t confhdl
, uint16_t cap_ptr
,
747 uint32_t *regbuf
, uint32_t notused
)
752 reg
= pci_config_get16(confhdl
, cap_ptr
+ PCI_CAP_ID_REGS_OFF
);
754 /* HT3.1 spec, ch 7.17 */
755 nwords
= 1 + (reg
& PCI_HTCAP_FUNCEXT_LEN_MASK
);
757 pci_fill_buf(confhdl
, cap_ptr
, regbuf
, nwords
);
762 pci_pmcap_check(ddi_acc_handle_t confhdl
, uint32_t *regbuf
,
763 uint16_t pmcap_offset
)
766 uint16_t pmcsr_offset
= pmcap_offset
+ PCI_PMCSR
;
767 uint32_t *saved_pmcsrp
= (uint32_t *)((caddr_t
)regbuf
+ PCI_PMCSR
);
770 * Copy the power state bits from the PMCSR to our saved copy.
771 * This is to make sure that we don't change the D state when
772 * we restore config space of the device.
774 pmcsr
= pci_config_get16(confhdl
, pmcsr_offset
);
775 (*saved_pmcsrp
) &= ~PCI_PMCSR_STATE_MASK
;
776 (*saved_pmcsrp
) |= (pmcsr
& PCI_PMCSR_STATE_MASK
);
780 pci_restore_caps(ddi_acc_handle_t confhdl
, uint32_t *regbuf
,
781 pci_cap_save_desc_t
*cap_descp
, uint32_t elements
)
786 for (i
= 0; i
< (elements
/ sizeof (pci_cap_save_desc_t
)); i
++) {
787 offset
= cap_descp
->cap_offset
;
788 if (cap_descp
->cap_id
== PCI_CAP_ID_PM
)
789 pci_pmcap_check(confhdl
, regbuf
, offset
);
790 for (j
= 0; j
< cap_descp
->cap_nregs
; j
++) {
791 pci_config_put32(confhdl
, offset
, *regbuf
);
800 * Restore config_regs from a single devinfo node.
803 pci_restore_config_regs(dev_info_t
*dip
)
805 ddi_acc_handle_t confhdl
;
806 pci_config_header_state_t
*chs_p
;
807 pci_cap_save_desc_t
*cap_descp
;
808 uint32_t elements
, i
;
810 uint32_t *regbuf
, *p
;
813 if (pci_config_setup(dip
, &confhdl
) != DDI_SUCCESS
) {
814 cmn_err(CE_WARN
, "%s%d can't get config handle",
815 ddi_driver_name(dip
), ddi_get_instance(dip
));
816 return (DDI_FAILURE
);
819 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
820 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
, SAVED_CONFIG_REGS_MASK
,
821 (uchar_t
**)&maskbuf
, &elements
) == DDI_PROP_SUCCESS
) {
823 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
824 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
, SAVED_CONFIG_REGS
,
825 (uchar_t
**)®buf
, &elements
) != DDI_PROP_SUCCESS
) {
826 goto restoreconfig_err
;
828 ASSERT(elements
== PCIE_CONF_HDR_SIZE
);
829 /* pcie device and has 4k config space saved */
831 for (i
= 0; i
< PCIE_CONF_HDR_SIZE
/ sizeof (uint32_t); i
++) {
832 /* If the word is readable then restore it */
833 if (maskbuf
[i
>> INDEX_SHIFT
] &
834 (uint8_t)(1 << (i
& BITMASK
)))
835 pci_config_put32(confhdl
, offset
, *p
);
837 offset
+= sizeof (uint32_t);
839 ddi_prop_free(regbuf
);
840 ddi_prop_free(maskbuf
);
841 if (ndi_prop_remove(DDI_DEV_T_NONE
, dip
,
842 SAVED_CONFIG_REGS_MASK
) != DDI_PROP_SUCCESS
) {
843 cmn_err(CE_WARN
, "%s%d can't remove prop %s",
844 ddi_driver_name(dip
), ddi_get_instance(dip
),
845 SAVED_CONFIG_REGS_MASK
);
848 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
849 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
, SAVED_CONFIG_REGS
,
850 (uchar_t
**)®buf
, &elements
) != DDI_PROP_SUCCESS
) {
852 pci_config_teardown(&confhdl
);
853 return (DDI_SUCCESS
);
856 chs_p
= (pci_config_header_state_t
*)regbuf
;
857 pci_config_put16(confhdl
, PCI_CONF_COMM
,
859 if ((chs_p
->chs_header_type
& PCI_HEADER_TYPE_M
) ==
861 pci_config_put16(confhdl
, PCI_BCNF_BCNTRL
,
862 chs_p
->chs_bridge_control
);
864 pci_config_put8(confhdl
, PCI_CONF_CACHE_LINESZ
,
865 chs_p
->chs_cache_line_size
);
866 pci_config_put8(confhdl
, PCI_CONF_LATENCY_TIMER
,
867 chs_p
->chs_latency_timer
);
868 if ((chs_p
->chs_header_type
& PCI_HEADER_TYPE_M
) ==
870 pci_config_put8(confhdl
, PCI_BCNF_LATENCY_TIMER
,
871 chs_p
->chs_sec_latency_timer
);
873 pci_config_put32(confhdl
, PCI_CONF_BASE0
, chs_p
->chs_base0
);
874 pci_config_put32(confhdl
, PCI_CONF_BASE1
, chs_p
->chs_base1
);
875 pci_config_put32(confhdl
, PCI_CONF_BASE2
, chs_p
->chs_base2
);
876 pci_config_put32(confhdl
, PCI_CONF_BASE3
, chs_p
->chs_base3
);
877 pci_config_put32(confhdl
, PCI_CONF_BASE4
, chs_p
->chs_base4
);
878 pci_config_put32(confhdl
, PCI_CONF_BASE5
, chs_p
->chs_base5
);
880 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
881 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
,
882 SAVED_CONFIG_REGS_CAPINFO
,
883 (uchar_t
**)&cap_descp
, &elements
) == DDI_PROP_SUCCESS
) {
885 * PCI capability related regsiters are saved.
886 * Restore them based on the description.
888 p
= (uint32_t *)((caddr_t
)regbuf
+
889 sizeof (pci_config_header_state_t
));
890 pci_restore_caps(confhdl
, p
, cap_descp
, elements
);
891 ddi_prop_free(cap_descp
);
894 ddi_prop_free(regbuf
);
898 * Make sure registers are flushed
900 (void) pci_config_get32(confhdl
, PCI_CONF_BASE5
);
903 if (ndi_prop_remove(DDI_DEV_T_NONE
, dip
, SAVED_CONFIG_REGS
) !=
905 cmn_err(CE_WARN
, "%s%d can't remove prop %s",
906 ddi_driver_name(dip
), ddi_get_instance(dip
),
910 pci_config_teardown(&confhdl
);
912 return (DDI_SUCCESS
);
915 ddi_prop_free(maskbuf
);
916 if (ndi_prop_remove(DDI_DEV_T_NONE
, dip
, SAVED_CONFIG_REGS_MASK
) !=
918 cmn_err(CE_WARN
, "%s%d can't remove prop %s",
919 ddi_driver_name(dip
), ddi_get_instance(dip
),
920 SAVED_CONFIG_REGS_MASK
);
922 pci_config_teardown(&confhdl
);
923 return (DDI_FAILURE
);
928 pci_lookup_pmcap(dev_info_t
*dip
, ddi_acc_handle_t conf_hdl
,
929 uint16_t *pmcap_offsetp
)
936 header_type
= pci_config_get8(conf_hdl
, PCI_CONF_HEADER
);
937 header_type
&= PCI_HEADER_TYPE_M
;
939 /* we don't deal with bridges, etc here */
940 if (header_type
!= PCI_HEADER_ZERO
) {
941 return (DDI_FAILURE
);
944 status
= pci_config_get16(conf_hdl
, PCI_CONF_STAT
);
945 if ((status
& PCI_STAT_CAP
) == 0) {
946 return (DDI_FAILURE
);
949 cap_ptr
= pci_config_get8(conf_hdl
, PCI_CONF_CAP_PTR
);
952 * Walk the capabilities searching for a PM entry.
954 while (cap_ptr
!= PCI_CAP_NEXT_PTR_NULL
) {
955 cap_id
= pci_config_get8(conf_hdl
, cap_ptr
+ PCI_CAP_ID
);
956 if (cap_id
== PCI_CAP_ID_PM
) {
959 cap_ptr
= pci_config_get8(conf_hdl
,
960 cap_ptr
+ PCI_CAP_NEXT_PTR
);
963 if (cap_ptr
== PCI_CAP_NEXT_PTR_NULL
) {
964 return (DDI_FAILURE
);
966 *pmcap_offsetp
= cap_ptr
;
967 return (DDI_SUCCESS
);
971 * Do common pci-specific suspend actions:
972 * - enable wakeup if appropriate for the device
973 * - put device in lowest D-state that supports wakeup, or D3 if none
974 * - turn off bus mastering in control register
975 * For lack of per-dip storage (parent private date is pretty busy)
976 * we use properties to store the necessary context
977 * To avoid grotting through pci config space on every suspend,
978 * we leave the prop in existence after resume, cause we know that
979 * the detach framework code will dispose of it for us.
982 typedef struct pci_pm_context
{
984 uint16_t ppc_cap_offset
; /* offset in config space to pm cap */
985 uint16_t ppc_pmcsr
; /* need this too */
986 uint16_t ppc_suspend_level
;
989 #define SAVED_PM_CONTEXT "pci-pm-context"
991 /* values for ppc_flags */
992 #define PPCF_NOPMCAP 1
995 * Handle pci-specific suspend processing
996 * PM CSR and PCI CMD are saved by pci_save_config_regs().
997 * If device can wake up system via PME, enable it to do so
998 * Set device power level to lowest that can generate PME, or D3 if none can
999 * Turn off bus master enable in pci command register
1002 extern int acpi_ddi_setwake(dev_info_t
*dip
, int level
);
1006 pci_post_suspend(dev_info_t
*dip
)
1008 pci_pm_context_t
*p
;
1009 uint16_t pmcap
, pmcsr
, pcicmd
;
1012 int fromprop
= 1; /* source of memory *p */
1013 ddi_acc_handle_t hdl
;
1015 PMD(PMD_SX
, ("pci_post_suspend %s:%d\n",
1016 ddi_driver_name(dip
), ddi_get_instance(dip
)))
1018 if (pci_save_config_regs(dip
) != DDI_SUCCESS
) {
1019 return (DDI_FAILURE
);
1022 if (pci_config_setup(dip
, &hdl
) != DDI_SUCCESS
) {
1023 return (DDI_FAILURE
);
1026 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
1027 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
,
1028 SAVED_PM_CONTEXT
, (uchar_t
**)&p
, &length
) != DDI_PROP_SUCCESS
) {
1029 p
= (pci_pm_context_t
*)kmem_zalloc(sizeof (*p
), KM_SLEEP
);
1031 if (pci_lookup_pmcap(dip
, hdl
,
1032 &p
->ppc_cap_offset
) != DDI_SUCCESS
) {
1033 p
->ppc_flags
|= PPCF_NOPMCAP
;
1034 ret
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
,
1035 SAVED_PM_CONTEXT
, (uchar_t
*)p
,
1036 sizeof (pci_pm_context_t
));
1037 if (ret
!= DDI_PROP_SUCCESS
) {
1038 (void) ddi_prop_remove(DDI_DEV_T_NONE
, dip
,
1047 * Upon suspend, set the power level to the lowest that can
1048 * wake the system. If none can, then set to lowest.
1049 * XXX later we will need to check policy to see if this
1050 * XXX device has had wakeup disabled
1052 pmcap
= pci_config_get16(hdl
, p
->ppc_cap_offset
+ PCI_PMCAP
);
1053 if ((pmcap
& (PCI_PMCAP_D3COLD_PME
| PCI_PMCAP_D3HOT_PME
)) != 0)
1054 p
->ppc_suspend_level
=
1055 (PCI_PMCSR_PME_EN
| PCI_PMCSR_D3HOT
);
1056 else if ((pmcap
& PCI_PMCAP_D2_PME
) != 0)
1057 p
->ppc_suspend_level
= PCI_PMCSR_PME_EN
| PCI_PMCSR_D2
;
1058 else if ((pmcap
& PCI_PMCAP_D1_PME
) != 0)
1059 p
->ppc_suspend_level
= PCI_PMCSR_PME_EN
| PCI_PMCSR_D1
;
1060 else if ((pmcap
& PCI_PMCAP_D0_PME
) != 0)
1061 p
->ppc_suspend_level
= PCI_PMCSR_PME_EN
| PCI_PMCSR_D0
;
1063 p
->ppc_suspend_level
= PCI_PMCSR_D3HOT
;
1066 * we defer updating the property to catch the saved
1067 * register values as well
1070 /* If we set this in kmem_zalloc'd memory, we already returned above */
1071 if ((p
->ppc_flags
& PPCF_NOPMCAP
) != 0) {
1075 pmcsr
= pci_config_get16(hdl
, p
->ppc_cap_offset
+ PCI_PMCSR
);
1076 p
->ppc_pmcsr
= pmcsr
;
1077 pmcsr
&= (PCI_PMCSR_STATE_MASK
);
1078 pmcsr
|= (PCI_PMCSR_PME_STAT
| p
->ppc_suspend_level
);
1081 * Push out saved register values
1083 ret
= ndi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
, SAVED_PM_CONTEXT
,
1084 (uchar_t
*)p
, sizeof (pci_pm_context_t
));
1085 if (ret
== DDI_PROP_SUCCESS
) {
1088 /* Failed; put things back the way we found them */
1089 (void) pci_restore_config_regs(dip
);
1093 kmem_free(p
, sizeof (*p
));
1094 (void) ddi_prop_remove(DDI_DEV_T_NONE
, dip
, SAVED_PM_CONTEXT
);
1095 pci_config_teardown(&hdl
);
1096 return (DDI_FAILURE
);
1101 * According to 8.2.2 of "PCI Bus Power Management Interface
1102 * Specification Revision 1.2":
1103 * "When placing a function into D3, the operating system software is
1104 * required to disable I/O and memory space as well as bus mastering via
1105 * the PCI Command register."
1108 pcicmd
= pci_config_get16(hdl
, PCI_CONF_COMM
);
1109 pcicmd
&= ~(PCI_COMM_ME
|PCI_COMM_MAE
|PCI_COMM_IO
);
1110 pci_config_put16(hdl
, PCI_CONF_COMM
, pcicmd
);
1114 if (pci_enable_wakeup
&&
1115 (p
->ppc_suspend_level
& PCI_PMCSR_PME_EN
) != 0) {
1116 ret
= acpi_ddi_setwake(dip
, 3);
1119 PMD(PMD_SX
, ("pci_post_suspend, setwake %s@%s rets "
1120 "%x\n", PM_NAME(dip
), PM_ADDR(dip
), ret
));
1128 * Some BIOS (e.g. Toshiba M10) expects pci-ide to be in D0
1129 * state when we set SLP_EN, otherwise it takes 5 minutes for
1130 * the BIOS to put the system into S3.
1132 if (strcmp(ddi_node_name(dip
), "pci-ide") == 0) {
1137 * pmcsr is the last write-operation to the device's PCI
1138 * config space, because we found that there are
1139 * some faulty devices whose PCI config space may not
1140 * respond correctly once in D3 state.
1142 if ((p
->ppc_flags
& PPCF_NOPMCAP
) == 0 && pci_enable_wakeup
) {
1143 pci_config_put16(hdl
, p
->ppc_cap_offset
+ PCI_PMCSR
,
1144 PCI_PMCSR_PME_STAT
);
1145 pci_config_put16(hdl
, p
->ppc_cap_offset
+ PCI_PMCSR
,
1152 kmem_free(p
, sizeof (*p
));
1155 pci_config_teardown(&hdl
);
1157 return (DDI_SUCCESS
);
1161 * The inverse of pci_post_suspend; handle pci-specific resume processing
1162 * First, turn device back on, then restore config space.
1166 pci_pre_resume(dev_info_t
*dip
)
1168 ddi_acc_handle_t hdl
;
1169 pci_pm_context_t
*p
;
1170 /* E_FUNC_SET_NOT_USED */
1171 uint16_t pmcap
, pmcsr
;
1174 clock_t drv_usectohz(clock_t microsecs
);
1176 PMD(PMD_SX
, ("pci_pre_resume %s:%d\n", ddi_driver_name(dip
),
1177 ddi_get_instance(dip
)))
1178 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY
, dip
,
1179 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
,
1180 SAVED_PM_CONTEXT
, (uchar_t
**)&p
, &length
) != DDI_PROP_SUCCESS
) {
1181 return (DDI_FAILURE
);
1183 flags
= p
->ppc_flags
;
1184 pmcap
= p
->ppc_cap_offset
;
1185 pmcsr
= p
->ppc_pmcsr
;
1189 * Turn platform wake enable back off
1191 if (pci_enable_wakeup
&&
1192 (p
->ppc_suspend_level
& PCI_PMCSR_PME_EN
) != 0) {
1195 retval
= acpi_ddi_setwake(dip
, 0); /* 0 for now */
1197 PMD(PMD_SX
, ("pci_pre_resume, setwake %s@%s rets "
1198 "%x\n", PM_NAME(dip
), PM_ADDR(dip
), retval
));
1205 if ((flags
& PPCF_NOPMCAP
) != 0)
1208 if (pci_config_setup(dip
, &hdl
) != DDI_SUCCESS
) {
1209 return (DDI_FAILURE
);
1211 pci_config_put16(hdl
, pmcap
+ PCI_PMCSR
, pmcsr
);
1212 delay(drv_usectohz(10000)); /* PCI PM spec D3->D0 (10ms) */
1213 pci_config_teardown(&hdl
);
1215 (void) pci_restore_config_regs(dip
); /* fudges D-state! */
1216 return (DDI_SUCCESS
);