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 case DDI_INTROP_GETTARGET: 685 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n")); 686 687 /* Note hdlp->ih_vector is actually an irq */ 688 if ((rv = pci_get_cpu_from_vecirq(hdlp->ih_vector, IS_IRQ)) == 689 -1) 690 return (DDI_FAILURE); 691 *(int *)result = rv; 692 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET " 693 "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, rv)); 694 break; 695 case DDI_INTROP_SETTARGET: 696 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n")); 697 698 /* hdlp->ih_vector is actually an irq */ 699 tmp_hdl.ih_vector = hdlp->ih_vector; 700 tmp_hdl.ih_flags = PSMGI_INTRBY_IRQ; 701 tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result; 702 psm_rval = (*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU, 703 &psm_status); 704 705 if (psm_rval != PSM_SUCCESS) 706 return (DDI_FAILURE); 707 break; 708 default: 709 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 710 } 711 712 return (DDI_SUCCESS); 713 } 714 715 int 716 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 717 int vecirq, boolean_t is_irq) 718 { 719 ddi_intr_handle_impl_t get_info_ii_hdl; 720 721 if (is_irq) 722 intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 723 724 /* 725 * For this locally-declared and used handle, ih_private will contain a 726 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 727 * global interrupt handling. 728 */ 729 get_info_ii_hdl.ih_private = intrinfo_p; 730 get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 731 732 if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 733 PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 734 return (DDI_FAILURE); 735 736 return (DDI_SUCCESS); 737 } 738 739 740 int 741 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 742 { 743 int rval; 744 745 apic_get_intr_t intrinfo; 746 intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 747 rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 748 749 if (rval == DDI_SUCCESS) 750 return (intrinfo.avgi_cpu_id); 751 else 752 return (-1); 753 } 754 755 756 static int 757 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 758 ddi_intr_handle_impl_t *hdlp, uint32_t inum) 759 { 760 struct intrspec *ispec; 761 int irq; 762 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 763 764 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 765 (void *)hdlp, inum)); 766 767 /* Translate the interrupt if needed */ 768 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 769 if (ispec == NULL) 770 return (DDI_FAILURE); 771 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 772 ispec->intrspec_vec = inum; 773 ihdl_plat_datap->ip_ispecp = ispec; 774 775 /* translate the interrupt if needed */ 776 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 777 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 778 hdlp->ih_pri, irq)); 779 780 /* Add the interrupt handler */ 781 if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 782 DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 783 hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 784 return (DDI_FAILURE); 785 786 /* Note this really is an irq. */ 787 hdlp->ih_vector = (ushort_t)irq; 788 789 return (DDI_SUCCESS); 790 } 791 792 793 static void 794 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 795 ddi_intr_handle_impl_t *hdlp, uint32_t inum) 796 { 797 int irq; 798 struct intrspec *ispec; 799 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 800 801 DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 802 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 803 if (ispec == NULL) 804 return; 805 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 806 ispec->intrspec_vec = inum; 807 ihdl_plat_datap->ip_ispecp = ispec; 808 809 /* translate the interrupt if needed */ 810 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 811 812 /* Disable the interrupt handler */ 813 rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 814 ihdl_plat_datap->ip_ispecp = NULL; 815 } 816 817 /* 818 * Miscellaneous library function 819 */ 820 int 821 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 822 { 823 int i; 824 int number; 825 int assigned_addr_len; 826 uint_t phys_hi = pci_rp->pci_phys_hi; 827 pci_regspec_t *assigned_addr; 828 829 if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 830 (phys_hi & PCI_RELOCAT_B)) 831 return (DDI_SUCCESS); 832 833 /* 834 * the "reg" property specifies relocatable, get and interpret the 835 * "assigned-addresses" property. 836 */ 837 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 838 "assigned-addresses", (int **)&assigned_addr, 839 (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 840 return (DDI_FAILURE); 841 842 /* 843 * Scan the "assigned-addresses" for one that matches the specified 844 * "reg" property entry. 845 */ 846 phys_hi &= PCI_CONF_ADDR_MASK; 847 number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 848 for (i = 0; i < number; i++) { 849 if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 850 phys_hi) { 851 pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 852 pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 853 ddi_prop_free(assigned_addr); 854 return (DDI_SUCCESS); 855 } 856 } 857 858 ddi_prop_free(assigned_addr); 859 return (DDI_FAILURE); 860 } 861 862 863 /* 864 * For pci_tools 865 */ 866 867 int 868 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 869 int mode, cred_t *credp, int *rvalp) 870 { 871 int rv = ENOTTY; 872 873 minor_t minor = getminor(dev); 874 875 switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 876 case PCI_TOOL_REG_MINOR_NUM: 877 878 switch (cmd) { 879 case PCITOOL_DEVICE_SET_REG: 880 case PCITOOL_DEVICE_GET_REG: 881 882 /* Require full privileges. */ 883 if (secpolicy_kmdb(credp)) 884 rv = EPERM; 885 else 886 rv = pcitool_dev_reg_ops(dip, (void *)arg, 887 cmd, mode); 888 break; 889 890 case PCITOOL_NEXUS_SET_REG: 891 case PCITOOL_NEXUS_GET_REG: 892 893 /* Require full privileges. */ 894 if (secpolicy_kmdb(credp)) 895 rv = EPERM; 896 else 897 rv = pcitool_bus_reg_ops(dip, (void *)arg, 898 cmd, mode); 899 break; 900 } 901 break; 902 903 case PCI_TOOL_INTR_MINOR_NUM: 904 905 switch (cmd) { 906 case PCITOOL_DEVICE_SET_INTR: 907 908 /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 909 if (secpolicy_ponline(credp)) { 910 rv = EPERM; 911 break; 912 } 913 914 /*FALLTHRU*/ 915 /* These require no special privileges. */ 916 case PCITOOL_DEVICE_GET_INTR: 917 case PCITOOL_SYSTEM_INTR_INFO: 918 rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 919 break; 920 } 921 break; 922 923 /* 924 * All non-PCItool ioctls go through here, including: 925 * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 926 * those for attachment points with where minor number is the 927 * device number. 928 */ 929 default: 930 rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 931 credp, rvalp); 932 break; 933 } 934 935 return (rv); 936 } 937 938 939 int 940 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 941 { 942 size_t size = in_args->size; 943 uintptr_t dev_addr = in_args->dev_addr; 944 uintptr_t host_addr = in_args->host_addr; 945 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 946 ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 947 size_t repcount = in_args->repcount; 948 uint_t flags = in_args->flags; 949 int err = DDI_SUCCESS; 950 951 /* 952 * if no handle then this is a poke. We have to return failure here 953 * as we have no way of knowing whether this is a MEM or IO space access 954 */ 955 if (in_args->handle == NULL) 956 return (DDI_FAILURE); 957 958 /* 959 * rest of this function is actually for cautious puts 960 */ 961 for (; repcount; repcount--) { 962 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 963 switch (size) { 964 case sizeof (uint8_t): 965 pci_config_wr8(hp, (uint8_t *)dev_addr, 966 *(uint8_t *)host_addr); 967 break; 968 case sizeof (uint16_t): 969 pci_config_wr16(hp, (uint16_t *)dev_addr, 970 *(uint16_t *)host_addr); 971 break; 972 case sizeof (uint32_t): 973 pci_config_wr32(hp, (uint32_t *)dev_addr, 974 *(uint32_t *)host_addr); 975 break; 976 case sizeof (uint64_t): 977 pci_config_wr64(hp, (uint64_t *)dev_addr, 978 *(uint64_t *)host_addr); 979 break; 980 default: 981 err = DDI_FAILURE; 982 break; 983 } 984 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 985 if (hdlp->ah_acc.devacc_attr_endian_flags == 986 DDI_STRUCTURE_BE_ACC) { 987 switch (size) { 988 case sizeof (uint8_t): 989 i_ddi_io_put8(hp, 990 (uint8_t *)dev_addr, 991 *(uint8_t *)host_addr); 992 break; 993 case sizeof (uint16_t): 994 i_ddi_io_swap_put16(hp, 995 (uint16_t *)dev_addr, 996 *(uint16_t *)host_addr); 997 break; 998 case sizeof (uint32_t): 999 i_ddi_io_swap_put32(hp, 1000 (uint32_t *)dev_addr, 1001 *(uint32_t *)host_addr); 1002 break; 1003 /* 1004 * note the 64-bit case is a dummy 1005 * function - so no need to swap 1006 */ 1007 case sizeof (uint64_t): 1008 i_ddi_io_put64(hp, 1009 (uint64_t *)dev_addr, 1010 *(uint64_t *)host_addr); 1011 break; 1012 default: 1013 err = DDI_FAILURE; 1014 break; 1015 } 1016 } else { 1017 switch (size) { 1018 case sizeof (uint8_t): 1019 i_ddi_io_put8(hp, 1020 (uint8_t *)dev_addr, 1021 *(uint8_t *)host_addr); 1022 break; 1023 case sizeof (uint16_t): 1024 i_ddi_io_put16(hp, 1025 (uint16_t *)dev_addr, 1026 *(uint16_t *)host_addr); 1027 break; 1028 case sizeof (uint32_t): 1029 i_ddi_io_put32(hp, 1030 (uint32_t *)dev_addr, 1031 *(uint32_t *)host_addr); 1032 break; 1033 case sizeof (uint64_t): 1034 i_ddi_io_put64(hp, 1035 (uint64_t *)dev_addr, 1036 *(uint64_t *)host_addr); 1037 break; 1038 default: 1039 err = DDI_FAILURE; 1040 break; 1041 } 1042 } 1043 } else { 1044 if (hdlp->ah_acc.devacc_attr_endian_flags == 1045 DDI_STRUCTURE_BE_ACC) { 1046 switch (size) { 1047 case sizeof (uint8_t): 1048 *(uint8_t *)dev_addr = 1049 *(uint8_t *)host_addr; 1050 break; 1051 case sizeof (uint16_t): 1052 *(uint16_t *)dev_addr = 1053 ddi_swap16(*(uint16_t *)host_addr); 1054 break; 1055 case sizeof (uint32_t): 1056 *(uint32_t *)dev_addr = 1057 ddi_swap32(*(uint32_t *)host_addr); 1058 break; 1059 case sizeof (uint64_t): 1060 *(uint64_t *)dev_addr = 1061 ddi_swap64(*(uint64_t *)host_addr); 1062 break; 1063 default: 1064 err = DDI_FAILURE; 1065 break; 1066 } 1067 } else { 1068 switch (size) { 1069 case sizeof (uint8_t): 1070 *(uint8_t *)dev_addr = 1071 *(uint8_t *)host_addr; 1072 break; 1073 case sizeof (uint16_t): 1074 *(uint16_t *)dev_addr = 1075 *(uint16_t *)host_addr; 1076 break; 1077 case sizeof (uint32_t): 1078 *(uint32_t *)dev_addr = 1079 *(uint32_t *)host_addr; 1080 break; 1081 case sizeof (uint64_t): 1082 *(uint64_t *)dev_addr = 1083 *(uint64_t *)host_addr; 1084 break; 1085 default: 1086 err = DDI_FAILURE; 1087 break; 1088 } 1089 } 1090 } 1091 host_addr += size; 1092 if (flags == DDI_DEV_AUTOINCR) 1093 dev_addr += size; 1094 } 1095 return (err); 1096 } 1097 1098 1099 int 1100 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 1101 { 1102 ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 1103 1104 /* endian-ness check */ 1105 if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 1106 return (DDI_FAILURE); 1107 1108 /* 1109 * range check 1110 */ 1111 if ((offset >= PCI_CONF_HDR_SIZE) || 1112 (len > PCI_CONF_HDR_SIZE) || 1113 (offset + len > PCI_CONF_HDR_SIZE)) 1114 return (DDI_FAILURE); 1115 1116 ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 1117 /* 1118 * always use cautious mechanism for config space gets 1119 */ 1120 ap->ahi_get8 = i_ddi_caut_get8; 1121 ap->ahi_get16 = i_ddi_caut_get16; 1122 ap->ahi_get32 = i_ddi_caut_get32; 1123 ap->ahi_get64 = i_ddi_caut_get64; 1124 ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 1125 ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 1126 ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 1127 ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 1128 if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 1129 ap->ahi_put8 = i_ddi_caut_put8; 1130 ap->ahi_put16 = i_ddi_caut_put16; 1131 ap->ahi_put32 = i_ddi_caut_put32; 1132 ap->ahi_put64 = i_ddi_caut_put64; 1133 ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 1134 ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 1135 ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 1136 ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 1137 } else { 1138 ap->ahi_put8 = pci_config_wr8; 1139 ap->ahi_put16 = pci_config_wr16; 1140 ap->ahi_put32 = pci_config_wr32; 1141 ap->ahi_put64 = pci_config_wr64; 1142 ap->ahi_rep_put8 = pci_config_rep_wr8; 1143 ap->ahi_rep_put16 = pci_config_rep_wr16; 1144 ap->ahi_rep_put32 = pci_config_rep_wr32; 1145 ap->ahi_rep_put64 = pci_config_rep_wr64; 1146 } 1147 1148 /* Initialize to default check/notify functions */ 1149 ap->ahi_fault_check = i_ddi_acc_fault_check; 1150 ap->ahi_fault_notify = i_ddi_acc_fault_notify; 1151 ap->ahi_fault = 0; 1152 impl_acc_err_init(hp); 1153 return (DDI_SUCCESS); 1154 } 1155 1156 1157 int 1158 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 1159 { 1160 size_t size = in_args->size; 1161 uintptr_t dev_addr = in_args->dev_addr; 1162 uintptr_t host_addr = in_args->host_addr; 1163 ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 1164 ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 1165 size_t repcount = in_args->repcount; 1166 uint_t flags = in_args->flags; 1167 int err = DDI_SUCCESS; 1168 1169 /* 1170 * if no handle then this is a peek. We have to return failure here 1171 * as we have no way of knowing whether this is a MEM or IO space access 1172 */ 1173 if (in_args->handle == NULL) 1174 return (DDI_FAILURE); 1175 1176 for (; repcount; repcount--) { 1177 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 1178 switch (size) { 1179 case sizeof (uint8_t): 1180 *(uint8_t *)host_addr = pci_config_rd8(hp, 1181 (uint8_t *)dev_addr); 1182 break; 1183 case sizeof (uint16_t): 1184 *(uint16_t *)host_addr = pci_config_rd16(hp, 1185 (uint16_t *)dev_addr); 1186 break; 1187 case sizeof (uint32_t): 1188 *(uint32_t *)host_addr = pci_config_rd32(hp, 1189 (uint32_t *)dev_addr); 1190 break; 1191 case sizeof (uint64_t): 1192 *(uint64_t *)host_addr = pci_config_rd64(hp, 1193 (uint64_t *)dev_addr); 1194 break; 1195 default: 1196 err = DDI_FAILURE; 1197 break; 1198 } 1199 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 1200 if (hdlp->ah_acc.devacc_attr_endian_flags == 1201 DDI_STRUCTURE_BE_ACC) { 1202 switch (size) { 1203 case sizeof (uint8_t): 1204 *(uint8_t *)host_addr = 1205 i_ddi_io_get8(hp, 1206 (uint8_t *)dev_addr); 1207 break; 1208 case sizeof (uint16_t): 1209 *(uint16_t *)host_addr = 1210 i_ddi_io_swap_get16(hp, 1211 (uint16_t *)dev_addr); 1212 break; 1213 case sizeof (uint32_t): 1214 *(uint32_t *)host_addr = 1215 i_ddi_io_swap_get32(hp, 1216 (uint32_t *)dev_addr); 1217 break; 1218 /* 1219 * note the 64-bit case is a dummy 1220 * function - so no need to swap 1221 */ 1222 case sizeof (uint64_t): 1223 *(uint64_t *)host_addr = 1224 i_ddi_io_get64(hp, 1225 (uint64_t *)dev_addr); 1226 break; 1227 default: 1228 err = DDI_FAILURE; 1229 break; 1230 } 1231 } else { 1232 switch (size) { 1233 case sizeof (uint8_t): 1234 *(uint8_t *)host_addr = 1235 i_ddi_io_get8(hp, 1236 (uint8_t *)dev_addr); 1237 break; 1238 case sizeof (uint16_t): 1239 *(uint16_t *)host_addr = 1240 i_ddi_io_get16(hp, 1241 (uint16_t *)dev_addr); 1242 break; 1243 case sizeof (uint32_t): 1244 *(uint32_t *)host_addr = 1245 i_ddi_io_get32(hp, 1246 (uint32_t *)dev_addr); 1247 break; 1248 case sizeof (uint64_t): 1249 *(uint64_t *)host_addr = 1250 i_ddi_io_get64(hp, 1251 (uint64_t *)dev_addr); 1252 break; 1253 default: 1254 err = DDI_FAILURE; 1255 break; 1256 } 1257 } 1258 } else { 1259 if (hdlp->ah_acc.devacc_attr_endian_flags == 1260 DDI_STRUCTURE_BE_ACC) { 1261 switch (in_args->size) { 1262 case sizeof (uint8_t): 1263 *(uint8_t *)host_addr = 1264 *(uint8_t *)dev_addr; 1265 break; 1266 case sizeof (uint16_t): 1267 *(uint16_t *)host_addr = 1268 ddi_swap16(*(uint16_t *)dev_addr); 1269 break; 1270 case sizeof (uint32_t): 1271 *(uint32_t *)host_addr = 1272 ddi_swap32(*(uint32_t *)dev_addr); 1273 break; 1274 case sizeof (uint64_t): 1275 *(uint64_t *)host_addr = 1276 ddi_swap64(*(uint64_t *)dev_addr); 1277 break; 1278 default: 1279 err = DDI_FAILURE; 1280 break; 1281 } 1282 } else { 1283 switch (in_args->size) { 1284 case sizeof (uint8_t): 1285 *(uint8_t *)host_addr = 1286 *(uint8_t *)dev_addr; 1287 break; 1288 case sizeof (uint16_t): 1289 *(uint16_t *)host_addr = 1290 *(uint16_t *)dev_addr; 1291 break; 1292 case sizeof (uint32_t): 1293 *(uint32_t *)host_addr = 1294 *(uint32_t *)dev_addr; 1295 break; 1296 case sizeof (uint64_t): 1297 *(uint64_t *)host_addr = 1298 *(uint64_t *)dev_addr; 1299 break; 1300 default: 1301 err = DDI_FAILURE; 1302 break; 1303 } 1304 } 1305 } 1306 host_addr += size; 1307 if (flags == DDI_DEV_AUTOINCR) 1308 dev_addr += size; 1309 } 1310 return (err); 1311 } 1312 1313 /*ARGSUSED*/ 1314 int 1315 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 1316 ddi_ctl_enum_t ctlop, void *arg, void *result) 1317 { 1318 if (ctlop == DDI_CTLOPS_PEEK) 1319 return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 1320 else 1321 return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 1322 } 1323 1324 /* 1325 * These are the get and put functions to be shared with drivers. The 1326 * mutex locking is done inside the functions referenced, rather than 1327 * here, and is thus shared across PCI child drivers and any other 1328 * consumers of PCI config space (such as the ACPI subsystem). 1329 * 1330 * The configuration space addresses come in as pointers. This is fine on 1331 * a 32-bit system, where the VM space and configuration space are the same 1332 * size. It's not such a good idea on a 64-bit system, where memory 1333 * addresses are twice as large as configuration space addresses. At some 1334 * point in the call tree we need to take a stand and say "you are 32-bit 1335 * from this time forth", and this seems like a nice self-contained place. 1336 */ 1337 1338 uint8_t 1339 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 1340 { 1341 pci_acc_cfblk_t *cfp; 1342 uint8_t rval; 1343 int reg; 1344 1345 ASSERT64(((uintptr_t)addr >> 32) == 0); 1346 1347 reg = (int)(uintptr_t)addr; 1348 1349 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1350 1351 rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1352 reg); 1353 1354 return (rval); 1355 } 1356 1357 void 1358 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1359 uint8_t *dev_addr, size_t repcount, uint_t flags) 1360 { 1361 uint8_t *h, *d; 1362 1363 h = host_addr; 1364 d = dev_addr; 1365 1366 if (flags == DDI_DEV_AUTOINCR) 1367 for (; repcount; repcount--) 1368 *h++ = pci_config_rd8(hdlp, d++); 1369 else 1370 for (; repcount; repcount--) 1371 *h++ = pci_config_rd8(hdlp, d); 1372 } 1373 1374 uint16_t 1375 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 1376 { 1377 pci_acc_cfblk_t *cfp; 1378 uint16_t rval; 1379 int reg; 1380 1381 ASSERT64(((uintptr_t)addr >> 32) == 0); 1382 1383 reg = (int)(uintptr_t)addr; 1384 1385 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1386 1387 rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1388 reg); 1389 1390 return (rval); 1391 } 1392 1393 void 1394 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1395 uint16_t *dev_addr, size_t repcount, uint_t flags) 1396 { 1397 uint16_t *h, *d; 1398 1399 h = host_addr; 1400 d = dev_addr; 1401 1402 if (flags == DDI_DEV_AUTOINCR) 1403 for (; repcount; repcount--) 1404 *h++ = pci_config_rd16(hdlp, d++); 1405 else 1406 for (; repcount; repcount--) 1407 *h++ = pci_config_rd16(hdlp, d); 1408 } 1409 1410 uint32_t 1411 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 1412 { 1413 pci_acc_cfblk_t *cfp; 1414 uint32_t rval; 1415 int reg; 1416 1417 ASSERT64(((uintptr_t)addr >> 32) == 0); 1418 1419 reg = (int)(uintptr_t)addr; 1420 1421 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1422 1423 rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 1424 cfp->c_funcnum, reg); 1425 1426 return (rval); 1427 } 1428 1429 void 1430 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1431 uint32_t *dev_addr, size_t repcount, uint_t flags) 1432 { 1433 uint32_t *h, *d; 1434 1435 h = host_addr; 1436 d = dev_addr; 1437 1438 if (flags == DDI_DEV_AUTOINCR) 1439 for (; repcount; repcount--) 1440 *h++ = pci_config_rd32(hdlp, d++); 1441 else 1442 for (; repcount; repcount--) 1443 *h++ = pci_config_rd32(hdlp, d); 1444 } 1445 1446 1447 void 1448 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 1449 { 1450 pci_acc_cfblk_t *cfp; 1451 int reg; 1452 1453 ASSERT64(((uintptr_t)addr >> 32) == 0); 1454 1455 reg = (int)(uintptr_t)addr; 1456 1457 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1458 1459 (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 1460 cfp->c_funcnum, reg, value); 1461 } 1462 1463 void 1464 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1465 uint8_t *dev_addr, size_t repcount, uint_t flags) 1466 { 1467 uint8_t *h, *d; 1468 1469 h = host_addr; 1470 d = dev_addr; 1471 1472 if (flags == DDI_DEV_AUTOINCR) 1473 for (; repcount; repcount--) 1474 pci_config_wr8(hdlp, d++, *h++); 1475 else 1476 for (; repcount; repcount--) 1477 pci_config_wr8(hdlp, d, *h++); 1478 } 1479 1480 void 1481 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 1482 { 1483 pci_acc_cfblk_t *cfp; 1484 int reg; 1485 1486 ASSERT64(((uintptr_t)addr >> 32) == 0); 1487 1488 reg = (int)(uintptr_t)addr; 1489 1490 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1491 1492 (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 1493 cfp->c_funcnum, reg, value); 1494 } 1495 1496 void 1497 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1498 uint16_t *dev_addr, size_t repcount, uint_t flags) 1499 { 1500 uint16_t *h, *d; 1501 1502 h = host_addr; 1503 d = dev_addr; 1504 1505 if (flags == DDI_DEV_AUTOINCR) 1506 for (; repcount; repcount--) 1507 pci_config_wr16(hdlp, d++, *h++); 1508 else 1509 for (; repcount; repcount--) 1510 pci_config_wr16(hdlp, d, *h++); 1511 } 1512 1513 void 1514 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 1515 { 1516 pci_acc_cfblk_t *cfp; 1517 int reg; 1518 1519 ASSERT64(((uintptr_t)addr >> 32) == 0); 1520 1521 reg = (int)(uintptr_t)addr; 1522 1523 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1524 1525 (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 1526 cfp->c_funcnum, reg, value); 1527 } 1528 1529 void 1530 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1531 uint32_t *dev_addr, size_t repcount, uint_t flags) 1532 { 1533 uint32_t *h, *d; 1534 1535 h = host_addr; 1536 d = dev_addr; 1537 1538 if (flags == DDI_DEV_AUTOINCR) 1539 for (; repcount; repcount--) 1540 pci_config_wr32(hdlp, d++, *h++); 1541 else 1542 for (; repcount; repcount--) 1543 pci_config_wr32(hdlp, d, *h++); 1544 } 1545 1546 uint64_t 1547 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 1548 { 1549 uint32_t lw_val; 1550 uint32_t hi_val; 1551 uint32_t *dp; 1552 uint64_t val; 1553 1554 dp = (uint32_t *)addr; 1555 lw_val = pci_config_rd32(hdlp, dp); 1556 dp++; 1557 hi_val = pci_config_rd32(hdlp, dp); 1558 val = ((uint64_t)hi_val << 32) | lw_val; 1559 return (val); 1560 } 1561 1562 void 1563 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 1564 { 1565 uint32_t lw_val; 1566 uint32_t hi_val; 1567 uint32_t *dp; 1568 1569 dp = (uint32_t *)addr; 1570 lw_val = (uint32_t)(value & 0xffffffff); 1571 hi_val = (uint32_t)(value >> 32); 1572 pci_config_wr32(hdlp, dp, lw_val); 1573 dp++; 1574 pci_config_wr32(hdlp, dp, hi_val); 1575 } 1576 1577 void 1578 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1579 uint64_t *dev_addr, size_t repcount, uint_t flags) 1580 { 1581 if (flags == DDI_DEV_AUTOINCR) { 1582 for (; repcount; repcount--) 1583 *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 1584 } else { 1585 for (; repcount; repcount--) 1586 *host_addr++ = pci_config_rd64(hdlp, dev_addr); 1587 } 1588 } 1589 1590 void 1591 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1592 uint64_t *dev_addr, size_t repcount, uint_t flags) 1593 { 1594 if (flags == DDI_DEV_AUTOINCR) { 1595 for (; repcount; repcount--) 1596 pci_config_wr64(hdlp, host_addr++, *dev_addr++); 1597 } else { 1598 for (; repcount; repcount--) 1599 pci_config_wr64(hdlp, host_addr++, *dev_addr); 1600 } 1601 } 1602