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