1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/sunndi.h> 29 #include <sys/sysmacros.h> 30 #include <sys/pci.h> 31 #include <sys/pcie.h> 32 #include <sys/pci_impl.h> 33 #include <sys/epm.h> 34 35 int 36 pci_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle) 37 { 38 caddr_t cfgaddr; 39 ddi_device_acc_attr_t attr; 40 41 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 42 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 43 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 44 45 /* Check for fault management capabilities */ 46 if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(dip))) { 47 attr.devacc_attr_version = DDI_DEVICE_ATTR_V1; 48 attr.devacc_attr_access = DDI_FLAGERR_ACC; 49 } 50 51 return (ddi_regs_map_setup(dip, 0, &cfgaddr, 0, 0, &attr, handle)); 52 } 53 54 void 55 pci_config_teardown(ddi_acc_handle_t *handle) 56 { 57 ddi_regs_map_free(handle); 58 } 59 60 uint8_t 61 pci_config_get8(ddi_acc_handle_t handle, off_t offset) 62 { 63 caddr_t cfgaddr; 64 ddi_acc_hdl_t *hp; 65 66 hp = impl_acc_hdl_get(handle); 67 cfgaddr = hp->ah_addr + offset; 68 return (ddi_get8(handle, (uint8_t *)cfgaddr)); 69 } 70 71 uint16_t 72 pci_config_get16(ddi_acc_handle_t handle, off_t offset) 73 { 74 caddr_t cfgaddr; 75 ddi_acc_hdl_t *hp; 76 77 hp = impl_acc_hdl_get(handle); 78 cfgaddr = hp->ah_addr + offset; 79 return (ddi_get16(handle, (uint16_t *)cfgaddr)); 80 } 81 82 uint32_t 83 pci_config_get32(ddi_acc_handle_t handle, off_t offset) 84 { 85 caddr_t cfgaddr; 86 ddi_acc_hdl_t *hp; 87 88 hp = impl_acc_hdl_get(handle); 89 cfgaddr = hp->ah_addr + offset; 90 return (ddi_get32(handle, (uint32_t *)cfgaddr)); 91 } 92 93 uint64_t 94 pci_config_get64(ddi_acc_handle_t handle, off_t offset) 95 { 96 caddr_t cfgaddr; 97 ddi_acc_hdl_t *hp; 98 99 hp = impl_acc_hdl_get(handle); 100 cfgaddr = hp->ah_addr + offset; 101 return (ddi_get64(handle, (uint64_t *)cfgaddr)); 102 } 103 104 void 105 pci_config_put8(ddi_acc_handle_t handle, off_t offset, uint8_t value) 106 { 107 caddr_t cfgaddr; 108 ddi_acc_hdl_t *hp; 109 110 hp = impl_acc_hdl_get(handle); 111 cfgaddr = hp->ah_addr + offset; 112 ddi_put8(handle, (uint8_t *)cfgaddr, value); 113 } 114 115 void 116 pci_config_put16(ddi_acc_handle_t handle, off_t offset, uint16_t value) 117 { 118 caddr_t cfgaddr; 119 ddi_acc_hdl_t *hp; 120 121 hp = impl_acc_hdl_get(handle); 122 cfgaddr = hp->ah_addr + offset; 123 ddi_put16(handle, (uint16_t *)cfgaddr, value); 124 } 125 126 void 127 pci_config_put32(ddi_acc_handle_t handle, off_t offset, uint32_t value) 128 { 129 caddr_t cfgaddr; 130 ddi_acc_hdl_t *hp; 131 132 hp = impl_acc_hdl_get(handle); 133 cfgaddr = hp->ah_addr + offset; 134 ddi_put32(handle, (uint32_t *)cfgaddr, value); 135 } 136 137 void 138 pci_config_put64(ddi_acc_handle_t handle, off_t offset, uint64_t value) 139 { 140 caddr_t cfgaddr; 141 ddi_acc_hdl_t *hp; 142 143 hp = impl_acc_hdl_get(handle); 144 cfgaddr = hp->ah_addr + offset; 145 ddi_put64(handle, (uint64_t *)cfgaddr, value); 146 } 147 148 /* 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. 155 */ 156 #ifdef _ILP32 157 uint8_t 158 pci_config_getb(ddi_acc_handle_t handle, off_t offset) 159 { 160 caddr_t cfgaddr; 161 ddi_acc_hdl_t *hp; 162 163 hp = impl_acc_hdl_get(handle); 164 cfgaddr = hp->ah_addr + offset; 165 return (ddi_get8(handle, (uint8_t *)cfgaddr)); 166 } 167 168 uint16_t 169 pci_config_getw(ddi_acc_handle_t handle, off_t offset) 170 { 171 caddr_t cfgaddr; 172 ddi_acc_hdl_t *hp; 173 174 hp = impl_acc_hdl_get(handle); 175 cfgaddr = hp->ah_addr + offset; 176 return (ddi_get16(handle, (uint16_t *)cfgaddr)); 177 } 178 179 uint32_t 180 pci_config_getl(ddi_acc_handle_t handle, off_t offset) 181 { 182 caddr_t cfgaddr; 183 ddi_acc_hdl_t *hp; 184 185 hp = impl_acc_hdl_get(handle); 186 cfgaddr = hp->ah_addr + offset; 187 return (ddi_get32(handle, (uint32_t *)cfgaddr)); 188 } 189 190 uint64_t 191 pci_config_getll(ddi_acc_handle_t handle, off_t offset) 192 { 193 caddr_t cfgaddr; 194 ddi_acc_hdl_t *hp; 195 196 hp = impl_acc_hdl_get(handle); 197 cfgaddr = hp->ah_addr + offset; 198 return (ddi_get64(handle, (uint64_t *)cfgaddr)); 199 } 200 201 void 202 pci_config_putb(ddi_acc_handle_t handle, off_t offset, uint8_t value) 203 { 204 caddr_t cfgaddr; 205 ddi_acc_hdl_t *hp; 206 207 hp = impl_acc_hdl_get(handle); 208 cfgaddr = hp->ah_addr + offset; 209 ddi_put8(handle, (uint8_t *)cfgaddr, value); 210 } 211 212 void 213 pci_config_putw(ddi_acc_handle_t handle, off_t offset, uint16_t value) 214 { 215 caddr_t cfgaddr; 216 ddi_acc_hdl_t *hp; 217 218 hp = impl_acc_hdl_get(handle); 219 cfgaddr = hp->ah_addr + offset; 220 ddi_put16(handle, (uint16_t *)cfgaddr, value); 221 } 222 223 void 224 pci_config_putl(ddi_acc_handle_t handle, off_t offset, uint32_t value) 225 { 226 caddr_t cfgaddr; 227 ddi_acc_hdl_t *hp; 228 229 hp = impl_acc_hdl_get(handle); 230 cfgaddr = hp->ah_addr + offset; 231 ddi_put32(handle, (uint32_t *)cfgaddr, value); 232 } 233 234 void 235 pci_config_putll(ddi_acc_handle_t handle, off_t offset, uint64_t value) 236 { 237 caddr_t cfgaddr; 238 ddi_acc_hdl_t *hp; 239 240 hp = impl_acc_hdl_get(handle); 241 cfgaddr = hp->ah_addr + offset; 242 ddi_put64(handle, (uint64_t *)cfgaddr, value); 243 } 244 #endif /* _ILP32 */ 245 246 /*ARGSUSED*/ 247 int 248 pci_report_pmcap(dev_info_t *dip, int cap, void *arg) 249 { 250 return (DDI_SUCCESS); 251 } 252 253 /* 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. 263 */ 264 #define INDEX_SHIFT 3 265 #define BITMASK 0x7 266 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); 289 290 /* 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. 300 */ 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}, 309 310 {PCI_CAP_ID_HT, PCI_HTCAP_SLPRI_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK, 311 PCI_HTCAP_SLPRI_NDWORDS, pci_generic_save}, 312 313 {PCI_CAP_ID_HT, PCI_HTCAP_HOSTSEC_TYPE, PCI_HTCAP_TYPE_SLHOST_MASK, 314 PCI_HTCAP_HOSTSEC_NDWORDS, pci_generic_save}, 315 316 {PCI_CAP_ID_HT, PCI_HTCAP_INTCONF_TYPE, PCI_HTCAP_TYPE_MASK, 317 PCI_HTCAP_INTCONF_NDWORDS, pci_generic_save}, 318 319 {PCI_CAP_ID_HT, PCI_HTCAP_REVID_TYPE, PCI_HTCAP_TYPE_MASK, 320 PCI_HTCAP_REVID_NDWORDS, pci_generic_save}, 321 322 {PCI_CAP_ID_HT, PCI_HTCAP_UNITID_CLUMP_TYPE, PCI_HTCAP_TYPE_MASK, 323 PCI_HTCAP_UNITID_CLUMP_NDWORDS, pci_generic_save}, 324 325 {PCI_CAP_ID_HT, PCI_HTCAP_ECFG_TYPE, PCI_HTCAP_TYPE_MASK, 326 PCI_HTCAP_ECFG_NDWORDS, pci_generic_save}, 327 328 {PCI_CAP_ID_HT, PCI_HTCAP_ADDRMAP_TYPE, PCI_HTCAP_TYPE_MASK, 329 PCI_CAP_SZUNKNOWN, pci_ht_addrmap_save}, 330 331 {PCI_CAP_ID_HT, PCI_HTCAP_MSIMAP_TYPE, PCI_HTCAP_TYPE_MASK, 332 PCI_HTCAP_MSIMAP_NDWORDS, pci_generic_save}, 333 334 {PCI_CAP_ID_HT, PCI_HTCAP_DIRROUTE_TYPE, PCI_HTCAP_TYPE_MASK, 335 PCI_HTCAP_DIRROUTE_NDWORDS, pci_generic_save}, 336 337 {PCI_CAP_ID_HT, PCI_HTCAP_VCSET_TYPE, PCI_HTCAP_TYPE_MASK, 338 PCI_HTCAP_VCSET_NDWORDS, pci_generic_save}, 339 340 {PCI_CAP_ID_HT, PCI_HTCAP_RETRYMODE_TYPE, PCI_HTCAP_TYPE_MASK, 341 PCI_HTCAP_RETRYMODE_NDWORDS, pci_generic_save}, 342 343 {PCI_CAP_ID_HT, PCI_HTCAP_GEN3_TYPE, PCI_HTCAP_TYPE_MASK, 344 PCI_HTCAP_GEN3_NDWORDS, pci_generic_save}, 345 346 {PCI_CAP_ID_HT, PCI_HTCAP_FUNCEXT_TYPE, PCI_HTCAP_TYPE_MASK, 347 PCI_CAP_SZUNKNOWN, pci_ht_funcext_save}, 348 349 {PCI_CAP_ID_HT, PCI_HTCAP_PM_TYPE, PCI_HTCAP_TYPE_MASK, 350 PCI_HTCAP_PM_NDWORDS, pci_generic_save}, 351 352 /* 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}, 359 */ 360 {PCI_CAP_NEXT_PTR_NULL, 0, NULL} 361 }; 362 363 364 /* 365 * Save the configuration registers for cdip as a property 366 * so that it persists after detach/uninitchild. 367 */ 368 int 369 pci_save_config_regs(dev_info_t *dip) 370 { 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 #ifdef __sparc 380 ddi_acc_hdl_t *hp; 381 #else 382 ddi_device_acc_attr_t attr; 383 caddr_t cfgaddr; 384 #endif 385 off_t offset = 0; 386 uint8_t cap_ptr, cap_id; 387 int pcie = 0; 388 uint16_t status; 389 390 PMD(PMD_SX, ("pci_save_config_regs %s:%d\n", ddi_driver_name(dip), 391 ddi_get_instance(dip))) 392 393 #ifdef __sparc 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)); 397 398 return (DDI_FAILURE); 399 } 400 #else 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) 407 != DDI_SUCCESS) { 408 cmn_err(CE_WARN, "%s%d can't setup cautious config handle", 409 ddi_driver_name(dip), ddi_get_instance(dip)); 410 411 return (DDI_FAILURE); 412 } 413 #endif 414 415 /* 416 * Determine if it implements capabilities 417 */ 418 status = pci_config_get16(confhdl, PCI_CONF_STAT); 419 if (!(status & 0x10)) { 420 goto no_cap; 421 } 422 /* 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. 426 */ 427 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); 428 /* 429 * Walk the capabilities searching for pci express capability 430 */ 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) { 435 pcie = 1; 436 break; 437 } 438 cap_ptr = pci_config_get8(confhdl, 439 cap_ptr + PCI_CAP_NEXT_PTR); 440 } 441 no_cap: 442 if (pcie) { 443 /* PCI express device. Can have data in all 4k space */ 444 regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE, 445 KM_SLEEP); 446 p = regbuf; 447 /* 448 * Allocate space for mask. 449 * mask size is 128 bytes (4096 / 4 / 8 ) 450 */ 451 maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >> 452 INDEX_SHIFT); 453 maskbuf = (uint8_t *)kmem_zalloc(maskbufsz, KM_SLEEP); 454 #ifdef __sparc 455 hp = impl_acc_hdl_get(confhdl); 456 #endif 457 for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) { 458 #ifdef __sparc 459 ret = ddi_peek32(dip, (int32_t *)(hp->ah_addr + offset), 460 (int32_t *)p); 461 if (ret == DDI_SUCCESS) { 462 #else 463 /* 464 * ddi_peek doesn't work on x86, so we use cautious pci 465 * config access instead. 466 */ 467 *p = pci_config_get32(confhdl, offset); 468 if (*p != -1) { 469 #endif 470 /* it is readable register. set the bit */ 471 maskbuf[i >> INDEX_SHIFT] |= 472 (uint8_t)(1 << (i & BITMASK)); 473 } 474 p++; 475 offset += sizeof (uint32_t); 476 } 477 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), 492 SAVED_CONFIG_REGS); 493 } 494 495 kmem_free(maskbuf, (size_t)maskbufsz); 496 kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE); 497 } else { 498 regbuf = (uint32_t *)kmem_zalloc((size_t)PCI_CONF_HDR_SIZE, 499 KM_SLEEP); 500 chsp = (pci_config_header_state_t *)regbuf; 501 502 chsp->chs_command = pci_config_get16(confhdl, PCI_CONF_COMM); 503 chsp->chs_header_type = pci_config_get8(confhdl, 504 PCI_CONF_HEADER); 505 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) == 506 PCI_HEADER_ONE) 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) == 514 PCI_HEADER_ONE) { 515 chsp->chs_sec_latency_timer = 516 pci_config_get8(confhdl, PCI_BCNF_LATENCY_TIMER); 517 } 518 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); 525 526 /* 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. 530 */ 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( 534 capbufsz, KM_SLEEP); 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); 540 541 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 542 SAVED_CONFIG_REGS, (uchar_t *)regbuf, regbufsz)) != 543 DDI_PROP_SUCCESS) { 544 cmn_err(CE_WARN, "%s%d can't update prop %s", 545 ddi_driver_name(dip), ddi_get_instance(dip), 546 SAVED_CONFIG_REGS); 547 } else if (ncaps) { 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, 553 SAVED_CONFIG_REGS); 554 } 555 kmem_free(regbuf, (size_t)PCI_CONF_HDR_SIZE); 556 kmem_free(pci_cap_descp, capbufsz); 557 } 558 pci_config_teardown(&confhdl); 559 560 if (ret != DDI_PROP_SUCCESS) 561 return (DDI_FAILURE); 562 563 return (DDI_SUCCESS); 564 } 565 566 /* 567 * Saves registers associated with PCI capabilities. 568 * Returns number of 32 bit words saved. 569 * Number of capabilities saved is returned in ncapsp. 570 */ 571 static uint32_t 572 pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 573 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp) 574 { 575 return (cap_walk_and_save(confhdl, regbuf, cap_descp, ncapsp, 0)); 576 } 577 578 static uint32_t 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) 581 { 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; 586 uint16_t cap_reg; 587 588 *ncapsp = 0; 589 590 /* 591 * Determine if it implements capabilities 592 */ 593 status = pci_config_get16(confhdl, PCI_CONF_STAT); 594 if (!(status & 0x10)) { 595 return (words_saved); 596 } 597 598 if (!xspace) 599 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); 600 /* 601 * Walk the capabilities 602 */ 603 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 604 cap_id = CAP_ID(confhdl, cap_ptr, xspace); 605 606 /* Search for this cap id in our table */ 607 if (!xspace) { 608 pci_cap_entp = pci_cap_table; 609 cap_reg = pci_config_get16(confhdl, 610 cap_ptr + PCI_CAP_ID_REGS_OFF); 611 } 612 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) 617 break; 618 619 pci_cap_entp++; 620 } 621 622 offset = cap_ptr; 623 cap_ptr = NEXT_CAP(confhdl, cap_ptr, xspace); 624 /* 625 * If this cap id is not found in the table, there is nothing 626 * to save. 627 */ 628 if (pci_cap_entp->cap_id == PCI_CAP_NEXT_PTR_NULL) 629 continue; 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; 636 regbuf += nwords; 637 cap_descp++; 638 words_saved += nwords; 639 (*ncapsp)++; 640 } 641 } 642 643 } 644 return (words_saved); 645 } 646 647 static void 648 pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 649 uint32_t *regbuf, uint32_t nwords) 650 { 651 int i; 652 653 for (i = 0; i < nwords; i++) { 654 *regbuf = pci_config_get32(confhdl, cap_ptr); 655 regbuf++; 656 cap_ptr += 4; 657 } 658 } 659 660 static uint32_t 661 pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 662 uint32_t nwords) 663 { 664 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 665 return (nwords); 666 } 667 668 /*ARGSUSED*/ 669 static uint32_t 670 pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 671 uint32_t notused) 672 { 673 uint32_t nwords = PCI_MSI_MIN_WORDS; 674 uint16_t msi_ctrl; 675 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) 680 nwords++; 681 /* If per vector masking capable, add two more words */ 682 if (msi_ctrl & PCI_MSI_PVM_MASK) 683 nwords += 2; 684 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 685 686 return (nwords); 687 } 688 689 /*ARGSUSED*/ 690 static uint32_t 691 pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 692 uint32_t notused) 693 { 694 uint32_t nwords = PCI_PCIX_MIN_WORDS; 695 uint16_t pcix_command; 696 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)) 702 nwords += 4; 703 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 704 705 return (nwords); 706 } 707 708 /*ARGSUSED*/ 709 static uint32_t 710 pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 711 uint32_t notused) 712 { 713 return (0); 714 } 715 716 /*ARGSUSED*/ 717 static uint32_t 718 pci_ht_addrmap_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 719 uint32_t *regbuf, uint32_t notused) 720 { 721 uint32_t nwords = 0; 722 uint16_t reg; 723 724 reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF); 725 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); 731 break; 732 case PCI_HTCAP_ADDRMAP_64BIT_ID: 733 /* HT3.1 spec, ch 7.8, 64-bit dma */ 734 nwords = 4; 735 break; 736 default: 737 nwords = 0; 738 } 739 740 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 741 return (nwords); 742 } 743 744 /*ARGSUSED*/ 745 static uint32_t 746 pci_ht_funcext_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 747 uint32_t *regbuf, uint32_t notused) 748 { 749 uint32_t nwords; 750 uint16_t reg; 751 752 reg = pci_config_get16(confhdl, cap_ptr + PCI_CAP_ID_REGS_OFF); 753 754 /* HT3.1 spec, ch 7.17 */ 755 nwords = 1 + (reg & PCI_HTCAP_FUNCEXT_LEN_MASK); 756 757 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 758 return (nwords); 759 } 760 761 static void 762 pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf, 763 uint16_t pmcap_offset) 764 { 765 uint16_t pmcsr; 766 uint16_t pmcsr_offset = pmcap_offset + PCI_PMCSR; 767 uint32_t *saved_pmcsrp = (uint32_t *)((caddr_t)regbuf + PCI_PMCSR); 768 769 /* 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. 773 */ 774 pmcsr = pci_config_get16(confhdl, pmcsr_offset); 775 (*saved_pmcsrp) &= ~PCI_PMCSR_STATE_MASK; 776 (*saved_pmcsrp) |= (pmcsr & PCI_PMCSR_STATE_MASK); 777 } 778 779 static void 780 pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 781 pci_cap_save_desc_t *cap_descp, uint32_t elements) 782 { 783 int i, j; 784 uint16_t offset; 785 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); 792 regbuf++; 793 offset += 4; 794 } 795 cap_descp++; 796 } 797 } 798 799 /* 800 * Restore config_regs from a single devinfo node. 801 */ 802 int 803 pci_restore_config_regs(dev_info_t *dip) 804 { 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; 809 uint8_t *maskbuf; 810 uint32_t *regbuf, *p; 811 off_t offset = 0; 812 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); 817 } 818 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) { 822 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; 827 } 828 ASSERT(elements == PCIE_CONF_HDR_SIZE); 829 /* pcie device and has 4k config space saved */ 830 p = regbuf; 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); 836 p++; 837 offset += sizeof (uint32_t); 838 } 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); 846 } 847 } else { 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) { 851 852 pci_config_teardown(&confhdl); 853 return (DDI_SUCCESS); 854 } 855 856 chs_p = (pci_config_header_state_t *)regbuf; 857 pci_config_put16(confhdl, PCI_CONF_COMM, 858 chs_p->chs_command); 859 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == 860 PCI_HEADER_ONE) { 861 pci_config_put16(confhdl, PCI_BCNF_BCNTRL, 862 chs_p->chs_bridge_control); 863 } 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) == 869 PCI_HEADER_ONE) 870 pci_config_put8(confhdl, PCI_BCNF_LATENCY_TIMER, 871 chs_p->chs_sec_latency_timer); 872 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); 879 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) { 884 /* 885 * PCI capability related regsiters are saved. 886 * Restore them based on the description. 887 */ 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); 892 } 893 894 ddi_prop_free(regbuf); 895 } 896 897 /* 898 * Make sure registers are flushed 899 */ 900 (void) pci_config_get32(confhdl, PCI_CONF_BASE5); 901 902 903 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS) != 904 DDI_PROP_SUCCESS) { 905 cmn_err(CE_WARN, "%s%d can't remove prop %s", 906 ddi_driver_name(dip), ddi_get_instance(dip), 907 SAVED_CONFIG_REGS); 908 } 909 910 pci_config_teardown(&confhdl); 911 912 return (DDI_SUCCESS); 913 914 restoreconfig_err: 915 ddi_prop_free(maskbuf); 916 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK) != 917 DDI_PROP_SUCCESS) { 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); 921 } 922 pci_config_teardown(&confhdl); 923 return (DDI_FAILURE); 924 } 925 926 /*ARGSUSED*/ 927 static int 928 pci_lookup_pmcap(dev_info_t *dip, ddi_acc_handle_t conf_hdl, 929 uint16_t *pmcap_offsetp) 930 { 931 uint8_t cap_ptr; 932 uint8_t cap_id; 933 uint8_t header_type; 934 uint16_t status; 935 936 header_type = pci_config_get8(conf_hdl, PCI_CONF_HEADER); 937 header_type &= PCI_HEADER_TYPE_M; 938 939 /* we don't deal with bridges, etc here */ 940 if (header_type != PCI_HEADER_ZERO) { 941 return (DDI_FAILURE); 942 } 943 944 status = pci_config_get16(conf_hdl, PCI_CONF_STAT); 945 if ((status & PCI_STAT_CAP) == 0) { 946 return (DDI_FAILURE); 947 } 948 949 cap_ptr = pci_config_get8(conf_hdl, PCI_CONF_CAP_PTR); 950 951 /* 952 * Walk the capabilities searching for a PM entry. 953 */ 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) { 957 break; 958 } 959 cap_ptr = pci_config_get8(conf_hdl, 960 cap_ptr + PCI_CAP_NEXT_PTR); 961 } 962 963 if (cap_ptr == PCI_CAP_NEXT_PTR_NULL) { 964 return (DDI_FAILURE); 965 } 966 *pmcap_offsetp = cap_ptr; 967 return (DDI_SUCCESS); 968 } 969 970 /* 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. 980 */ 981 982 typedef struct pci_pm_context { 983 int ppc_flags; 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; 987 } pci_pm_context_t; 988 989 #define SAVED_PM_CONTEXT "pci-pm-context" 990 991 /* values for ppc_flags */ 992 #define PPCF_NOPMCAP 1 993 994 /* 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 1000 */ 1001 #if defined(__x86) 1002 extern int acpi_ddi_setwake(dev_info_t *dip, int level); 1003 #endif 1004 1005 int 1006 pci_post_suspend(dev_info_t *dip) 1007 { 1008 pci_pm_context_t *p; 1009 uint16_t pmcap, pmcsr, pcicmd; 1010 uint_t length; 1011 int ret; 1012 int fromprop = 1; /* source of memory *p */ 1013 ddi_acc_handle_t hdl; 1014 1015 PMD(PMD_SX, ("pci_post_suspend %s:%d\n", 1016 ddi_driver_name(dip), ddi_get_instance(dip))) 1017 1018 if (pci_save_config_regs(dip) != DDI_SUCCESS) { 1019 return (DDI_FAILURE); 1020 } 1021 1022 if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) { 1023 return (DDI_FAILURE); 1024 } 1025 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); 1030 fromprop = 0; 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, 1039 SAVED_PM_CONTEXT); 1040 ret = DDI_FAILURE; 1041 } else { 1042 ret = DDI_SUCCESS; 1043 } 1044 kmem_free(p, sizeof (*p)); 1045 pci_config_teardown(&hdl); 1046 return (DDI_SUCCESS); 1047 } 1048 /* 1049 * Upon suspend, set the power level to the lowest that can 1050 * wake the system. If none can, then set to lowest. 1051 * XXX later we will need to check policy to see if this 1052 * XXX device has had wakeup disabled 1053 */ 1054 pmcap = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCAP); 1055 if ((pmcap & PCI_PMCAP_D3COLD_PME) != 0) 1056 p->ppc_suspend_level = 1057 (PCI_PMCSR_PME_EN | PCI_PMCSR_D3HOT); 1058 else if ((pmcap & (PCI_PMCAP_D3HOT_PME | PCI_PMCAP_D2_PME)) != 1059 0) 1060 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D2; 1061 else if ((pmcap & PCI_PMCAP_D1_PME) != 0) 1062 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D1; 1063 else if ((pmcap & PCI_PMCAP_D0_PME) != 0) 1064 p->ppc_suspend_level = PCI_PMCSR_PME_EN | PCI_PMCSR_D0; 1065 else 1066 p->ppc_suspend_level = PCI_PMCSR_D3HOT; 1067 1068 /* 1069 * we defer updating the property to catch the saved 1070 * register values as well 1071 */ 1072 } 1073 /* If we set this in kmem_zalloc'd memory, we already returned above */ 1074 if ((p->ppc_flags & PPCF_NOPMCAP) != 0) { 1075 ddi_prop_free(p); 1076 pci_config_teardown(&hdl); 1077 return (DDI_SUCCESS); 1078 } 1079 1080 1081 /* 1082 * Turn off (Bus) Master Enable, since acpica will be turning off 1083 * bus master aribitration 1084 */ 1085 pcicmd = pci_config_get16(hdl, PCI_CONF_COMM); 1086 pcicmd &= ~PCI_COMM_ME; 1087 pci_config_put16(hdl, PCI_CONF_COMM, pcicmd); 1088 1089 /* 1090 * set pm csr 1091 */ 1092 pmcsr = pci_config_get16(hdl, p->ppc_cap_offset + PCI_PMCSR); 1093 p->ppc_pmcsr = pmcsr; 1094 pmcsr &= (PCI_PMCSR_STATE_MASK); 1095 pmcsr |= (PCI_PMCSR_PME_STAT | p->ppc_suspend_level); 1096 pci_config_put16(hdl, p->ppc_cap_offset + PCI_PMCSR, pmcsr); 1097 1098 #if defined(__x86) 1099 /* 1100 * Arrange for platform wakeup enabling 1101 */ 1102 if ((p->ppc_suspend_level & PCI_PMCSR_PME_EN) != 0) { 1103 int retval; 1104 1105 retval = acpi_ddi_setwake(dip, 3); /* XXX 3 for now */ 1106 if (retval) { 1107 PMD(PMD_SX, ("pci_post_suspend, setwake %s@%s rets " 1108 "%x\n", PM_NAME(dip), PM_ADDR(dip), retval)); 1109 } 1110 } 1111 #endif 1112 1113 /* 1114 * Push out saved register values 1115 */ 1116 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT, 1117 (uchar_t *)p, sizeof (pci_pm_context_t)); 1118 if (ret == DDI_PROP_SUCCESS) { 1119 if (fromprop) 1120 ddi_prop_free(p); 1121 else 1122 kmem_free(p, sizeof (*p)); 1123 pci_config_teardown(&hdl); 1124 return (DDI_SUCCESS); 1125 } 1126 /* Failed; put things back the way we found them */ 1127 (void) pci_restore_config_regs(dip); 1128 if (fromprop) 1129 ddi_prop_free(p); 1130 else 1131 kmem_free(p, sizeof (*p)); 1132 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PM_CONTEXT); 1133 pci_config_teardown(&hdl); 1134 return (DDI_FAILURE); 1135 } 1136 1137 /* 1138 * The inverse of pci_post_suspend; handle pci-specific resume processing 1139 * First, turn device back on, then restore config space. 1140 */ 1141 1142 int 1143 pci_pre_resume(dev_info_t *dip) 1144 { 1145 ddi_acc_handle_t hdl; 1146 pci_pm_context_t *p; 1147 /* E_FUNC_SET_NOT_USED */ 1148 uint16_t pmcap, pmcsr; 1149 int flags; 1150 uint_t length; 1151 clock_t drv_usectohz(clock_t microsecs); 1152 #if defined(__x86) 1153 uint16_t suspend_level; 1154 #endif 1155 1156 PMD(PMD_SX, ("pci_pre_resume %s:%d\n", ddi_driver_name(dip), 1157 ddi_get_instance(dip))) 1158 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1159 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 1160 SAVED_PM_CONTEXT, (uchar_t **)&p, &length) != DDI_PROP_SUCCESS) { 1161 return (DDI_FAILURE); 1162 } 1163 flags = p->ppc_flags; 1164 pmcap = p->ppc_cap_offset; 1165 pmcsr = p->ppc_pmcsr; 1166 #if defined(__x86) 1167 suspend_level = p->ppc_suspend_level; 1168 #endif 1169 ddi_prop_free(p); 1170 if ((flags & PPCF_NOPMCAP) != 0) 1171 goto done; 1172 #if defined(__x86) 1173 /* 1174 * Turn platform wake enable back off 1175 */ 1176 if ((suspend_level & PCI_PMCSR_PME_EN) != 0) { 1177 int retval; 1178 1179 retval = acpi_ddi_setwake(dip, 0); /* 0 for now */ 1180 if (retval) { 1181 PMD(PMD_SX, ("pci_pre_resume, setwake %s@%s rets " 1182 "%x\n", PM_NAME(dip), PM_ADDR(dip), retval)); 1183 } 1184 } 1185 #endif 1186 if (pci_config_setup(dip, &hdl) != DDI_SUCCESS) { 1187 return (DDI_FAILURE); 1188 } 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); 1195 } 1196