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