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