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