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