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