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 if (hdlp->ih_irq == -1) 954 hdlp->ih_irq = irq; 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 }