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