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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 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 #ifdef _LP64 464 uint8_t 465 pci_config_get8(ddi_acc_handle_t handle, off_t offset) 466 #else /* _ILP32 */ 467 uint8_t 468 pci_config_getb(ddi_acc_handle_t handle, off_t offset) 469 #endif 470 { 471 caddr_t cfgaddr; 472 ddi_acc_hdl_t *hp; 473 474 hp = impl_acc_hdl_get(handle); 475 cfgaddr = hp->ah_addr + offset; 476 return (ddi_get8(handle, (uint8_t *)cfgaddr)); 477 } 478 479 #ifdef _LP64 480 uint16_t 481 pci_config_get16(ddi_acc_handle_t handle, off_t offset) 482 #else /* _ILP32 */ 483 uint16_t 484 pci_config_getw(ddi_acc_handle_t handle, off_t offset) 485 #endif 486 { 487 caddr_t cfgaddr; 488 ddi_acc_hdl_t *hp; 489 490 hp = impl_acc_hdl_get(handle); 491 cfgaddr = hp->ah_addr + offset; 492 return (ddi_get16(handle, (uint16_t *)cfgaddr)); 493 } 494 495 #ifdef _LP64 496 uint32_t 497 pci_config_get32(ddi_acc_handle_t handle, off_t offset) 498 #else /* _ILP32 */ 499 uint32_t 500 pci_config_getl(ddi_acc_handle_t handle, off_t offset) 501 #endif 502 { 503 caddr_t cfgaddr; 504 ddi_acc_hdl_t *hp; 505 506 hp = impl_acc_hdl_get(handle); 507 cfgaddr = hp->ah_addr + offset; 508 return (ddi_get32(handle, (uint32_t *)cfgaddr)); 509 } 510 511 #ifdef _LP64 512 uint64_t 513 pci_config_get64(ddi_acc_handle_t handle, off_t offset) 514 #else /* _ILP32 */ 515 uint64_t 516 pci_config_getll(ddi_acc_handle_t handle, off_t offset) 517 #endif 518 { 519 caddr_t cfgaddr; 520 ddi_acc_hdl_t *hp; 521 522 hp = impl_acc_hdl_get(handle); 523 cfgaddr = hp->ah_addr + offset; 524 return (ddi_get64(handle, (uint64_t *)cfgaddr)); 525 } 526 527 #ifdef _LP64 528 void 529 pci_config_put8(ddi_acc_handle_t handle, off_t offset, uint8_t value) 530 #else /* _ILP32 */ 531 void 532 pci_config_putb(ddi_acc_handle_t handle, off_t offset, uint8_t value) 533 #endif 534 { 535 caddr_t cfgaddr; 536 ddi_acc_hdl_t *hp; 537 538 hp = impl_acc_hdl_get(handle); 539 cfgaddr = hp->ah_addr + offset; 540 ddi_put8(handle, (uint8_t *)cfgaddr, value); 541 } 542 543 #ifdef _LP64 544 void 545 pci_config_put16(ddi_acc_handle_t handle, off_t offset, uint16_t value) 546 #else /* _ILP32 */ 547 void 548 pci_config_putw(ddi_acc_handle_t handle, off_t offset, uint16_t value) 549 #endif 550 { 551 caddr_t cfgaddr; 552 ddi_acc_hdl_t *hp; 553 554 hp = impl_acc_hdl_get(handle); 555 cfgaddr = hp->ah_addr + offset; 556 ddi_put16(handle, (uint16_t *)cfgaddr, value); 557 } 558 559 #ifdef _LP64 560 void 561 pci_config_put32(ddi_acc_handle_t handle, off_t offset, uint32_t value) 562 #else /* _ILP32 */ 563 void 564 pci_config_putl(ddi_acc_handle_t handle, off_t offset, uint32_t value) 565 #endif 566 { 567 caddr_t cfgaddr; 568 ddi_acc_hdl_t *hp; 569 570 hp = impl_acc_hdl_get(handle); 571 cfgaddr = hp->ah_addr + offset; 572 ddi_put32(handle, (uint32_t *)cfgaddr, value); 573 } 574 575 #ifdef _LP64 576 void 577 pci_config_put64(ddi_acc_handle_t handle, off_t offset, uint64_t value) 578 #else /* _ILP32 */ 579 void 580 pci_config_putll(ddi_acc_handle_t handle, off_t offset, uint64_t value) 581 #endif 582 { 583 caddr_t cfgaddr; 584 ddi_acc_hdl_t *hp; 585 586 hp = impl_acc_hdl_get(handle); 587 cfgaddr = hp->ah_addr + offset; 588 ddi_put64(handle, (uint64_t *)cfgaddr, value); 589 } 590 591 /*ARGSUSED*/ 592 int 593 pci_report_pmcap(dev_info_t *dip, int cap, void *arg) 594 { 595 return (DDI_SUCCESS); 596 } 597 598 /* 599 * Note about saving and restoring config space. 600 * PCI devices have only upto 256 bytes of config space while PCI Express 601 * devices can have upto 4k config space. In case of PCI Express device, 602 * we save all 4k config space and restore it even if it doesn't make use 603 * of all 4k. But some devices don't respond to reads to non-existent 604 * registers within the config space. To avoid any panics, we use ddi_peek 605 * to do the reads. A bit mask is used to indicate which words of the 606 * config space are accessible. While restoring the config space, only those 607 * readable words are restored. We do all this in 32 bit size words. 608 */ 609 #define INDEX_SHIFT 3 610 #define BITMASK 0x7 611 612 static uint32_t pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 613 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp); 614 static void pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 615 pci_cap_save_desc_t *cap_descp, uint32_t elements); 616 static uint32_t pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 617 uint32_t *regbuf, uint32_t nwords); 618 static uint32_t pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 619 uint32_t *regbuf, uint32_t notused); 620 static uint32_t pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 621 uint32_t *regbuf, uint32_t notused); 622 static uint32_t pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 623 uint32_t *regbuf, uint32_t notused); 624 static void pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 625 uint32_t *regbuf, uint32_t nwords); 626 static uint32_t cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf, 627 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace); 628 static void pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf, 629 uint16_t pmcap_offset); 630 631 /* 632 * Table below specifies the number of registers to be saved for each PCI 633 * capability. pci_generic_save saves the number of words specified in the 634 * table. Any special considerations will be taken care by the capability 635 * specific save function e.g. use pci_msi_save to save registers associated 636 * with MSI capability. PCI_UNKNOWN_SIZE indicates that number of registers 637 * to be saved is variable and will be determined by the specific save function. 638 * Currently we save/restore all the registers associated with the capability 639 * including read only registers. Regsiters are saved and restored in 32 bit 640 * size words. 641 */ 642 static pci_cap_entry_t pci_cap_table[] = { 643 {PCI_CAP_ID_PM, PCI_PMCAP_NDWORDS, pci_generic_save}, 644 {PCI_CAP_ID_AGP, PCI_AGP_NDWORDS, pci_generic_save}, 645 {PCI_CAP_ID_SLOT_ID, PCI_SLOTID_NDWORDS, pci_generic_save}, 646 {PCI_CAP_ID_MSI_X, PCI_MSIX_NDWORDS, pci_generic_save}, 647 {PCI_CAP_ID_MSI, PCI_CAP_SZUNKNOWN, pci_msi_save}, 648 {PCI_CAP_ID_PCIX, PCI_CAP_SZUNKNOWN, pci_pcix_save}, 649 {PCI_CAP_ID_PCI_E, PCI_CAP_SZUNKNOWN, pci_pcie_save}, 650 /* 651 * {PCI_CAP_ID_cPCI_CRC, 0, NULL}, 652 * {PCI_CAP_ID_VPD, 0, NULL}, 653 * {PCI_CAP_ID_cPCI_HS, 0, NULL}, 654 * {PCI_CAP_ID_PCI_HOTPLUG, 0, NULL}, 655 * {PCI_CAP_ID_AGP_8X, 0, NULL}, 656 * {PCI_CAP_ID_SECURE_DEV, 0, NULL}, 657 */ 658 {PCI_CAP_NEXT_PTR_NULL, 0, NULL} 659 }; 660 661 /* 662 * Save the configuration registers for cdip as a property 663 * so that it persists after detach/uninitchild. 664 */ 665 int 666 pci_save_config_regs(dev_info_t *dip) 667 { 668 ddi_acc_handle_t confhdl; 669 pci_config_header_state_t *chsp; 670 pci_cap_save_desc_t *pci_cap_descp; 671 int ret; 672 uint32_t i, ncaps, nwords; 673 uint32_t *regbuf, *p; 674 uint8_t *maskbuf; 675 size_t maskbufsz, regbufsz, capbufsz; 676 ddi_acc_hdl_t *hp; 677 off_t offset = 0; 678 uint8_t cap_ptr, cap_id; 679 int pcie = 0; 680 681 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) { 682 cmn_err(CE_WARN, "%s%d can't get config handle", 683 ddi_driver_name(dip), ddi_get_instance(dip)); 684 685 return (DDI_FAILURE); 686 } 687 /* 688 * Determine if it is a pci express device. If it is, save entire 689 * 4k config space treating it as a array of 32 bit integers. 690 * If it is not, do it in a usual PCI way. 691 */ 692 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); 693 /* 694 * Walk the capabilities searching for pci express capability 695 */ 696 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 697 cap_id = pci_config_get8(confhdl, 698 cap_ptr + PCI_CAP_ID); 699 if (cap_id == PCI_CAP_ID_PCI_E) { 700 pcie = 1; 701 break; 702 } 703 cap_ptr = pci_config_get8(confhdl, 704 cap_ptr + PCI_CAP_NEXT_PTR); 705 } 706 707 if (pcie) { 708 /* PCI express device. Can have data in all 4k space */ 709 regbuf = (uint32_t *)kmem_zalloc((size_t)PCIE_CONF_HDR_SIZE, 710 KM_SLEEP); 711 p = regbuf; 712 /* 713 * Allocate space for mask. 714 * mask size is 128 bytes (4096 / 4 / 8 ) 715 */ 716 maskbufsz = (size_t)((PCIE_CONF_HDR_SIZE/ sizeof (uint32_t)) >> 717 INDEX_SHIFT); 718 maskbuf = (uint8_t *)kmem_zalloc(maskbufsz, KM_SLEEP); 719 hp = impl_acc_hdl_get(confhdl); 720 for (i = 0; i < (PCIE_CONF_HDR_SIZE / sizeof (uint32_t)); i++) { 721 if (ddi_peek32(dip, (int32_t *)(hp->ah_addr + offset), 722 (int32_t *)p) == DDI_SUCCESS) { 723 /* it is readable register. set the bit */ 724 maskbuf[i >> INDEX_SHIFT] |= 725 (uint8_t)(1 << (i & BITMASK)); 726 } 727 p++; 728 offset += sizeof (uint32_t); 729 } 730 731 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 732 SAVED_CONFIG_REGS_MASK, (uchar_t *)maskbuf, 733 maskbufsz)) != DDI_PROP_SUCCESS) { 734 cmn_err(CE_WARN, "couldn't create %s property while" 735 "saving config space for %s@%d\n", 736 SAVED_CONFIG_REGS_MASK, ddi_driver_name(dip), 737 ddi_get_instance(dip)); 738 } else if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, 739 dip, SAVED_CONFIG_REGS, (uchar_t *)regbuf, 740 (size_t)PCIE_CONF_HDR_SIZE)) != DDI_PROP_SUCCESS) { 741 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 742 SAVED_CONFIG_REGS_MASK); 743 cmn_err(CE_WARN, "%s%d can't update prop %s", 744 ddi_driver_name(dip), ddi_get_instance(dip), 745 SAVED_CONFIG_REGS); 746 } 747 748 kmem_free(maskbuf, (size_t)maskbufsz); 749 kmem_free(regbuf, (size_t)PCIE_CONF_HDR_SIZE); 750 } else { 751 regbuf = (uint32_t *)kmem_zalloc((size_t)PCI_CONF_HDR_SIZE, 752 KM_SLEEP); 753 chsp = (pci_config_header_state_t *)regbuf; 754 755 chsp->chs_command = pci_config_get16(confhdl, PCI_CONF_COMM); 756 chsp->chs_header_type = pci_config_get8(confhdl, 757 PCI_CONF_HEADER); 758 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) == 759 PCI_HEADER_ONE) 760 chsp->chs_bridge_control = 761 pci_config_get16(confhdl, PCI_BCNF_BCNTRL); 762 chsp->chs_cache_line_size = pci_config_get8(confhdl, 763 PCI_CONF_CACHE_LINESZ); 764 chsp->chs_latency_timer = pci_config_get8(confhdl, 765 PCI_CONF_LATENCY_TIMER); 766 if ((chsp->chs_header_type & PCI_HEADER_TYPE_M) == 767 PCI_HEADER_ONE) { 768 chsp->chs_sec_latency_timer = 769 pci_config_get8(confhdl, PCI_BCNF_LATENCY_TIMER); 770 } 771 772 chsp->chs_base0 = pci_config_get32(confhdl, PCI_CONF_BASE0); 773 chsp->chs_base1 = pci_config_get32(confhdl, PCI_CONF_BASE1); 774 chsp->chs_base2 = pci_config_get32(confhdl, PCI_CONF_BASE2); 775 chsp->chs_base3 = pci_config_get32(confhdl, PCI_CONF_BASE3); 776 chsp->chs_base4 = pci_config_get32(confhdl, PCI_CONF_BASE4); 777 chsp->chs_base5 = pci_config_get32(confhdl, PCI_CONF_BASE5); 778 779 /* 780 * Allocate maximum space required for capability descriptions. 781 * The maximum number of capabilties saved is the number of 782 * capabilities listed in the pci_cap_table. 783 */ 784 ncaps = (sizeof (pci_cap_table) / sizeof (pci_cap_entry_t)); 785 capbufsz = ncaps * sizeof (pci_cap_save_desc_t); 786 pci_cap_descp = (pci_cap_save_desc_t *)kmem_zalloc( 787 capbufsz, KM_SLEEP); 788 p = (uint32_t *)((caddr_t)regbuf + 789 sizeof (pci_config_header_state_t)); 790 nwords = pci_save_caps(confhdl, p, pci_cap_descp, &ncaps); 791 regbufsz = sizeof (pci_config_header_state_t) + 792 nwords * sizeof (uint32_t); 793 794 if ((ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 795 SAVED_CONFIG_REGS, (uchar_t *)regbuf, regbufsz)) != 796 DDI_PROP_SUCCESS) { 797 cmn_err(CE_WARN, "%s%d can't update prop %s", 798 ddi_driver_name(dip), ddi_get_instance(dip), 799 SAVED_CONFIG_REGS); 800 } else if (ncaps) { 801 ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, 802 SAVED_CONFIG_REGS_CAPINFO, (uchar_t *)pci_cap_descp, 803 ncaps * sizeof (pci_cap_save_desc_t)); 804 if (ret != DDI_PROP_SUCCESS) 805 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 806 SAVED_CONFIG_REGS); 807 } 808 kmem_free(regbuf, (size_t)PCI_CONF_HDR_SIZE); 809 kmem_free(pci_cap_descp, capbufsz); 810 } 811 pci_config_teardown(&confhdl); 812 813 if (ret != DDI_PROP_SUCCESS) 814 return (DDI_FAILURE); 815 816 return (DDI_SUCCESS); 817 } 818 819 /* 820 * Saves registers associated with PCI capabilities. 821 * Returns number of 32 bit words saved. 822 * Number of capabilities saved is returned in ncapsp. 823 */ 824 static uint32_t 825 pci_save_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 826 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp) 827 { 828 return (cap_walk_and_save(confhdl, regbuf, cap_descp, ncapsp, 0)); 829 } 830 831 static uint32_t 832 cap_walk_and_save(ddi_acc_handle_t confhdl, uint32_t *regbuf, 833 pci_cap_save_desc_t *cap_descp, uint32_t *ncapsp, int xspace) 834 { 835 pci_cap_entry_t *pci_cap_entp; 836 uint16_t cap_id, offset; 837 uint32_t words_saved = 0, nwords = 0; 838 uint16_t cap_ptr = PCI_CAP_NEXT_PTR_NULL; 839 840 *ncapsp = 0; 841 if (!xspace) 842 cap_ptr = pci_config_get8(confhdl, PCI_BCNF_CAP_PTR); 843 /* 844 * Walk the capabilities 845 */ 846 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 847 cap_id = CAP_ID(confhdl, cap_ptr, xspace); 848 /* Search for this cap id in our table */ 849 if (!xspace) 850 pci_cap_entp = pci_cap_table; 851 while (pci_cap_entp->cap_id != PCI_CAP_NEXT_PTR_NULL && 852 pci_cap_entp->cap_id != cap_id) 853 pci_cap_entp++; 854 855 offset = cap_ptr; 856 cap_ptr = NEXT_CAP(confhdl, cap_ptr, xspace); 857 /* 858 * If this cap id is not found in the table, there is nothing 859 * to save. 860 */ 861 if (pci_cap_entp->cap_id == PCI_CAP_NEXT_PTR_NULL) 862 continue; 863 if (pci_cap_entp->cap_save_func) { 864 if ((nwords = pci_cap_entp->cap_save_func(confhdl, 865 offset, regbuf, pci_cap_entp->cap_ndwords))) { 866 cap_descp->cap_nregs = nwords; 867 cap_descp->cap_offset = offset; 868 cap_descp->cap_id = cap_id; 869 regbuf += nwords; 870 cap_descp++; 871 words_saved += nwords; 872 (*ncapsp)++; 873 } 874 } 875 876 } 877 return (words_saved); 878 } 879 880 static void 881 pci_fill_buf(ddi_acc_handle_t confhdl, uint16_t cap_ptr, 882 uint32_t *regbuf, uint32_t nwords) 883 { 884 int i; 885 886 for (i = 0; i < nwords; i++) { 887 *regbuf = pci_config_get32(confhdl, cap_ptr); 888 regbuf++; 889 cap_ptr += 4; 890 } 891 } 892 893 static uint32_t 894 pci_generic_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 895 uint32_t nwords) 896 { 897 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 898 return (nwords); 899 } 900 901 /*ARGSUSED*/ 902 static uint32_t 903 pci_msi_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 904 uint32_t notused) 905 { 906 uint32_t nwords = PCI_MSI_MIN_WORDS; 907 uint16_t msi_ctrl; 908 909 /* Figure out how many registers to be saved */ 910 msi_ctrl = pci_config_get16(confhdl, cap_ptr + PCI_MSI_CTRL); 911 /* If 64 bit address capable add one word */ 912 if (msi_ctrl & PCI_MSI_64BIT_MASK) 913 nwords++; 914 /* If per vector masking capable, add two more words */ 915 if (msi_ctrl & PCI_MSI_PVM_MASK) 916 nwords += 2; 917 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 918 919 return (nwords); 920 } 921 922 /*ARGSUSED*/ 923 static uint32_t 924 pci_pcix_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 925 uint32_t notused) 926 { 927 uint32_t nwords = PCI_PCIX_MIN_WORDS; 928 uint16_t pcix_command; 929 930 /* Figure out how many registers to be saved */ 931 pcix_command = pci_config_get16(confhdl, cap_ptr + PCI_PCIX_COMMAND); 932 /* If it is version 1 or version 2, add 4 words */ 933 if (((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_1) || 934 ((pcix_command & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2)) 935 nwords += 4; 936 pci_fill_buf(confhdl, cap_ptr, regbuf, nwords); 937 938 return (nwords); 939 } 940 941 /*ARGSUSED*/ 942 static uint32_t 943 pci_pcie_save(ddi_acc_handle_t confhdl, uint16_t cap_ptr, uint32_t *regbuf, 944 uint32_t notused) 945 { 946 return (0); 947 } 948 949 static void 950 pci_pmcap_check(ddi_acc_handle_t confhdl, uint32_t *regbuf, 951 uint16_t pmcap_offset) 952 { 953 uint16_t pmcsr; 954 uint16_t pmcsr_offset = pmcap_offset + PCI_PMCSR; 955 uint32_t *saved_pmcsrp = (uint32_t *)((caddr_t)regbuf + PCI_PMCSR); 956 957 /* 958 * Copy the power state bits from the PMCSR to our saved copy. 959 * This is to make sure that we don't change the D state when 960 * we restore config space of the device. 961 */ 962 pmcsr = pci_config_get16(confhdl, pmcsr_offset); 963 (*saved_pmcsrp) &= ~PCI_PMCSR_STATE_MASK; 964 (*saved_pmcsrp) |= (pmcsr & PCI_PMCSR_STATE_MASK); 965 } 966 967 static void 968 pci_restore_caps(ddi_acc_handle_t confhdl, uint32_t *regbuf, 969 pci_cap_save_desc_t *cap_descp, uint32_t elements) 970 { 971 int i, j; 972 uint16_t offset; 973 974 for (i = 0; i < (elements / sizeof (pci_cap_save_desc_t)); i++) { 975 offset = cap_descp->cap_offset; 976 if (cap_descp->cap_id == PCI_CAP_ID_PM) 977 pci_pmcap_check(confhdl, regbuf, offset); 978 for (j = 0; j < cap_descp->cap_nregs; j++) { 979 pci_config_put32(confhdl, offset, *regbuf); 980 regbuf++; 981 offset += 4; 982 } 983 cap_descp++; 984 } 985 } 986 987 /* 988 * Restore config_regs from a single devinfo node. 989 */ 990 int 991 pci_restore_config_regs(dev_info_t *dip) 992 { 993 ddi_acc_handle_t confhdl; 994 pci_config_header_state_t *chs_p; 995 pci_cap_save_desc_t *cap_descp; 996 uint32_t elements, i; 997 uint8_t *maskbuf; 998 uint32_t *regbuf, *p; 999 off_t offset = 0; 1000 1001 if (pci_config_setup(dip, &confhdl) != DDI_SUCCESS) { 1002 cmn_err(CE_WARN, "%s%d can't get config handle", 1003 ddi_driver_name(dip), ddi_get_instance(dip)); 1004 return (DDI_FAILURE); 1005 } 1006 1007 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1008 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS_MASK, 1009 (uchar_t **)&maskbuf, &elements) == DDI_PROP_SUCCESS) { 1010 1011 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1012 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS, 1013 (uchar_t **)®buf, &elements) != DDI_PROP_SUCCESS) { 1014 goto restoreconfig_err; 1015 } 1016 ASSERT(elements == PCIE_CONF_HDR_SIZE); 1017 /* pcie device and has 4k config space saved */ 1018 p = regbuf; 1019 for (i = 0; i < PCIE_CONF_HDR_SIZE / sizeof (uint32_t); i++) { 1020 /* If the word is readable then restore it */ 1021 if (maskbuf[i >> INDEX_SHIFT] & 1022 (uint8_t)(1 << (i & BITMASK))) 1023 pci_config_put32(confhdl, offset, *p); 1024 p++; 1025 offset += sizeof (uint32_t); 1026 } 1027 ddi_prop_free(regbuf); 1028 ddi_prop_free(maskbuf); 1029 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, 1030 SAVED_CONFIG_REGS_MASK) != DDI_PROP_SUCCESS) { 1031 cmn_err(CE_WARN, "%s%d can't remove prop %s", 1032 ddi_driver_name(dip), ddi_get_instance(dip), 1033 SAVED_CONFIG_REGS_MASK); 1034 } 1035 } else { 1036 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1037 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, SAVED_CONFIG_REGS, 1038 (uchar_t **)®buf, &elements) != DDI_PROP_SUCCESS) { 1039 1040 pci_config_teardown(&confhdl); 1041 return (DDI_FAILURE); 1042 } 1043 1044 chs_p = (pci_config_header_state_t *)regbuf; 1045 pci_config_put16(confhdl, PCI_CONF_COMM, 1046 chs_p->chs_command); 1047 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == 1048 PCI_HEADER_ONE) { 1049 pci_config_put16(confhdl, PCI_BCNF_BCNTRL, 1050 chs_p->chs_bridge_control); 1051 } 1052 pci_config_put8(confhdl, PCI_CONF_CACHE_LINESZ, 1053 chs_p->chs_cache_line_size); 1054 pci_config_put8(confhdl, PCI_CONF_LATENCY_TIMER, 1055 chs_p->chs_latency_timer); 1056 if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == 1057 PCI_HEADER_ONE) 1058 pci_config_put8(confhdl, PCI_BCNF_LATENCY_TIMER, 1059 chs_p->chs_sec_latency_timer); 1060 1061 pci_config_put32(confhdl, PCI_CONF_BASE0, chs_p->chs_base0); 1062 pci_config_put32(confhdl, PCI_CONF_BASE1, chs_p->chs_base1); 1063 pci_config_put32(confhdl, PCI_CONF_BASE2, chs_p->chs_base2); 1064 pci_config_put32(confhdl, PCI_CONF_BASE3, chs_p->chs_base3); 1065 pci_config_put32(confhdl, PCI_CONF_BASE4, chs_p->chs_base4); 1066 pci_config_put32(confhdl, PCI_CONF_BASE5, chs_p->chs_base5); 1067 1068 if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, 1069 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 1070 SAVED_CONFIG_REGS_CAPINFO, 1071 (uchar_t **)&cap_descp, &elements) == DDI_PROP_SUCCESS) { 1072 /* 1073 * PCI capability related regsiters are saved. 1074 * Restore them based on the description. 1075 */ 1076 p = (uint32_t *)((caddr_t)regbuf + 1077 sizeof (pci_config_header_state_t)); 1078 pci_restore_caps(confhdl, p, cap_descp, elements); 1079 ddi_prop_free(cap_descp); 1080 } 1081 1082 ddi_prop_free(regbuf); 1083 } 1084 1085 /* 1086 * Make sure registers are flushed 1087 */ 1088 (void) pci_config_get32(confhdl, PCI_CONF_BASE5); 1089 1090 1091 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS) != 1092 DDI_PROP_SUCCESS) { 1093 cmn_err(CE_WARN, "%s%d can't remove prop %s", 1094 ddi_driver_name(dip), ddi_get_instance(dip), 1095 SAVED_CONFIG_REGS); 1096 } 1097 1098 pci_config_teardown(&confhdl); 1099 1100 return (DDI_SUCCESS); 1101 1102 restoreconfig_err: 1103 ddi_prop_free(maskbuf); 1104 if (ndi_prop_remove(DDI_DEV_T_NONE, dip, SAVED_CONFIG_REGS_MASK) != 1105 DDI_PROP_SUCCESS) { 1106 cmn_err(CE_WARN, "%s%d can't remove prop %s", 1107 ddi_driver_name(dip), ddi_get_instance(dip), 1108 SAVED_CONFIG_REGS_MASK); 1109 } 1110 pci_config_teardown(&confhdl); 1111 return (DDI_FAILURE); 1112 } 1113