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 2007 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 /* 30 * File that has code which is common between pci(7d) and npe(7d) 31 * It shares the following: 32 * - interrupt code 33 * - pci_tools ioctl code 34 * - name_child code 35 * - set_parent_private_data code 36 */ 37 38 #include <sys/conf.h> 39 #include <sys/pci.h> 40 #include <sys/sunndi.h> 41 #include <sys/mach_intr.h> 42 #include <sys/hotplug/pci/pcihp.h> 43 #include <sys/pci_intr_lib.h> 44 #include <sys/psm.h> 45 #include <sys/policy.h> 46 #include <sys/sysmacros.h> 47 #include <sys/clock.h> 48 #include <sys/apic.h> 49 #include <sys/pci_tools.h> 50 #include <io/pci/pci_var.h> 51 #include <io/pci/pci_tools_ext.h> 52 #include <io/pci/pci_common.h> 53 #include <sys/pci_cfgspace.h> 54 #include <sys/pci_impl.h> 55 #include <sys/pci_cap.h> 56 57 /* 58 * Function prototypes 59 */ 60 static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 61 static int pci_enable_intr(dev_info_t *, dev_info_t *, 62 ddi_intr_handle_impl_t *, uint32_t); 63 static void pci_disable_intr(dev_info_t *, dev_info_t *, 64 ddi_intr_handle_impl_t *, uint32_t); 65 66 /* Extern decalration for pcplusmp module */ 67 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 68 psm_intr_op_t, int *); 69 70 71 /* 72 * pci_name_child: 73 * 74 * Assign the address portion of the node name 75 */ 76 int 77 pci_common_name_child(dev_info_t *child, char *name, int namelen) 78 { 79 int dev, func, length; 80 char **unit_addr; 81 uint_t n; 82 pci_regspec_t *pci_rp; 83 84 if (ndi_dev_is_persistent_node(child) == 0) { 85 /* 86 * For .conf node, use "unit-address" property 87 */ 88 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 89 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 90 DDI_PROP_SUCCESS) { 91 cmn_err(CE_WARN, "cannot find unit-address in %s.conf", 92 ddi_get_name(child)); 93 return (DDI_FAILURE); 94 } 95 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 96 cmn_err(CE_WARN, "unit-address property in %s.conf" 97 " not well-formed", ddi_get_name(child)); 98 ddi_prop_free(unit_addr); 99 return (DDI_FAILURE); 100 } 101 (void) snprintf(name, namelen, "%s", *unit_addr); 102 ddi_prop_free(unit_addr); 103 return (DDI_SUCCESS); 104 } 105 106 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 107 "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { 108 cmn_err(CE_WARN, "cannot find reg property in %s", 109 ddi_get_name(child)); 110 return (DDI_FAILURE); 111 } 112 113 /* copy the device identifications */ 114 dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 115 func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 116 117 /* 118 * free the memory allocated by ddi_prop_lookup_int_array 119 */ 120 ddi_prop_free(pci_rp); 121 122 if (func != 0) { 123 (void) snprintf(name, namelen, "%x,%x", dev, func); 124 } else { 125 (void) snprintf(name, namelen, "%x", dev); 126 } 127 128 return (DDI_SUCCESS); 129 } 130 131 /* 132 * Interrupt related code: 133 * 134 * The following busop is common to npe and pci drivers 135 * bus_introp 136 */ 137 138 /* 139 * Create the ddi_parent_private_data for a pseudo child. 140 */ 141 void 142 pci_common_set_parent_private_data(dev_info_t *dip) 143 { 144 struct ddi_parent_private_data *pdptr; 145 146 pdptr = (struct ddi_parent_private_data *)kmem_zalloc( 147 (sizeof (struct ddi_parent_private_data) + 148 sizeof (struct intrspec)), KM_SLEEP); 149 pdptr->par_intr = (struct intrspec *)(pdptr + 1); 150 pdptr->par_nintr = 1; 151 ddi_set_parent_data(dip, pdptr); 152 } 153 154 /* 155 * pci_get_priority: 156 * Figure out the priority of the device 157 */ 158 static int 159 pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri) 160 { 161 struct intrspec *ispec; 162 163 DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n", 164 (void *)dip, (void *)hdlp)); 165 166 if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 167 hdlp->ih_inum)) == NULL) { 168 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 169 int class = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 170 DDI_PROP_DONTPASS, "class-code", -1); 171 172 *pri = (class == -1) ? 1 : pci_devclass_to_ipl(class); 173 pci_common_set_parent_private_data(hdlp->ih_dip); 174 ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 175 hdlp->ih_inum); 176 return (DDI_SUCCESS); 177 } 178 return (DDI_FAILURE); 179 } 180 181 *pri = ispec->intrspec_pri; 182 return (DDI_SUCCESS); 183 } 184 185 186 187 static int pcie_pci_intr_pri_counter = 0; 188 189 /* 190 * pci_common_intr_ops: bus_intr_op() function for interrupt support 191 */ 192 int 193 pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 194 ddi_intr_handle_impl_t *hdlp, void *result) 195 { 196 int priority = 0; 197 int psm_status = 0; 198 int pci_status = 0; 199 int pci_rval, psm_rval = PSM_FAILURE; 200 int types = 0; 201 int pciepci = 0; 202 int i, j, count; 203 int rv; 204 int behavior; 205 int cap_ptr; 206 uint16_t msi_cap_base, msix_cap_base, cap_ctrl; 207 char *prop; 208 ddi_intrspec_t isp; 209 struct intrspec *ispec; 210 ddi_intr_handle_impl_t tmp_hdl; 211 ddi_intr_msix_t *msix_p; 212 ihdl_plat_t *ihdl_plat_datap; 213 ddi_intr_handle_t *h_array; 214 ddi_acc_handle_t handle; 215 216 DDI_INTR_NEXDBG((CE_CONT, 217 "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 218 (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 219 220 /* Process the request */ 221 switch (intr_op) { 222 case DDI_INTROP_SUPPORTED_TYPES: 223 /* 224 * First we determine the interrupt types supported by the 225 * device itself, then we filter them through what the OS 226 * and system supports. We determine system-level 227 * interrupt type support for anything other than fixed intrs 228 * through the psm_intr_ops vector 229 */ 230 rv = DDI_FAILURE; 231 232 /* Fixed supported by default */ 233 types = DDI_INTR_TYPE_FIXED; 234 235 if (psm_intr_ops == NULL) { 236 *(int *)result = types; 237 return (DDI_SUCCESS); 238 } 239 if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) 240 return (DDI_FAILURE); 241 242 /* Sanity test cap control values if found */ 243 244 if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == 245 DDI_SUCCESS) { 246 cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, 247 PCI_MSI_CTRL); 248 if (cap_ctrl == PCI_CAP_EINVAL16) 249 goto SUPPORTED_TYPES_OUT; 250 251 types |= DDI_INTR_TYPE_MSI; 252 } 253 254 if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == 255 DDI_SUCCESS) { 256 cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, 257 PCI_MSIX_CTRL); 258 if (cap_ctrl == PCI_CAP_EINVAL16) 259 goto SUPPORTED_TYPES_OUT; 260 261 types |= DDI_INTR_TYPE_MSIX; 262 } 263 264 /* 265 * Filter device-level types through system-level support 266 */ 267 tmp_hdl.ih_type = types; 268 if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, 269 &types) != PSM_SUCCESS) 270 goto SUPPORTED_TYPES_OUT; 271 272 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 273 "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 274 *(int *)result)); 275 276 /* 277 * Export any MSI/MSI-X cap locations via properties 278 */ 279 if (types & DDI_INTR_TYPE_MSI) { 280 if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 281 "pci-msi-capid-pointer", (int)msi_cap_base) != 282 DDI_PROP_SUCCESS) 283 goto SUPPORTED_TYPES_OUT; 284 } 285 if (types & DDI_INTR_TYPE_MSIX) { 286 if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 287 "pci-msix-capid-pointer", (int)msix_cap_base) != 288 DDI_PROP_SUCCESS) 289 goto SUPPORTED_TYPES_OUT; 290 } 291 292 rv = DDI_SUCCESS; 293 294 SUPPORTED_TYPES_OUT: 295 *(int *)result = types; 296 pci_config_teardown(&handle); 297 return (rv); 298 299 case DDI_INTROP_NAVAIL: 300 case DDI_INTROP_NINTRS: 301 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 302 if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type, 303 result) != DDI_SUCCESS) 304 return (DDI_FAILURE); 305 } else { 306 *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip); 307 if (*(int *)result == 0) 308 return (DDI_FAILURE); 309 } 310 break; 311 case DDI_INTROP_ALLOC: 312 /* 313 * MSI or MSIX (figure out number of vectors available) 314 * FIXED interrupts: just return available interrupts 315 */ 316 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 317 (psm_intr_ops != NULL) && 318 (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 319 /* 320 * Following check is a special case for 'pcie_pci'. 321 * This makes sure vectors with the right priority 322 * are allocated for pcie_pci during ALLOC time. 323 */ 324 if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) { 325 hdlp->ih_pri = 326 (pcie_pci_intr_pri_counter % 2) ? 4 : 7; 327 pciepci = 1; 328 } else 329 hdlp->ih_pri = priority; 330 behavior = (int)(uintptr_t)hdlp->ih_scratch2; 331 332 /* 333 * Cache in the config handle and cap_ptr 334 */ 335 if (i_ddi_get_pci_config_handle(rdip) == NULL) { 336 if (pci_config_setup(rdip, &handle) != 337 DDI_SUCCESS) 338 return (DDI_FAILURE); 339 i_ddi_set_pci_config_handle(rdip, handle); 340 } 341 342 prop = NULL; 343 cap_ptr = 0; 344 if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 345 prop = "pci-msi-capid-pointer"; 346 else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) 347 prop = "pci-msix-capid-pointer"; 348 349 /* 350 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES 351 * for MSI(X) before allocation 352 */ 353 if (prop != NULL) { 354 cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 355 DDI_PROP_DONTPASS, prop, 0); 356 if (cap_ptr == 0) { 357 DDI_INTR_NEXDBG((CE_CONT, 358 "pci_common_intr_ops: rdip: 0x%p " 359 "attempted MSI(X) alloc without " 360 "cap property\n", (void *)rdip)); 361 return (DDI_FAILURE); 362 } 363 } 364 i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 365 366 /* 367 * Allocate interrupt vectors 368 */ 369 (void) (*psm_intr_ops)(rdip, hdlp, 370 PSM_INTR_OP_ALLOC_VECTORS, result); 371 372 if (*(int *)result == 0) 373 return (DDI_INTR_NOTFOUND); 374 375 /* verify behavior flag and take appropriate action */ 376 if ((behavior == DDI_INTR_ALLOC_STRICT) && 377 (*(int *)result < hdlp->ih_scratch1)) { 378 DDI_INTR_NEXDBG((CE_CONT, 379 "pci_common_intr_ops: behavior %x, " 380 "couldn't get enough intrs\n", behavior)); 381 hdlp->ih_scratch1 = *(int *)result; 382 (void) (*psm_intr_ops)(rdip, hdlp, 383 PSM_INTR_OP_FREE_VECTORS, NULL); 384 return (DDI_EAGAIN); 385 } 386 387 if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 388 if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 389 msix_p = pci_msix_init(hdlp->ih_dip); 390 if (msix_p) 391 i_ddi_set_msix(hdlp->ih_dip, 392 msix_p); 393 } 394 } 395 396 if (pciepci) { 397 /* update priority in ispec */ 398 isp = pci_intx_get_ispec(pdip, rdip, 399 (int)hdlp->ih_inum); 400 ispec = (struct intrspec *)isp; 401 if (ispec) 402 ispec->intrspec_pri = hdlp->ih_pri; 403 ++pcie_pci_intr_pri_counter; 404 } 405 406 } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 407 /* Figure out if this device supports MASKING */ 408 pci_rval = pci_intx_get_cap(rdip, &pci_status); 409 if (pci_rval == DDI_SUCCESS && pci_status) 410 hdlp->ih_cap |= pci_status; 411 *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 412 } else 413 return (DDI_FAILURE); 414 break; 415 case DDI_INTROP_FREE: 416 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 417 (psm_intr_ops != NULL)) { 418 if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 == 419 0) { 420 if (handle = i_ddi_get_pci_config_handle( 421 rdip)) { 422 (void) pci_config_teardown(&handle); 423 i_ddi_set_pci_config_handle(rdip, NULL); 424 } 425 if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 426 i_ddi_set_msi_msix_cap_ptr(rdip, 0); 427 } 428 429 (void) (*psm_intr_ops)(rdip, hdlp, 430 PSM_INTR_OP_FREE_VECTORS, NULL); 431 432 if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 433 msix_p = i_ddi_get_msix(hdlp->ih_dip); 434 if (msix_p && 435 (i_ddi_intr_get_current_nintrs( 436 hdlp->ih_dip) - 1) == 0) { 437 pci_msix_fini(msix_p); 438 i_ddi_set_msix(hdlp->ih_dip, NULL); 439 } 440 } 441 } 442 break; 443 case DDI_INTROP_GETPRI: 444 /* Get the priority */ 445 if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 446 return (DDI_FAILURE); 447 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 448 "priority = 0x%x\n", priority)); 449 *(int *)result = priority; 450 break; 451 case DDI_INTROP_SETPRI: 452 /* Validate the interrupt priority passed */ 453 if (*(int *)result > LOCK_LEVEL) 454 return (DDI_FAILURE); 455 456 /* Ensure that PSM is all initialized */ 457 if (psm_intr_ops == NULL) 458 return (DDI_FAILURE); 459 460 /* Change the priority */ 461 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 462 PSM_FAILURE) 463 return (DDI_FAILURE); 464 465 /* update ispec */ 466 isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 467 ispec = (struct intrspec *)isp; 468 if (ispec) 469 ispec->intrspec_pri = *(int *)result; 470 break; 471 case DDI_INTROP_ADDISR: 472 /* update ispec */ 473 isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 474 ispec = (struct intrspec *)isp; 475 if (ispec) { 476 ispec->intrspec_func = hdlp->ih_cb_func; 477 ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 478 pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 479 } 480 break; 481 case DDI_INTROP_REMISR: 482 /* Get the interrupt structure pointer */ 483 isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 484 ispec = (struct intrspec *)isp; 485 if (ispec) { 486 ispec->intrspec_func = (uint_t (*)()) 0; 487 ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 488 if (ihdl_plat_datap->ip_ksp != NULL) 489 pci_kstat_delete(ihdl_plat_datap->ip_ksp); 490 } 491 break; 492 case DDI_INTROP_GETCAP: 493 /* 494 * First check the config space and/or 495 * MSI capability register(s) 496 */ 497 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 498 pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 499 &pci_status); 500 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 501 pci_rval = pci_intx_get_cap(rdip, &pci_status); 502 503 /* next check with pcplusmp */ 504 if (psm_intr_ops != NULL) 505 psm_rval = (*psm_intr_ops)(rdip, hdlp, 506 PSM_INTR_OP_GET_CAP, &psm_status); 507 508 DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 509 "psm_status = %x, pci_rval = %x, pci_status = %x\n", 510 psm_rval, psm_status, pci_rval, pci_status)); 511 512 if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 513 *(int *)result = 0; 514 return (DDI_FAILURE); 515 } 516 517 if (psm_rval == PSM_SUCCESS) 518 *(int *)result = psm_status; 519 520 if (pci_rval == DDI_SUCCESS) 521 *(int *)result |= pci_status; 522 523 DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 524 *(int *)result)); 525 break; 526 case DDI_INTROP_SETCAP: 527 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 528 "SETCAP cap=0x%x\n", *(int *)result)); 529 if (psm_intr_ops == NULL) 530 return (DDI_FAILURE); 531 532 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 533 DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 534 " returned failure\n")); 535 return (DDI_FAILURE); 536 } 537 break; 538 case DDI_INTROP_ENABLE: 539 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 540 if (psm_intr_ops == NULL) 541 return (DDI_FAILURE); 542 543 if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 544 DDI_SUCCESS) 545 return (DDI_FAILURE); 546 547 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 548 "vector=0x%x\n", hdlp->ih_vector)); 549 break; 550 case DDI_INTROP_DISABLE: 551 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 552 if (psm_intr_ops == NULL) 553 return (DDI_FAILURE); 554 555 pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 556 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 557 "vector = %x\n", hdlp->ih_vector)); 558 break; 559 case DDI_INTROP_BLOCKENABLE: 560 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 561 "BLOCKENABLE\n")); 562 if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 563 DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 564 return (DDI_FAILURE); 565 } 566 567 /* Check if psm_intr_ops is NULL? */ 568 if (psm_intr_ops == NULL) 569 return (DDI_FAILURE); 570 571 count = hdlp->ih_scratch1; 572 h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 573 for (i = 0; i < count; i++) { 574 hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 575 if (pci_enable_intr(pdip, rdip, hdlp, 576 hdlp->ih_inum) != DDI_SUCCESS) { 577 DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 578 "pci_enable_intr failed for %d\n", i)); 579 for (j = 0; j < i; j++) { 580 hdlp = (ddi_intr_handle_impl_t *) 581 h_array[j]; 582 pci_disable_intr(pdip, rdip, hdlp, 583 hdlp->ih_inum); 584 } 585 return (DDI_FAILURE); 586 } 587 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 588 "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 589 } 590 break; 591 case DDI_INTROP_BLOCKDISABLE: 592 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 593 "BLOCKDISABLE\n")); 594 if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 595 DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 596 return (DDI_FAILURE); 597 } 598 599 /* Check if psm_intr_ops is present */ 600 if (psm_intr_ops == NULL) 601 return (DDI_FAILURE); 602 603 count = hdlp->ih_scratch1; 604 h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 605 for (i = 0; i < count; i++) { 606 hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 607 pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 608 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 609 "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 610 } 611 break; 612 case DDI_INTROP_SETMASK: 613 case DDI_INTROP_CLRMASK: 614 /* 615 * First handle in the config space 616 */ 617 if (intr_op == DDI_INTROP_SETMASK) { 618 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 619 pci_status = pci_msi_set_mask(rdip, 620 hdlp->ih_type, hdlp->ih_inum); 621 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 622 pci_status = pci_intx_set_mask(rdip); 623 } else { 624 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 625 pci_status = pci_msi_clr_mask(rdip, 626 hdlp->ih_type, hdlp->ih_inum); 627 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 628 pci_status = pci_intx_clr_mask(rdip); 629 } 630 631 /* For MSI/X; no need to check with pcplusmp */ 632 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 633 return (pci_status); 634 635 /* For fixed interrupts only: handle config space first */ 636 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 637 pci_status == DDI_SUCCESS) 638 break; 639 640 /* For fixed interrupts only: confer with pcplusmp next */ 641 if (psm_intr_ops != NULL) { 642 /* If interrupt is shared; do nothing */ 643 psm_rval = (*psm_intr_ops)(rdip, hdlp, 644 PSM_INTR_OP_GET_SHARED, &psm_status); 645 646 if (psm_rval == PSM_FAILURE || psm_status == 1) 647 return (pci_status); 648 649 /* Now, pcplusmp should try to set/clear the mask */ 650 if (intr_op == DDI_INTROP_SETMASK) 651 psm_rval = (*psm_intr_ops)(rdip, hdlp, 652 PSM_INTR_OP_SET_MASK, NULL); 653 else 654 psm_rval = (*psm_intr_ops)(rdip, hdlp, 655 PSM_INTR_OP_CLEAR_MASK, NULL); 656 } 657 return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 658 case DDI_INTROP_GETPENDING: 659 /* 660 * First check the config space and/or 661 * MSI capability register(s) 662 */ 663 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 664 pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 665 hdlp->ih_inum, &pci_status); 666 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 667 pci_rval = pci_intx_get_pending(rdip, &pci_status); 668 669 /* On failure; next try with pcplusmp */ 670 if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 671 psm_rval = (*psm_intr_ops)(rdip, hdlp, 672 PSM_INTR_OP_GET_PENDING, &psm_status); 673 674 DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 675 "psm_rval = %x, psm_status = %x, pci_rval = %x, " 676 "pci_status = %x\n", psm_rval, psm_status, pci_rval, 677 pci_status)); 678 if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 679 *(int *)result = 0; 680 return (DDI_FAILURE); 681 } 682 683 if (psm_rval != PSM_FAILURE) 684 *(int *)result = psm_status; 685 else if (pci_rval != DDI_FAILURE) 686 *(int *)result = pci_status; 687 DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 688 *(int *)result)); 689 break; 690 default: 691 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 692 } 693 694 return (DDI_SUCCESS); 695 } 696 697 int 698 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 699 int vecirq, boolean_t is_irq) 700 { 701 ddi_intr_handle_impl_t get_info_ii_hdl; 702 703 if (is_irq) 704 intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 705 706 /* 707 * For this locally-declared and used handle, ih_private will contain a 708 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 709 * global interrupt handling. 710 */ 711 get_info_ii_hdl.ih_private = intrinfo_p; 712 get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 713 714 if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 715 PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 716 return (DDI_FAILURE); 717 718 return (DDI_SUCCESS); 719 } 720 721 722 int 723 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 724 { 725 int rval; 726 727 apic_get_intr_t intrinfo; 728 intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 729 rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 730 731 if (rval == DDI_SUCCESS) 732 return (intrinfo.avgi_cpu_id); 733 else 734 return (-1); 735 } 736 737 738 static int 739 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 740 ddi_intr_handle_impl_t *hdlp, uint32_t inum) 741 { 742 struct intrspec *ispec; 743 int irq; 744 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 745 746 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 747 (void *)hdlp, inum)); 748 749 /* Translate the interrupt if needed */ 750 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 751 if (ispec == NULL) 752 return (DDI_FAILURE); 753 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 754 ispec->intrspec_vec = inum; 755 ihdl_plat_datap->ip_ispecp = ispec; 756 757 /* translate the interrupt if needed */ 758 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 759 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 760 hdlp->ih_pri, irq)); 761 762 /* Add the interrupt handler */ 763 if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 764 DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 765 hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 766 return (DDI_FAILURE); 767 768 /* Note this really is an irq. */ 769 hdlp->ih_vector = (ushort_t)irq; 770 771 return (DDI_SUCCESS); 772 } 773 774 775 static void 776 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 777 ddi_intr_handle_impl_t *hdlp, uint32_t inum) 778 { 779 int irq; 780 struct intrspec *ispec; 781 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 782 783 DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 784 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 785 if (ispec == NULL) 786 return; 787 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 788 ispec->intrspec_vec = inum; 789 ihdl_plat_datap->ip_ispecp = ispec; 790 791 /* translate the interrupt if needed */ 792 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 793 794 /* Disable the interrupt handler */ 795 rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 796 ihdl_plat_datap->ip_ispecp = NULL; 797 } 798 799 /* 800 * Miscellaneous library function 801 */ 802 int 803 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 804 { 805 int i; 806 int number; 807 int assigned_addr_len; 808 uint_t phys_hi = pci_rp->pci_phys_hi; 809 pci_regspec_t *assigned_addr; 810 811 if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 812 (phys_hi & PCI_RELOCAT_B)) 813 return (DDI_SUCCESS); 814 815 /* 816 * the "reg" property specifies relocatable, get and interpret the 817 * "assigned-addresses" property. 818 */ 819 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 820 "assigned-addresses", (int **)&assigned_addr, 821 (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 822 return (DDI_FAILURE); 823 824 /* 825 * Scan the "assigned-addresses" for one that matches the specified 826 * "reg" property entry. 827 */ 828 phys_hi &= PCI_CONF_ADDR_MASK; 829 number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 830 for (i = 0; i < number; i++) { 831 if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 832 phys_hi) { 833 pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 834 pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 835 ddi_prop_free(assigned_addr); 836 return (DDI_SUCCESS); 837 } 838 } 839 840 ddi_prop_free(assigned_addr); 841 return (DDI_FAILURE); 842 } 843 844 845 /* 846 * For pci_tools 847 */ 848 849 int 850 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 851 int mode, cred_t *credp, int *rvalp) 852 { 853 int rv = ENOTTY; 854 855 minor_t minor = getminor(dev); 856 857 switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 858 case PCI_TOOL_REG_MINOR_NUM: 859 860 switch (cmd) { 861 case PCITOOL_DEVICE_SET_REG: 862 case PCITOOL_DEVICE_GET_REG: 863 864 /* Require full privileges. */ 865 if (secpolicy_kmdb(credp)) 866 rv = EPERM; 867 else 868 rv = pcitool_dev_reg_ops(dip, (void *)arg, 869 cmd, mode); 870 break; 871 872 case PCITOOL_NEXUS_SET_REG: 873 case PCITOOL_NEXUS_GET_REG: 874 875 /* Require full privileges. */ 876 if (secpolicy_kmdb(credp)) 877 rv = EPERM; 878 else 879 rv = pcitool_bus_reg_ops(dip, (void *)arg, 880 cmd, mode); 881 break; 882 } 883 break; 884 885 case PCI_TOOL_INTR_MINOR_NUM: 886 887 switch (cmd) { 888 case PCITOOL_DEVICE_SET_INTR: 889 890 /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 891 if (secpolicy_ponline(credp)) { 892 rv = EPERM; 893 break; 894 } 895 896 /*FALLTHRU*/ 897 /* These require no special privileges. */ 898 case PCITOOL_DEVICE_GET_INTR: 899 case PCITOOL_SYSTEM_INTR_INFO: 900 rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 901 break; 902 } 903 break; 904 905 /* 906 * All non-PCItool ioctls go through here, including: 907 * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 908 * those for attachment points with where minor number is the 909 * device number. 910 */ 911 default: 912 rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 913 credp, rvalp); 914 break; 915 } 916 917 return (rv); 918 } 919 920 921 int 922 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 923 { 924 size_t size = in_args->size; 925 uintptr_t dev_addr = in_args->dev_addr; 926 uintptr_t host_addr = in_args->host_addr; 927 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 928 ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 929 size_t repcount = in_args->repcount; 930 uint_t flags = in_args->flags; 931 int err = DDI_SUCCESS; 932 933 /* 934 * if no handle then this is a poke. We have to return failure here 935 * as we have no way of knowing whether this is a MEM or IO space access 936 */ 937 if (in_args->handle == NULL) 938 return (DDI_FAILURE); 939 940 /* 941 * rest of this function is actually for cautious puts 942 */ 943 for (; repcount; repcount--) { 944 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 945 switch (size) { 946 case sizeof (uint8_t): 947 pci_config_wr8(hp, (uint8_t *)dev_addr, 948 *(uint8_t *)host_addr); 949 break; 950 case sizeof (uint16_t): 951 pci_config_wr16(hp, (uint16_t *)dev_addr, 952 *(uint16_t *)host_addr); 953 break; 954 case sizeof (uint32_t): 955 pci_config_wr32(hp, (uint32_t *)dev_addr, 956 *(uint32_t *)host_addr); 957 break; 958 case sizeof (uint64_t): 959 pci_config_wr64(hp, (uint64_t *)dev_addr, 960 *(uint64_t *)host_addr); 961 break; 962 default: 963 err = DDI_FAILURE; 964 break; 965 } 966 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 967 if (hdlp->ah_acc.devacc_attr_endian_flags == 968 DDI_STRUCTURE_BE_ACC) { 969 switch (size) { 970 case sizeof (uint8_t): 971 i_ddi_io_put8(hp, 972 (uint8_t *)dev_addr, 973 *(uint8_t *)host_addr); 974 break; 975 case sizeof (uint16_t): 976 i_ddi_io_swap_put16(hp, 977 (uint16_t *)dev_addr, 978 *(uint16_t *)host_addr); 979 break; 980 case sizeof (uint32_t): 981 i_ddi_io_swap_put32(hp, 982 (uint32_t *)dev_addr, 983 *(uint32_t *)host_addr); 984 break; 985 /* 986 * note the 64-bit case is a dummy 987 * function - so no need to swap 988 */ 989 case sizeof (uint64_t): 990 i_ddi_io_put64(hp, 991 (uint64_t *)dev_addr, 992 *(uint64_t *)host_addr); 993 break; 994 default: 995 err = DDI_FAILURE; 996 break; 997 } 998 } else { 999 switch (size) { 1000 case sizeof (uint8_t): 1001 i_ddi_io_put8(hp, 1002 (uint8_t *)dev_addr, 1003 *(uint8_t *)host_addr); 1004 break; 1005 case sizeof (uint16_t): 1006 i_ddi_io_put16(hp, 1007 (uint16_t *)dev_addr, 1008 *(uint16_t *)host_addr); 1009 break; 1010 case sizeof (uint32_t): 1011 i_ddi_io_put32(hp, 1012 (uint32_t *)dev_addr, 1013 *(uint32_t *)host_addr); 1014 break; 1015 case sizeof (uint64_t): 1016 i_ddi_io_put64(hp, 1017 (uint64_t *)dev_addr, 1018 *(uint64_t *)host_addr); 1019 break; 1020 default: 1021 err = DDI_FAILURE; 1022 break; 1023 } 1024 } 1025 } else { 1026 if (hdlp->ah_acc.devacc_attr_endian_flags == 1027 DDI_STRUCTURE_BE_ACC) { 1028 switch (size) { 1029 case sizeof (uint8_t): 1030 *(uint8_t *)dev_addr = 1031 *(uint8_t *)host_addr; 1032 break; 1033 case sizeof (uint16_t): 1034 *(uint16_t *)dev_addr = 1035 ddi_swap16(*(uint16_t *)host_addr); 1036 break; 1037 case sizeof (uint32_t): 1038 *(uint32_t *)dev_addr = 1039 ddi_swap32(*(uint32_t *)host_addr); 1040 break; 1041 case sizeof (uint64_t): 1042 *(uint64_t *)dev_addr = 1043 ddi_swap64(*(uint64_t *)host_addr); 1044 break; 1045 default: 1046 err = DDI_FAILURE; 1047 break; 1048 } 1049 } else { 1050 switch (size) { 1051 case sizeof (uint8_t): 1052 *(uint8_t *)dev_addr = 1053 *(uint8_t *)host_addr; 1054 break; 1055 case sizeof (uint16_t): 1056 *(uint16_t *)dev_addr = 1057 *(uint16_t *)host_addr; 1058 break; 1059 case sizeof (uint32_t): 1060 *(uint32_t *)dev_addr = 1061 *(uint32_t *)host_addr; 1062 break; 1063 case sizeof (uint64_t): 1064 *(uint64_t *)dev_addr = 1065 *(uint64_t *)host_addr; 1066 break; 1067 default: 1068 err = DDI_FAILURE; 1069 break; 1070 } 1071 } 1072 } 1073 host_addr += size; 1074 if (flags == DDI_DEV_AUTOINCR) 1075 dev_addr += size; 1076 } 1077 return (err); 1078 } 1079 1080 1081 int 1082 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 1083 { 1084 ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 1085 1086 /* endian-ness check */ 1087 if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 1088 return (DDI_FAILURE); 1089 1090 /* 1091 * range check 1092 */ 1093 if ((offset >= PCI_CONF_HDR_SIZE) || 1094 (len > PCI_CONF_HDR_SIZE) || 1095 (offset + len > PCI_CONF_HDR_SIZE)) 1096 return (DDI_FAILURE); 1097 1098 ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 1099 /* 1100 * always use cautious mechanism for config space gets 1101 */ 1102 ap->ahi_get8 = i_ddi_caut_get8; 1103 ap->ahi_get16 = i_ddi_caut_get16; 1104 ap->ahi_get32 = i_ddi_caut_get32; 1105 ap->ahi_get64 = i_ddi_caut_get64; 1106 ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 1107 ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 1108 ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 1109 ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 1110 if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 1111 ap->ahi_put8 = i_ddi_caut_put8; 1112 ap->ahi_put16 = i_ddi_caut_put16; 1113 ap->ahi_put32 = i_ddi_caut_put32; 1114 ap->ahi_put64 = i_ddi_caut_put64; 1115 ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 1116 ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 1117 ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 1118 ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 1119 } else { 1120 ap->ahi_put8 = pci_config_wr8; 1121 ap->ahi_put16 = pci_config_wr16; 1122 ap->ahi_put32 = pci_config_wr32; 1123 ap->ahi_put64 = pci_config_wr64; 1124 ap->ahi_rep_put8 = pci_config_rep_wr8; 1125 ap->ahi_rep_put16 = pci_config_rep_wr16; 1126 ap->ahi_rep_put32 = pci_config_rep_wr32; 1127 ap->ahi_rep_put64 = pci_config_rep_wr64; 1128 } 1129 1130 /* Initialize to default check/notify functions */ 1131 ap->ahi_fault_check = i_ddi_acc_fault_check; 1132 ap->ahi_fault_notify = i_ddi_acc_fault_notify; 1133 ap->ahi_fault = 0; 1134 impl_acc_err_init(hp); 1135 return (DDI_SUCCESS); 1136 } 1137 1138 1139 int 1140 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 1141 { 1142 size_t size = in_args->size; 1143 uintptr_t dev_addr = in_args->dev_addr; 1144 uintptr_t host_addr = in_args->host_addr; 1145 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 1146 ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 1147 size_t repcount = in_args->repcount; 1148 uint_t flags = in_args->flags; 1149 int err = DDI_SUCCESS; 1150 1151 /* 1152 * if no handle then this is a peek. We have to return failure here 1153 * as we have no way of knowing whether this is a MEM or IO space access 1154 */ 1155 if (in_args->handle == NULL) 1156 return (DDI_FAILURE); 1157 1158 for (; repcount; repcount--) { 1159 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 1160 switch (size) { 1161 case sizeof (uint8_t): 1162 *(uint8_t *)host_addr = pci_config_rd8(hp, 1163 (uint8_t *)dev_addr); 1164 break; 1165 case sizeof (uint16_t): 1166 *(uint16_t *)host_addr = pci_config_rd16(hp, 1167 (uint16_t *)dev_addr); 1168 break; 1169 case sizeof (uint32_t): 1170 *(uint32_t *)host_addr = pci_config_rd32(hp, 1171 (uint32_t *)dev_addr); 1172 break; 1173 case sizeof (uint64_t): 1174 *(uint64_t *)host_addr = pci_config_rd64(hp, 1175 (uint64_t *)dev_addr); 1176 break; 1177 default: 1178 err = DDI_FAILURE; 1179 break; 1180 } 1181 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 1182 if (hdlp->ah_acc.devacc_attr_endian_flags == 1183 DDI_STRUCTURE_BE_ACC) { 1184 switch (size) { 1185 case sizeof (uint8_t): 1186 *(uint8_t *)host_addr = 1187 i_ddi_io_get8(hp, 1188 (uint8_t *)dev_addr); 1189 break; 1190 case sizeof (uint16_t): 1191 *(uint16_t *)host_addr = 1192 i_ddi_io_swap_get16(hp, 1193 (uint16_t *)dev_addr); 1194 break; 1195 case sizeof (uint32_t): 1196 *(uint32_t *)host_addr = 1197 i_ddi_io_swap_get32(hp, 1198 (uint32_t *)dev_addr); 1199 break; 1200 /* 1201 * note the 64-bit case is a dummy 1202 * function - so no need to swap 1203 */ 1204 case sizeof (uint64_t): 1205 *(uint64_t *)host_addr = 1206 i_ddi_io_get64(hp, 1207 (uint64_t *)dev_addr); 1208 break; 1209 default: 1210 err = DDI_FAILURE; 1211 break; 1212 } 1213 } else { 1214 switch (size) { 1215 case sizeof (uint8_t): 1216 *(uint8_t *)host_addr = 1217 i_ddi_io_get8(hp, 1218 (uint8_t *)dev_addr); 1219 break; 1220 case sizeof (uint16_t): 1221 *(uint16_t *)host_addr = 1222 i_ddi_io_get16(hp, 1223 (uint16_t *)dev_addr); 1224 break; 1225 case sizeof (uint32_t): 1226 *(uint32_t *)host_addr = 1227 i_ddi_io_get32(hp, 1228 (uint32_t *)dev_addr); 1229 break; 1230 case sizeof (uint64_t): 1231 *(uint64_t *)host_addr = 1232 i_ddi_io_get64(hp, 1233 (uint64_t *)dev_addr); 1234 break; 1235 default: 1236 err = DDI_FAILURE; 1237 break; 1238 } 1239 } 1240 } else { 1241 if (hdlp->ah_acc.devacc_attr_endian_flags == 1242 DDI_STRUCTURE_BE_ACC) { 1243 switch (in_args->size) { 1244 case sizeof (uint8_t): 1245 *(uint8_t *)host_addr = 1246 *(uint8_t *)dev_addr; 1247 break; 1248 case sizeof (uint16_t): 1249 *(uint16_t *)host_addr = 1250 ddi_swap16(*(uint16_t *)dev_addr); 1251 break; 1252 case sizeof (uint32_t): 1253 *(uint32_t *)host_addr = 1254 ddi_swap32(*(uint32_t *)dev_addr); 1255 break; 1256 case sizeof (uint64_t): 1257 *(uint64_t *)host_addr = 1258 ddi_swap64(*(uint64_t *)dev_addr); 1259 break; 1260 default: 1261 err = DDI_FAILURE; 1262 break; 1263 } 1264 } else { 1265 switch (in_args->size) { 1266 case sizeof (uint8_t): 1267 *(uint8_t *)host_addr = 1268 *(uint8_t *)dev_addr; 1269 break; 1270 case sizeof (uint16_t): 1271 *(uint16_t *)host_addr = 1272 *(uint16_t *)dev_addr; 1273 break; 1274 case sizeof (uint32_t): 1275 *(uint32_t *)host_addr = 1276 *(uint32_t *)dev_addr; 1277 break; 1278 case sizeof (uint64_t): 1279 *(uint64_t *)host_addr = 1280 *(uint64_t *)dev_addr; 1281 break; 1282 default: 1283 err = DDI_FAILURE; 1284 break; 1285 } 1286 } 1287 } 1288 host_addr += size; 1289 if (flags == DDI_DEV_AUTOINCR) 1290 dev_addr += size; 1291 } 1292 return (err); 1293 } 1294 1295 /*ARGSUSED*/ 1296 int 1297 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 1298 ddi_ctl_enum_t ctlop, void *arg, void *result) 1299 { 1300 if (ctlop == DDI_CTLOPS_PEEK) 1301 return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 1302 else 1303 return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 1304 } 1305 1306 /* 1307 * These are the get and put functions to be shared with drivers. The 1308 * mutex locking is done inside the functions referenced, rather than 1309 * here, and is thus shared across PCI child drivers and any other 1310 * consumers of PCI config space (such as the ACPI subsystem). 1311 * 1312 * The configuration space addresses come in as pointers. This is fine on 1313 * a 32-bit system, where the VM space and configuration space are the same 1314 * size. It's not such a good idea on a 64-bit system, where memory 1315 * addresses are twice as large as configuration space addresses. At some 1316 * point in the call tree we need to take a stand and say "you are 32-bit 1317 * from this time forth", and this seems like a nice self-contained place. 1318 */ 1319 1320 uint8_t 1321 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 1322 { 1323 pci_acc_cfblk_t *cfp; 1324 uint8_t rval; 1325 int reg; 1326 1327 ASSERT64(((uintptr_t)addr >> 32) == 0); 1328 1329 reg = (int)(uintptr_t)addr; 1330 1331 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1332 1333 rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1334 reg); 1335 1336 return (rval); 1337 } 1338 1339 void 1340 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1341 uint8_t *dev_addr, size_t repcount, uint_t flags) 1342 { 1343 uint8_t *h, *d; 1344 1345 h = host_addr; 1346 d = dev_addr; 1347 1348 if (flags == DDI_DEV_AUTOINCR) 1349 for (; repcount; repcount--) 1350 *h++ = pci_config_rd8(hdlp, d++); 1351 else 1352 for (; repcount; repcount--) 1353 *h++ = pci_config_rd8(hdlp, d); 1354 } 1355 1356 uint16_t 1357 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 1358 { 1359 pci_acc_cfblk_t *cfp; 1360 uint16_t rval; 1361 int reg; 1362 1363 ASSERT64(((uintptr_t)addr >> 32) == 0); 1364 1365 reg = (int)(uintptr_t)addr; 1366 1367 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1368 1369 rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1370 reg); 1371 1372 return (rval); 1373 } 1374 1375 void 1376 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1377 uint16_t *dev_addr, size_t repcount, uint_t flags) 1378 { 1379 uint16_t *h, *d; 1380 1381 h = host_addr; 1382 d = dev_addr; 1383 1384 if (flags == DDI_DEV_AUTOINCR) 1385 for (; repcount; repcount--) 1386 *h++ = pci_config_rd16(hdlp, d++); 1387 else 1388 for (; repcount; repcount--) 1389 *h++ = pci_config_rd16(hdlp, d); 1390 } 1391 1392 uint32_t 1393 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 1394 { 1395 pci_acc_cfblk_t *cfp; 1396 uint32_t rval; 1397 int reg; 1398 1399 ASSERT64(((uintptr_t)addr >> 32) == 0); 1400 1401 reg = (int)(uintptr_t)addr; 1402 1403 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1404 1405 rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 1406 cfp->c_funcnum, reg); 1407 1408 return (rval); 1409 } 1410 1411 void 1412 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1413 uint32_t *dev_addr, size_t repcount, uint_t flags) 1414 { 1415 uint32_t *h, *d; 1416 1417 h = host_addr; 1418 d = dev_addr; 1419 1420 if (flags == DDI_DEV_AUTOINCR) 1421 for (; repcount; repcount--) 1422 *h++ = pci_config_rd32(hdlp, d++); 1423 else 1424 for (; repcount; repcount--) 1425 *h++ = pci_config_rd32(hdlp, d); 1426 } 1427 1428 1429 void 1430 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 1431 { 1432 pci_acc_cfblk_t *cfp; 1433 int reg; 1434 1435 ASSERT64(((uintptr_t)addr >> 32) == 0); 1436 1437 reg = (int)(uintptr_t)addr; 1438 1439 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1440 1441 (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 1442 cfp->c_funcnum, reg, value); 1443 } 1444 1445 void 1446 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1447 uint8_t *dev_addr, size_t repcount, uint_t flags) 1448 { 1449 uint8_t *h, *d; 1450 1451 h = host_addr; 1452 d = dev_addr; 1453 1454 if (flags == DDI_DEV_AUTOINCR) 1455 for (; repcount; repcount--) 1456 pci_config_wr8(hdlp, d++, *h++); 1457 else 1458 for (; repcount; repcount--) 1459 pci_config_wr8(hdlp, d, *h++); 1460 } 1461 1462 void 1463 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 1464 { 1465 pci_acc_cfblk_t *cfp; 1466 int reg; 1467 1468 ASSERT64(((uintptr_t)addr >> 32) == 0); 1469 1470 reg = (int)(uintptr_t)addr; 1471 1472 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1473 1474 (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 1475 cfp->c_funcnum, reg, value); 1476 } 1477 1478 void 1479 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1480 uint16_t *dev_addr, size_t repcount, uint_t flags) 1481 { 1482 uint16_t *h, *d; 1483 1484 h = host_addr; 1485 d = dev_addr; 1486 1487 if (flags == DDI_DEV_AUTOINCR) 1488 for (; repcount; repcount--) 1489 pci_config_wr16(hdlp, d++, *h++); 1490 else 1491 for (; repcount; repcount--) 1492 pci_config_wr16(hdlp, d, *h++); 1493 } 1494 1495 void 1496 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 1497 { 1498 pci_acc_cfblk_t *cfp; 1499 int reg; 1500 1501 ASSERT64(((uintptr_t)addr >> 32) == 0); 1502 1503 reg = (int)(uintptr_t)addr; 1504 1505 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1506 1507 (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 1508 cfp->c_funcnum, reg, value); 1509 } 1510 1511 void 1512 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1513 uint32_t *dev_addr, size_t repcount, uint_t flags) 1514 { 1515 uint32_t *h, *d; 1516 1517 h = host_addr; 1518 d = dev_addr; 1519 1520 if (flags == DDI_DEV_AUTOINCR) 1521 for (; repcount; repcount--) 1522 pci_config_wr32(hdlp, d++, *h++); 1523 else 1524 for (; repcount; repcount--) 1525 pci_config_wr32(hdlp, d, *h++); 1526 } 1527 1528 uint64_t 1529 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 1530 { 1531 uint32_t lw_val; 1532 uint32_t hi_val; 1533 uint32_t *dp; 1534 uint64_t val; 1535 1536 dp = (uint32_t *)addr; 1537 lw_val = pci_config_rd32(hdlp, dp); 1538 dp++; 1539 hi_val = pci_config_rd32(hdlp, dp); 1540 val = ((uint64_t)hi_val << 32) | lw_val; 1541 return (val); 1542 } 1543 1544 void 1545 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 1546 { 1547 uint32_t lw_val; 1548 uint32_t hi_val; 1549 uint32_t *dp; 1550 1551 dp = (uint32_t *)addr; 1552 lw_val = (uint32_t)(value & 0xffffffff); 1553 hi_val = (uint32_t)(value >> 32); 1554 pci_config_wr32(hdlp, dp, lw_val); 1555 dp++; 1556 pci_config_wr32(hdlp, dp, hi_val); 1557 } 1558 1559 void 1560 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1561 uint64_t *dev_addr, size_t repcount, uint_t flags) 1562 { 1563 if (flags == DDI_DEV_AUTOINCR) { 1564 for (; repcount; repcount--) 1565 *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 1566 } else { 1567 for (; repcount; repcount--) 1568 *host_addr++ = pci_config_rd64(hdlp, dev_addr); 1569 } 1570 } 1571 1572 void 1573 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1574 uint64_t *dev_addr, size_t repcount, uint_t flags) 1575 { 1576 if (flags == DDI_DEV_AUTOINCR) { 1577 for (; repcount; repcount--) 1578 pci_config_wr64(hdlp, host_addr++, *dev_addr++); 1579 } else { 1580 for (; repcount; repcount--) 1581 pci_config_wr64(hdlp, host_addr++, *dev_addr); 1582 } 1583 } 1584 1585 1586 /* 1587 * Enable Legacy PCI config space access for the following four north bridges 1588 * Host bridge: AMD HyperTransport Technology Configuration 1589 * Host bridge: AMD Address Map 1590 * Host bridge: AMD DRAM Controller 1591 * Host bridge: AMD Miscellaneous Control 1592 */ 1593 int 1594 is_amd_northbridge(dev_info_t *dip) 1595 { 1596 int vendor_id, device_id; 1597 1598 vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1599 "vendor-id", -1); 1600 device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1601 "device-id", -1); 1602 1603 if (IS_AMD_NTBRIDGE(vendor_id, device_id)) 1604 return (0); 1605 1606 return (1); 1607 } 1608