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