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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/sunndi.h> 31 #include <sys/ddifm_impl.h> 32 #include <sys/fm/util.h> 33 #include <sys/fm/protocol.h> 34 #include <sys/fm/io/pci.h> 35 #include <sys/fm/io/ddi.h> 36 #include <sys/pci.h> 37 #include <sys/pcie.h> 38 #include <sys/pci_impl.h> 39 #include <sys/epm.h> 40 41 42 int 43 pci_config_setup(dev_info_t *dip, ddi_acc_handle_t *handle) 44 { 45 caddr_t cfgaddr; 46 ddi_device_acc_attr_t attr; 47 48 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 49 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 50 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 51 52 /* Check for fault management capabilities */ 53 if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(dip))) 54 attr.devacc_attr_access = DDI_FLAGERR_ACC; 55 56 return (ddi_regs_map_setup(dip, 0, &cfgaddr, 0, 0, &attr, handle)); 57 } 58 59 void 60 pci_config_teardown(ddi_acc_handle_t *handle) 61 { 62 ddi_regs_map_free(handle); 63 } 64 65 /* 66 * pci_ereport_setup, pci_ereport_teardown, pci_ereport_post: 67 * Interfaces to be used by ereport capable PCI device drivers to setup, 68 * teardown, and post generic PCI error reports. This is to guarantee a 69 * consistant error report model for all PCI devices. Please see 70 * PSARC/2004/391. 71 */ 72 73 typedef struct pci_erpt { 74 caddr_t pci_cfg_addr; /* Config space address */ 75 ddi_acc_handle_t pci_cfg_hdl; /* Config space access handle */ 76 } pci_erpt_t; 77 78 pci_fm_err_t pci_err_tbl[] = { 79 PCI_DET_PERR, PCI_STAT_PERROR, NULL, 80 PCI_MDPE, PCI_STAT_S_PERROR, PCI_TARG_MDPE, 81 PCI_SIG_SERR, PCI_STAT_S_SYSERR, NULL, 82 PCI_MA, PCI_STAT_R_MAST_AB, PCI_TARG_MA, 83 PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, 84 PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, 85 NULL, NULL, 86 }; 87 88 pci_fm_err_t pci_bdg_err_tbl[] = { 89 PCI_DET_PERR, PCI_STAT_PERROR, NULL, 90 PCI_MDPE, PCI_STAT_S_PERROR, NULL, 91 PCI_REC_SERR, PCI_STAT_S_SYSERR, NULL, 92 PCI_MA, PCI_STAT_R_MAST_AB, NULL, 93 PCI_REC_TA, PCI_STAT_R_TARG_AB, NULL, 94 PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, 95 NULL, NULL, 96 }; 97 98 void 99 pci_ereport_setup(dev_info_t *dip) 100 { 101 struct dev_info *devi = DEVI(dip); 102 struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl; 103 pci_erpt_t *erpt_p; 104 ddi_acc_hdl_t *hp; 105 uint16_t pci_devstat = 0; 106 uint16_t pcie_cap = 0; 107 uint8_t ecap_ptr = 0; 108 uint8_t cap_ptr = 0; 109 uint8_t cap_id = 0; 110 int have_pciex; 111 112 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip))) { 113 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 114 return; 115 } 116 117 ASSERT(fmhdl); 118 ASSERT(fmhdl->fh_bus_specific == NULL); 119 120 if ((erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP)) == NULL) 121 return; 122 123 /* 124 * Setup config space and store config address 125 * in pci_erpt struct. 126 */ 127 if (pci_config_setup(dip, &erpt_p->pci_cfg_hdl) == DDI_SUCCESS) { 128 hp = impl_acc_hdl_get(erpt_p->pci_cfg_hdl); 129 erpt_p->pci_cfg_addr = (caddr_t)hp->ah_addr; 130 fmhdl->fh_bus_specific = (void *)erpt_p; 131 } else { 132 return; 133 } 134 135 /* 136 * Determine if this device supports a capabilities list. We 137 * do so by looking at a bit in the status register. If we are 138 * unable to retrieve the status register, something is horribly 139 * wrong and we should just bail. 140 */ 141 if ((pci_devstat = ddi_get16(erpt_p->pci_cfg_hdl, 142 (uint16_t *)(erpt_p->pci_cfg_addr + PCI_CONF_STAT))) == 0xff) 143 return; 144 if ((pci_devstat & PCI_STAT_CAP) == 0) 145 return; 146 147 /* 148 * Determine if we are on a machine with pci express. We do so 149 * by looping through the capabilities of the device and looking 150 * to see if one of those capabilities is support of PCI 151 * express. 152 */ 153 have_pciex = 0; 154 if ((cap_ptr = ddi_get8(erpt_p->pci_cfg_hdl, 155 (uint8_t *)(erpt_p->pci_cfg_addr + PCI_CONF_CAP_PTR))) != 156 0xff) { 157 while ((cap_id = ddi_get8(erpt_p->pci_cfg_hdl, 158 (uint8_t *)(erpt_p->pci_cfg_addr + cap_ptr))) != 159 0xff) { 160 if (cap_id == PCI_CAP_ID_PCI_E) { 161 ecap_ptr = cap_ptr; 162 have_pciex = 1; 163 break; 164 } 165 if ((cap_ptr = ddi_get8(erpt_p->pci_cfg_hdl, 166 (uint8_t *)(erpt_p->pci_cfg_addr + 167 cap_ptr + 1))) == 0xff || cap_ptr == 0) 168 break; 169 } 170 } 171 172 /* 173 * If not pci express, we're done 174 */ 175 if (have_pciex == 0) 176 return; 177 178 /* 179 * Save and export the pci express capabilities reg. 180 */ 181 pcie_cap = ddi_get16(erpt_p->pci_cfg_hdl, 182 (uint16_t *)(erpt_p->pci_cfg_addr + ecap_ptr + PCIE_PCIECAP)); 183 (void) ndi_prop_update_int(DDI_DEV_T_NONE, 184 dip, SAVED_PCIEX_CAP_REG, pcie_cap); 185 186 /* 187 * Find and export any slot capabilities register 188 */ 189 if (pcie_cap & PCIE_PCIECAP_SLOT_IMPL) { 190 int sltcap = ddi_get32(erpt_p->pci_cfg_hdl, 191 (uint32_t *) 192 (erpt_p->pci_cfg_addr + ecap_ptr + PCIE_SLOTCAP)); 193 (void) ndi_prop_update_int(DDI_DEV_T_NONE, 194 dip, SAVED_PCIEX_SLOTCAP_REG, sltcap); 195 } 196 } 197 198 void 199 pci_ereport_teardown(dev_info_t *dip) 200 { 201 struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl; 202 pci_erpt_t *erpt_p; 203 204 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip))) { 205 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP); 206 } 207 208 ASSERT(fmhdl); 209 210 erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 211 if (erpt_p == NULL) 212 return; 213 214 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PCIEX_CAP_REG); 215 (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_PCIEX_SLOTCAP_REG); 216 pci_config_teardown(&erpt_p->pci_cfg_hdl); 217 kmem_free(erpt_p, sizeof (pci_erpt_t)); 218 fmhdl->fh_bus_specific = NULL; 219 } 220 221 void 222 pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *status) 223 { 224 struct i_ddi_fmhdl *fmhdl; 225 pci_erpt_t *erpt_p; 226 char buf[FM_MAX_CLASS]; 227 uint16_t cfg_comm = 0xffff; 228 uint16_t cfg_stat = 0xffff; 229 int i; 230 fmhdl = DEVI(dip)->devi_fmhdl; 231 232 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip))) { 233 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 234 return; 235 } 236 237 ASSERT(fmhdl); 238 239 derr->fme_ena = derr->fme_ena ? derr->fme_ena : fm_ena_generate(0, 240 FM_ENA_FMT1); 241 242 erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 243 if (erpt_p == NULL) { 244 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 245 return; 246 } 247 248 if ((cfg_stat = ddi_get16(erpt_p->pci_cfg_hdl, 249 (uint16_t *)(erpt_p->pci_cfg_addr + PCI_CONF_STAT))) == 0xffff) { 250 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 251 PCI_ERROR_SUBCLASS, PCI_NR); 252 ddi_fm_ereport_post(dip, buf, derr->fme_ena, DDI_NOSLEEP, 253 FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 254 goto done; 255 } 256 if ((cfg_comm = ddi_get16(erpt_p->pci_cfg_hdl, 257 (uint16_t *)(erpt_p->pci_cfg_addr + PCI_CONF_COMM))) == 0xffff) { 258 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 259 PCI_ERROR_SUBCLASS, PCI_NR); 260 ddi_fm_ereport_post(dip, buf, derr->fme_ena, DDI_NOSLEEP, 261 FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 262 goto done; 263 } 264 265 if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 266 for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 267 if (cfg_stat & pci_err_tbl[i].reg_bit) { 268 269 /* 270 * Generate an ereport for this error bit. 271 */ 272 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 273 PCI_ERROR_SUBCLASS, 274 pci_err_tbl[i].err_class); 275 ddi_fm_ereport_post(dip, buf, derr->fme_ena, 276 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 277 PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 278 cfg_stat, PCI_CONFIG_COMMAND, 279 DATA_TYPE_UINT16, cfg_comm, NULL); 280 281 /* 282 * Generate a corresponding ereport on behalf 283 * of the target (the parent dip) of the 284 * transaction. 285 */ 286 if (pci_err_tbl[i].terr_class != NULL && 287 DDI_FM_EREPORT_CAP(ddi_fm_capable( 288 (dev_info_t *)DEVI(dip)->devi_parent))) { 289 (void) snprintf(buf, FM_MAX_CLASS, 290 "%s.%s", PCI_ERROR_SUBCLASS, 291 pci_err_tbl[i].terr_class); 292 ddi_fm_ereport_post((dev_info_t *) 293 DEVI(dip)->devi_parent, buf, 294 derr->fme_ena, DDI_NOSLEEP, 295 FM_VERSION, DATA_TYPE_UINT8, 0, 296 NULL); 297 } 298 } 299 } 300 } 301 302 /* 303 * Clear error bits 304 */ 305 ddi_put16(erpt_p->pci_cfg_hdl, 306 (uint16_t *)(erpt_p->pci_cfg_addr + PCI_CONF_STAT), 307 (uint16_t)cfg_stat); 308 done: 309 if (status != NULL) 310 *status = cfg_stat; 311 } 312 313 /* 314 * Generic pci-pci bridge error report function 315 */ 316 void 317 pci_bdg_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *status) 318 { 319 struct i_ddi_fmhdl *fmhdl; 320 pci_erpt_t *erpt_p; 321 char buf[FM_MAX_CLASS]; 322 uint16_t bdg_ctrl = 0xffff; 323 uint16_t cfg_sec_stat = 0xffff; 324 int i; 325 326 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip))) { 327 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 328 return; 329 } 330 331 fmhdl = DEVI(dip)->devi_fmhdl; 332 333 ASSERT(fmhdl); 334 335 derr->fme_ena = derr->fme_ena ? derr->fme_ena : fm_ena_generate(0, 336 FM_ENA_FMT1); 337 338 erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific; 339 if (erpt_p == NULL) { 340 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP); 341 return; 342 } 343 344 if ((cfg_sec_stat = ddi_get16(erpt_p->pci_cfg_hdl, 345 (uint16_t *)(erpt_p->pci_cfg_addr + PCI_BCNF_SEC_STATUS))) 346 == 0xffff) { 347 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", PCI_ERROR_SUBCLASS, 348 PCI_NR); 349 ddi_fm_ereport_post(dip, buf, derr->fme_ena, DDI_NOSLEEP, 350 FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 351 goto done; 352 } 353 354 if ((bdg_ctrl = ddi_get16(erpt_p->pci_cfg_hdl, 355 (uint16_t *)(erpt_p->pci_cfg_addr + PCI_BCNF_BCNTRL))) == 0xffff) { 356 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", PCI_ERROR_SUBCLASS, 357 PCI_NR); 358 ddi_fm_ereport_post(dip, buf, derr->fme_ena, DDI_NOSLEEP, 359 FM_VERSION, DATA_TYPE_UINT8, 0, NULL); 360 goto done; 361 } 362 363 if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 364 if (bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT) { 365 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 366 PCI_ERROR_SUBCLASS, PCI_DTO); 367 ddi_fm_ereport_post(dip, buf, derr->fme_ena, 368 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 369 PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 370 cfg_sec_stat, PCI_BCNTRL, DATA_TYPE_UINT16, 371 bdg_ctrl, NULL); 372 } 373 374 for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) { 375 if (cfg_sec_stat & pci_bdg_err_tbl[i].reg_bit) { 376 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", 377 PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, 378 pci_bdg_err_tbl[i].err_class); 379 ddi_fm_ereport_post(dip, buf, derr->fme_ena, 380 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 381 PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16, 382 cfg_sec_stat, PCI_BCNTRL, DATA_TYPE_UINT16, 383 bdg_ctrl, NULL); 384 } 385 } 386 } 387 388 /* 389 * Clear error bits 390 */ 391 ddi_put16(erpt_p->pci_cfg_hdl, (uint16_t *) 392 (erpt_p->pci_cfg_addr + PCI_BCNF_SEC_STATUS), 393 (uint16_t)cfg_sec_stat); 394 ddi_put16(erpt_p->pci_cfg_hdl, (uint16_t *) 395 (erpt_p->pci_cfg_addr + PCI_BCNF_BCNTRL), 396 (uint16_t)bdg_ctrl); 397 398 done: 399 if (status != NULL) 400 *status = cfg_sec_stat; 401 } 402 403 /* 404 * Generic pci-pci bridge error analysis function 405 */ 406 int 407 pci_bdg_check_status(dev_info_t *dip, ddi_fm_error_t *derr, 408 uint16_t pci_cfg_stat, uint16_t pci_cfg_sec_stat) 409 { 410 int ret; 411 int fatal = 0; 412 int nonfatal = 0; 413 int unknown = 0; 414 415 if (derr->fme_flag == DDI_FM_ERR_POKE) { 416 /* 417 * special case for pokes - we only consider master abort 418 * and target abort as nonfatal. Sserr with no master abort is 419 * fatal, but master/target abort can come in on separate 420 * instance, so return unknown and parent will determine if 421 * nonfatal (if another child returned nonfatal - ie master 422 * or target abort) or fatal otherwise 423 */ 424 if (pci_cfg_sec_stat & (PCI_STAT_R_TARG_AB | 425 PCI_STAT_R_MAST_AB)) 426 nonfatal++; 427 if (pci_cfg_stat & PCI_STAT_S_SYSERR) 428 unknown++; 429 } else if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) { 430 /* 431 * Only sserr on primary bus is considered fatal. 432 * In all other conditions, the bridge has been able to notify 433 * the initiator of the error condition, so let the initiator 434 * (be it the host for PIO or the leaf device for DMA) handle it 435 */ 436 if (pci_cfg_stat & PCI_STAT_S_SYSERR) 437 fatal++; 438 if (pci_cfg_stat & (PCI_STAT_PERROR | 439 PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | 440 PCI_STAT_R_TARG_AB | PCI_STAT_S_TARG_AB)) 441 nonfatal++; 442 if (pci_cfg_sec_stat & (PCI_STAT_R_TARG_AB | 443 PCI_STAT_S_SYSERR | PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | 444 PCI_STAT_PERROR | PCI_STAT_S_TARG_AB)) 445 nonfatal++; 446 } 447 448 /* 449 * now check children below the bridge 450 */ 451 ret = ndi_fm_handler_dispatch(dip, NULL, derr); 452 if (ret == DDI_FM_FATAL) 453 fatal++; 454 else if (ret == DDI_FM_NONFATAL) 455 nonfatal++; 456 else if (ret == DDI_FM_UNKNOWN) 457 unknown++; 458 459 return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 460 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 461 } 462 463 uint8_t 464 pci_config_get8(ddi_acc_handle_t handle, off_t offset) 465 { 466 caddr_t cfgaddr; 467 ddi_acc_hdl_t *hp; 468 469 hp = impl_acc_hdl_get(handle); 470 cfgaddr = hp->ah_addr + offset; 471 return (ddi_get8(handle, (uint8_t *)cfgaddr)); 472 } 473 474 uint16_t 475 pci_config_get16(ddi_acc_handle_t handle, off_t offset) 476 { 477 caddr_t cfgaddr; 478 ddi_acc_hdl_t *hp; 479 480 hp = impl_acc_hdl_get(handle); 481 cfgaddr = hp->ah_addr + offset; 482 return (ddi_get16(handle, (uint16_t *)cfgaddr)); 483 } 484 485 uint32_t 486 pci_config_get32(ddi_acc_handle_t handle, off_t offset) 487 { 488 caddr_t cfgaddr; 489 ddi_acc_hdl_t *hp; 490 491 hp = impl_acc_hdl_get(handle); 492 cfgaddr = hp->ah_addr + offset; 493 return (ddi_get32(handle, (uint32_t *)cfgaddr)); 494 } 495 496 uint64_t 497 pci_config_get64(ddi_acc_handle_t handle, off_t offset) 498 { 499 caddr_t cfgaddr; 500 ddi_acc_hdl_t *hp; 501 502 hp = impl_acc_hdl_get(handle); 503 cfgaddr = hp->ah_addr + offset; 504 return (ddi_get64(handle, (uint64_t *)cfgaddr)); 505 } 506 507 void 508 pci_config_put8(ddi_acc_handle_t handle, off_t offset, uint8_t value) 509 { 510 caddr_t cfgaddr; 511 ddi_acc_hdl_t *hp; 512 513 hp = impl_acc_hdl_get(handle); 514 cfgaddr = hp->ah_addr + offset; 515 ddi_put8(handle, (uint8_t *)cfgaddr, value); 516 } 517 518 void 519 pci_config_put16(ddi_acc_handle_t handle, off_t offset, uint16_t value) 520 { 521 caddr_t cfgaddr; 522 ddi_acc_hdl_t *hp; 523 524 hp = impl_acc_hdl_get(handle); 525 cfgaddr = hp->ah_addr + offset; 526 ddi_put16(handle, (uint16_t *)cfgaddr, value); 527 } 528 529 void 530 pci_config_put32(ddi_acc_handle_t handle, off_t offset, uint32_t value) 531 { 532 caddr_t cfgaddr; 533 ddi_acc_hdl_t *hp; 534 535 hp = impl_acc_hdl_get(handle); 536 cfgaddr = hp->ah_addr + offset; 537 ddi_put32(handle, (uint32_t *)cfgaddr, value); 538 } 539 540 void 541 pci_config_put64(ddi_acc_handle_t handle, off_t offset, uint64_t value) 542 { 543 caddr_t cfgaddr; 544 ddi_acc_hdl_t *hp; 545 546 hp = impl_acc_hdl_get(handle); 547 cfgaddr = hp->ah_addr + offset; 548 ddi_put64(handle, (uint64_t *)cfgaddr, value); 549 } 550 551 /* 552 * We need to separate the old interfaces from the new ones and leave them 553 * in here for a while. Previous versions of the OS defined the new interfaces 554 * to the old interfaces. This way we can fix things up so that we can 555 * eventually remove these interfaces. 556 * e.g. A 3rd party module/driver using pci_config_get8 and built against S10 557 * or earlier will actually have a reference to pci_config_getb in the binary. 558 */ 559 #ifdef _ILP32 560 uint8_t 561 pci_config_getb(ddi_acc_handle_t handle, off_t offset) 562 { 563 caddr_t cfgaddr; 564 ddi_acc_hdl_t *hp; 565 566 hp = impl_acc_hdl_get(handle); 567 cfgaddr = hp->ah_addr + offset; 568 return (ddi_get8(handle, (uint8_t *)cfgaddr)); 569 } 570 571 uint16_t 572 pci_config_getw(ddi_acc_handle_t handle, off_t offset) 573 { 574 caddr_t cfgaddr; 575 ddi_acc_hdl_t *hp; 576 577 hp = impl_acc_hdl_get(handle); 578 cfgaddr = hp->ah_addr + offset; 579 return (ddi_get16(handle, (uint16_t *)cfgaddr)); 580 } 581 582 uint32_t 583 pci_config_getl(ddi_acc_handle_t handle, off_t offset) 584 { 585 caddr_t cfgaddr; 586 ddi_acc_hdl_t *hp; 587 588 hp = impl_acc_hdl_get(handle); 589 cfgaddr = hp->ah_addr + offset; 590 return (ddi_get32(handle, (uint32_t *)cfgaddr)); 591 } 592 593 uint64_t 594 pci_config_getll(ddi_acc_handle_t handle, off_t offset) 595 { 596 caddr_t cfgaddr; 597 ddi_acc_hdl_t *hp; 598 599 hp = impl_acc_hdl_get(handle); 600 cfgaddr = hp->ah_addr + offset; 601 return (ddi_get64(handle, (uint64_t *)cfgaddr)); 602 } 603 604 void 605 pci_config_putb(ddi_acc_handle_t handle, off_t offset, uint8_t value) 606 { 607 caddr_t cfgaddr; 608 ddi_acc_hdl_t *hp; 609 610 hp = impl_acc_hdl_get(handle); 611 cfgaddr = hp->ah_addr + offset; 612 ddi_put8(handle, (uint8_t *)cfgaddr, value); 613 } 614 615 void 616 pci_config_putw(ddi_acc_handle_t handle, off_t offset, uint16_t value) 617 { 618 caddr_t cfgaddr; 619 ddi_acc_hdl_t *hp; 620 621 hp = impl_acc_hdl_get(handle); 622 cfgaddr = hp->ah_addr + offset; 623 ddi_put16(handle, (uint16_t *)cfgaddr, value); 624 } 625 626 void 627 pci_config_putl(ddi_acc_handle_t handle, off_t offset, uint32_t value) 628 { 629 caddr_t cfgaddr; 630 ddi_acc_hdl_t *hp; 631 632 hp = impl_acc_hdl_get(handle); 633 cfgaddr = hp->ah_addr + offset; 634 ddi_put32(handle, (uint32_t *)cfgaddr, value); 635 } 636 637 void 638 pci_config_putll(ddi_acc_handle_t handle, off_t offset, uint64_t value) 639 { 640 caddr_t cfgaddr; 641 ddi_acc_hdl_t *hp; 642 643 hp = impl_acc_hdl_get(handle); 644 cfgaddr = hp->ah_addr + offset; 645 ddi_put64(handle, (uint64_t *)cfgaddr, value); 646 } 647 #endif /* _ILP32 */ 648 649 /*ARGSUSED*/ 650 int 651 pci_report_pmcap(dev_info_t *dip, int cap, void *arg) 652 { 653 return (DDI_SUCCESS); 654 } 655 656 /* 657 * Note about saving and restoring config space. 658 * PCI devices have only upto 256 bytes of config space while PCI Express 659 * devices can have upto 4k config space. In case of PCI Express device, 660 * we save all 4k config space and restore it even if it doesn't make use 661 * of all 4k. But some devices don't respond to reads to non-existent 662 * registers within the config space. To avoid any panics, we use ddi_peek 663 * to do the reads. A bit mask is used to indicate which words of the 664 * config space are accessible. While restoring the config space, only those 665 * readable words are restored. We do all this in 32 bit size words. 666 */ 667 #define INDEX_SHIFT 3 668 #define BITMASK 0x7 669 670 static uint32_t pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 671 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp); 672 static void pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 673 pci_cap_save_desc_t *cap_descp, uint32_t elements); 674 static uint32_t pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 675 uint32_t *regbuf, uint32_t nwords); 676 static uint32_t pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 677 uint32_t *regbuf, uint32_t notused); 678 static uint32_t pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 679 uint32_t *regbuf, uint32_t notused); 680 static uint32_t pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 681 uint32_t *regbuf, uint32_t notused); 682 static void pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 683 uint32_t *regbuf, uint32_t nwords); 684 static uint32_t cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf, 685 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace); 686 static void pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf, 687 uint16_t pmcap_offset); 688 689 /* 690 * Table below specifies the number of registers to be saved for each PCI 691 * capability. pci_generic_save saves the number of words specified in the 692 * table. Any special considerations will be taken care by the capability 693 * specific save function e.g. use pci_msi_save to save registers associated 694 * with MSI capability. PCI_UNKNOWN_SIZE indicates that number of registers 695 * to be saved is variable and will be determined by the specific save function. 696 * Currently we save/restore all the registers associated with the capability 697 * including read only registers. Regsiters are saved and restored in 32 bit 698 * size words. 699 */ 700 static pci_cap_entry_t pci_cap_table[] = { 701 {PCI_CAP_ID_PM, PCI_PMCAP_NDWORDS, pci_generic_save}, 702 {PCI_CAP_ID_AGP, PCI_AGP_NDWORDS, pci_generic_save}, 703 {PCI_CAP_ID_SLOT_ID, PCI_SLOTID_NDWORDS, pci_generic_save}, 704 {PCI_CAP_ID_MSI_X, PCI_MSIX_NDWORDS, pci_generic_save}, 705 {PCI_CAP_ID_MSI, PCI_CAP_SZUNKNOWN, pci_msi_save}, 706 {PCI_CAP_ID_PCIX, PCI_CAP_SZUNKNOWN, pci_pcix_save}, 707 {PCI_CAP_ID_PCI_E, PCI_CAP_SZUNKNOWN, pci_pcie_save}, 708 /* 709 * {PCI_CAP_ID_cPCI_CRC, 0, NULL}, 710 * {PCI_CAP_ID_VPD, 0, NULL}, 711 * {PCI_CAP_ID_cPCI_HS, 0, NULL}, 712 * {PCI_CAP_ID_PCI_HOTPLUG, 0, NULL}, 713 * {PCI_CAP_ID_AGP_8X, 0, NULL}, 714 * {PCI_CAP_ID_SECURE_DEV, 0, NULL}, 715 */ 716 {PCI_CAP_NEXT_PTR_NULL, 0, NULL} 717 }; 718 719 /* 720 * Save the configuration registers for cdip as a property 721 * so that it persists after detach/uninitchild. 722 */ 723 int 724 pci_save_config_regs(dev_info_t *dip) 725 { 726 ddi_acc_handle_t confhdl; 727 pci_config_header_state_t *chsp; 728 pci_cap_save_desc_t *pci_cap_descp; 729 int ret; 730 uint32_t i, ncaps, nwords; 731 uint32_t *regbuf, *p; 732 uint8_t *maskbuf; 733 size_t maskbufsz, regbufsz, capbufsz; 734 ddi_acc_hdl_t *hp; 735 off_t offset = 0; 736 uint8_t cap_ptr, cap_id; 737 int pcie = 0; 738 739 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) { 740 cmn_err(CE_WARN, "%s%d can't get config handle", 741 ddi_driver_name(dip), ddi_get_instance(dip)); 742 743 return (DDI_FAILURE); 744 } 745 /* 746 * Determine if it is a pci express device. If it is, save entire 747 * 4k config space treating it as a array of 32 bit integers. 748 * If it is not, do it in a usual PCI way. 749 */ 750 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); 751 /* 752 * Walk the capabilities searching for pci express capability 753 */ 754 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 755 cap_id = pci_config_get8(confhdl, 756 cap_ptr + PCI_CAP_ID); 757 if (cap_id == PCI_CAP_ID_PCI_E) { 758 pcie = 1; 759 break; 760 } 761 cap_ptr = pci_config_get8(confhdl, 762 cap_ptr + PCI_CAP_NEXT_PTR); 763 } 764 765 if (pcie) { 766 /* PCI express device. Can have data in all 4k space */ 767 regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE, 768 KM_SLEEP); 769 p = regbuf; 770 /* 771 * Allocate space for mask. 772 * mask size is 128 bytes (4096 / 4 / 8 ) 773 */ 774 maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >> 775 INDEX_SHIFT); 776 maskbuf = (uint8_t *)kmem_zalloc(maskbufsz, KM_SLEEP); 777 hp = impl_acc_hdl_get(confhdl); 778 for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) { 779 if (ddi_peek32(dip, (int32_t *)(hp->ah_addr + offset), 780 (int32_t *)p) == DDI_SUCCESS) { 781 /* it is readable register. set the bit */ 782 maskbuf[i >> INDEX_SHIFT] |= 783 (uint8_t)(1 << (i & BITMASK)); 784 } 785 p++; 786 offset += sizeof (uint32_t); 787 } 788 789 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 790 SAVED_CONFIG_REGS_MASK, (uchar_t *)maskbuf, 791 maskbufsz)) != DDI_PROP_SUCCESS) { 792 cmn_err(CE_WARN, "couldn't create %s property while" 793 "saving config space for %s@%d\n", 794 SAVED_CONFIG_REGS_MASK, ddi_driver_name(dip), 795 ddi_get_instance(dip)); 796 } else if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, 797 dip, SAVED_CONFIG_REGS, (uchar_t *)regbuf, 798 (size_t)PCIE_CONF_HDR_SIZE)) != DDI_PROP_SUCCESS) { 799 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 800 SAVED_CONFIG_REGS_MASK); 801 cmn_err(CE_WARN, "%s%d can't update prop %s", 802 ddi_driver_name(dip), ddi_get_instance(dip), 803 SAVED_CONFIG_REGS); 804 } 805 806 kmem_free(maskbuf, (size_t)maskbufsz); 807 kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE); 808 } else { 809 regbuf = (uint32_t *)kmem_zalloc((size_t)PCI_CONF_HDR_SIZE, 810 KM_SLEEP); 811 chsp = (pci_config_header_state_t *)regbuf; 812 813 chsp->chs_command = pci_config_get16(confhdl, PCI_CONF_COMM); 814 chsp->chs_header_type = pci_config_get8(confhdl, 815 PCI_CONF_HEADER); 816 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) == 817 PCI_HEADER_ONE) 818 chsp->chs_bridge_control = 819 pci_config_get16(confhdl, PCI_BCNF_BCNTRL); 820 chsp->chs_cache_line_size = pci_config_get8(confhdl, 821 PCI_CONF_CACHE_LINESZ); 822 chsp->chs_latency_timer = pci_config_get8(confhdl, 823 PCI_CONF_LATENCY_TIMER); 824 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) == 825 PCI_HEADER_ONE) { 826 chsp->chs_sec_latency_timer = 827 pci_config_get8(confhdl, PCI_BCNF_LATENCY_TIMER); 828 } 829 830 chsp->chs_base0 = pci_config_get32(confhdl, PCI_CONF_BASE0); 831 chsp->chs_base1 = pci_config_get32(confhdl, PCI_CONF_BASE1); 832 chsp->chs_base2 = pci_config_get32(confhdl, PCI_CONF_BASE2); 833 chsp->chs_base3 = pci_config_get32(confhdl, PCI_CONF_BASE3); 834 chsp->chs_base4 = pci_config_get32(confhdl, PCI_CONF_BASE4); 835 chsp->chs_base5 = pci_config_get32(confhdl, PCI_CONF_BASE5); 836 837 /* 838 * Allocate maximum space required for capability descriptions. 839 * The maximum number of capabilties saved is the number of 840 * capabilities listed in the pci_cap_table. 841 */ 842 ncaps = (sizeof (pci_cap_table) / sizeof (pci_cap_entry_t)); 843 capbufsz = ncaps * sizeof (pci_cap_save_desc_t); 844 pci_cap_descp = (pci_cap_save_desc_t *)kmem_zalloc( 845 capbufsz, KM_SLEEP); 846 p = (uint32_t *)((caddr_t)regbuf + 847 sizeof (pci_config_header_state_t)); 848 nwords = pci_save_caps(confhdl, p, pci_cap_descp, &ncaps); 849 regbufsz = sizeof (pci_config_header_state_t) + 850 nwords * sizeof (uint32_t); 851 852 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 853 SAVED_CONFIG_REGS, (uchar_t *)regbuf, regbufsz)) != 854 DDI_PROP_SUCCESS) { 855 cmn_err(CE_WARN, "%s%d can't update prop %s", 856 ddi_driver_name(dip), ddi_get_instance(dip), 857 SAVED_CONFIG_REGS); 858 } else if (ncaps) { 859 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 860 SAVED_CONFIG_REGS_CAPINFO, (uchar_t *)pci_cap_descp, 861 ncaps * sizeof (pci_cap_save_desc_t)); 862 if (ret != DDI_PROP_SUCCESS) 863 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 864 SAVED_CONFIG_REGS); 865 } 866 kmem_free(regbuf, (size_t)PCI_CONF_HDR_SIZE); 867 kmem_free(pci_cap_descp, capbufsz); 868 } 869 pci_config_teardown(&confhdl); 870 871 if (ret != DDI_PROP_SUCCESS) 872 return (DDI_FAILURE); 873 874 return (DDI_SUCCESS); 875 } 876 877 /* 878 * Saves registers associated with PCI capabilities. 879 * Returns number of 32 bit words saved. 880 * Number of capabilities saved is returned in ncapsp. 881 */ 882 static uint32_t 883 pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 884 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp) 885 { 886 return (cap_walk_and_save(confhdl, regbuf, cap_descp, ncapsp, 0)); 887 } 888 889 static uint32_t 890 cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf, 891 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace) 892 { 893 pci_cap_entry_t *pci_cap_entp; 894 uint16_t cap_id, offset; 895 uint32_t words_saved = 0, nwords = 0; 896 uint16_t cap_ptr = PCI_CAP_NEXT_PTR_NULL; 897 898 *ncapsp = 0; 899 if (!xspace) 900 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); 901 /* 902 * Walk the capabilities 903 */ 904 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 905 cap_id = CAP_ID(confhdl, cap_ptr, xspace); 906 /* Search for this cap id in our table */ 907 if (!xspace) 908 pci_cap_entp = pci_cap_table; 909 while (pci_cap_entp->cap_id != PCI_CAP_NEXT_PTR_NULL && 910 pci_cap_entp->cap_id != cap_id) 911 pci_cap_entp++; 912 913 offset = cap_ptr; 914 cap_ptr = NEXT_CAP(confhdl, cap_ptr, xspace); 915 /* 916 * If this cap id is not found in the table, there is nothing 917 * to save. 918 */ 919 if (pci_cap_entp->cap_id == PCI_CAP_NEXT_PTR_NULL) 920 continue; 921 if (pci_cap_entp->cap_save_func) { 922 if ((nwords = pci_cap_entp->cap_save_func(confhdl, 923 offset, regbuf, pci_cap_entp->cap_ndwords))) { 924 cap_descp->cap_nregs = nwords; 925 cap_descp->cap_offset = offset; 926 cap_descp->cap_id = cap_id; 927 regbuf += nwords; 928 cap_descp++; 929 words_saved += nwords; 930 (*ncapsp)++; 931 } 932 } 933 934 } 935 return (words_saved); 936 } 937 938 static void 939 pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 940 uint32_t *regbuf, uint32_t nwords) 941 { 942 int i; 943 944 for (i = 0; i < nwords; i++) { 945 *regbuf = pci_config_get32(confhdl, cap_ptr); 946 regbuf++; 947 cap_ptr += 4; 948 } 949 } 950 951 static uint32_t 952 pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 953 uint32_t nwords) 954 { 955 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 956 return (nwords); 957 } 958 959 /*ARGSUSED*/ 960 static uint32_t 961 pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 962 uint32_t notused) 963 { 964 uint32_t nwords = PCI_MSI_MIN_WORDS; 965 uint16_t msi_ctrl; 966 967 /* Figure out how many registers to be saved */ 968 msi_ctrl = pci_config_get16(confhdl, cap_ptr + PCI_MSI_CTRL); 969 /* If 64 bit address capable add one word */ 970 if (msi_ctrl & PCI_MSI_64BIT_MASK) 971 nwords++; 972 /* If per vector masking capable, add two more words */ 973 if (msi_ctrl & PCI_MSI_PVM_MASK) 974 nwords += 2; 975 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 976 977 return (nwords); 978 } 979 980 /*ARGSUSED*/ 981 static uint32_t 982 pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 983 uint32_t notused) 984 { 985 uint32_t nwords = PCI_PCIX_MIN_WORDS; 986 uint16_t pcix_command; 987 988 /* Figure out how many registers to be saved */ 989 pcix_command = pci_config_get16(confhdl, cap_ptr + PCI_PCIX_COMMAND); 990 /* If it is version 1 or version 2, add 4 words */ 991 if (((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_1) || 992 ((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2)) 993 nwords += 4; 994 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 995 996 return (nwords); 997 } 998 999 /*ARGSUSED*/ 1000 static uint32_t 1001 pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 1002 uint32_t notused) 1003 { 1004 return (0); 1005 } 1006 1007 static void 1008 pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf, 1009 uint16_t pmcap_offset) 1010 { 1011 uint16_t pmcsr; 1012 uint16_t pmcsr_offset = pmcap_offset + PCI_PMCSR; 1013 uint32_t *saved_pmcsrp = (uint32_t *)((caddr_t)regbuf + PCI_PMCSR); 1014 1015 /* 1016 * Copy the power state bits from the PMCSR to our saved copy. 1017 * This is to make sure that we don't change the D state when 1018 * we restore config space of the device. 1019 */ 1020 pmcsr = pci_config_get16(confhdl, pmcsr_offset); 1021 (*saved_pmcsrp) &= ~PCI_PMCSR_STATE_MASK; 1022 (*saved_pmcsrp) |= (pmcsr & PCI_PMCSR_STATE_MASK); 1023 } 1024 1025 static void 1026 pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 1027 pci_cap_save_desc_t *cap_descp, uint32_t elements) 1028 { 1029 int i, j; 1030 uint16_t offset; 1031 1032 for (i = 0; i < (elements / sizeof (pci_cap_save_desc_t)); i++) { 1033 offset = cap_descp->cap_offset; 1034 if (cap_descp->cap_id == PCI_CAP_ID_PM) 1035 pci_pmcap_check(confhdl, regbuf, offset); 1036 for (j = 0; j < cap_descp->cap_nregs; j++) { 1037 pci_config_put32(confhdl, offset, *regbuf); 1038 regbuf++; 1039 offset += 4; 1040 } 1041 cap_descp++; 1042 } 1043 } 1044 1045 /* 1046 * Restore config_regs from a single devinfo node. 1047 */ 1048 int 1049 pci_restore_config_regs(dev_info_t *dip) 1050 { 1051 ddi_acc_handle_t confhdl; 1052 pci_config_header_state_t *chs_p; 1053 pci_cap_save_desc_t *cap_descp; 1054 uint32_t elements, i; 1055 uint8_t *maskbuf; 1056 uint32_t *regbuf, *p; 1057 off_t offset = 0; 1058 1059 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) { 1060 cmn_err(CE_WARN, "%s%d can't get config handle", 1061 ddi_driver_name(dip), ddi_get_instance(dip)); 1062 return (DDI_FAILURE); 1063 } 1064 1065 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1066 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS_MASK, 1067 (uchar_t **)&maskbuf, &elements) == DDI_PROP_SUCCESS) { 1068 1069 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1070 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS, 1071 (uchar_t **)®buf, &elements) != DDI_PROP_SUCCESS) { 1072 goto restoreconfig_err; 1073 } 1074 ASSERT(elements == PCIE_CONF_HDR_SIZE); 1075 /* pcie device and has 4k config space saved */ 1076 p = regbuf; 1077 for (i = 0; i < PCIE_CONF_HDR_SIZE / sizeof (uint32_t); i++) { 1078 /* If the word is readable then restore it */ 1079 if (maskbuf[i >> INDEX_SHIFT] & 1080 (uint8_t)(1 << (i & BITMASK))) 1081 pci_config_put32(confhdl, offset, *p); 1082 p++; 1083 offset += sizeof (uint32_t); 1084 } 1085 ddi_prop_free(regbuf); 1086 ddi_prop_free(maskbuf); 1087 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, 1088 SAVED_CONFIG_REGS_MASK) != DDI_PROP_SUCCESS) { 1089 cmn_err(CE_WARN, "%s%d can't remove prop %s", 1090 ddi_driver_name(dip), ddi_get_instance(dip), 1091 SAVED_CONFIG_REGS_MASK); 1092 } 1093 } else { 1094 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1095 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS, 1096 (uchar_t **)®buf, &elements) != DDI_PROP_SUCCESS) { 1097 1098 pci_config_teardown(&confhdl); 1099 return (DDI_FAILURE); 1100 } 1101 1102 chs_p = (pci_config_header_state_t *)regbuf; 1103 pci_config_put16(confhdl, PCI_CONF_COMM, 1104 chs_p->chs_command); 1105 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == 1106 PCI_HEADER_ONE) { 1107 pci_config_put16(confhdl, PCI_BCNF_BCNTRL, 1108 chs_p->chs_bridge_control); 1109 } 1110 pci_config_put8(confhdl, PCI_CONF_CACHE_LINESZ, 1111 chs_p->chs_cache_line_size); 1112 pci_config_put8(confhdl, PCI_CONF_LATENCY_TIMER, 1113 chs_p->chs_latency_timer); 1114 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == 1115 PCI_HEADER_ONE) 1116 pci_config_put8(confhdl, PCI_BCNF_LATENCY_TIMER, 1117 chs_p->chs_sec_latency_timer); 1118 1119 pci_config_put32(confhdl, PCI_CONF_BASE0, chs_p->chs_base0); 1120 pci_config_put32(confhdl, PCI_CONF_BASE1, chs_p->chs_base1); 1121 pci_config_put32(confhdl, PCI_CONF_BASE2, chs_p->chs_base2); 1122 pci_config_put32(confhdl, PCI_CONF_BASE3, chs_p->chs_base3); 1123 pci_config_put32(confhdl, PCI_CONF_BASE4, chs_p->chs_base4); 1124 pci_config_put32(confhdl, PCI_CONF_BASE5, chs_p->chs_base5); 1125 1126 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1127 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 1128 SAVED_CONFIG_REGS_CAPINFO, 1129 (uchar_t **)&cap_descp, &elements) == DDI_PROP_SUCCESS) { 1130 /* 1131 * PCI capability related regsiters are saved. 1132 * Restore them based on the description. 1133 */ 1134 p = (uint32_t *)((caddr_t)regbuf + 1135 sizeof (pci_config_header_state_t)); 1136 pci_restore_caps(confhdl, p, cap_descp, elements); 1137 ddi_prop_free(cap_descp); 1138 } 1139 1140 ddi_prop_free(regbuf); 1141 } 1142 1143 /* 1144 * Make sure registers are flushed 1145 */ 1146 (void) pci_config_get32(confhdl, PCI_CONF_BASE5); 1147 1148 1149 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS) != 1150 DDI_PROP_SUCCESS) { 1151 cmn_err(CE_WARN, "%s%d can't remove prop %s", 1152 ddi_driver_name(dip), ddi_get_instance(dip), 1153 SAVED_CONFIG_REGS); 1154 } 1155 1156 pci_config_teardown(&confhdl); 1157 1158 return (DDI_SUCCESS); 1159 1160 restoreconfig_err: 1161 ddi_prop_free(maskbuf); 1162 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK) != 1163 DDI_PROP_SUCCESS) { 1164 cmn_err(CE_WARN, "%s%d can't remove prop %s", 1165 ddi_driver_name(dip), ddi_get_instance(dip), 1166 SAVED_CONFIG_REGS_MASK); 1167 } 1168 pci_config_teardown(&confhdl); 1169 return (DDI_FAILURE); 1170 } 1171