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 2006 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 <io/pcplusmp/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 56 /* 57 * Function prototypes 58 */ 59 static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 60 static int pci_get_nintrs(dev_info_t *, int, 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 * pci_get_nintrs: 188 * Figure out how many interrupts the device supports 189 */ 190 static int 191 pci_get_nintrs(dev_info_t *dip, int type, int *nintrs) 192 { 193 int ret; 194 195 *nintrs = 0; 196 197 if (DDI_INTR_IS_MSI_OR_MSIX(type)) 198 ret = pci_msi_get_nintrs(dip, type, nintrs); 199 else { 200 ret = DDI_FAILURE; 201 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 202 "interrupts", -1) != -1) { 203 *nintrs = 1; 204 ret = DDI_SUCCESS; 205 } 206 } 207 208 return (ret); 209 } 210 211 static int pcie_pci_intr_pri_counter = 0; 212 213 /* 214 * pci_common_intr_ops: bus_intr_op() function for interrupt support 215 */ 216 int 217 pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 218 ddi_intr_handle_impl_t *hdlp, void *result) 219 { 220 int priority = 0; 221 int psm_status = 0; 222 int pci_status = 0; 223 int pci_rval, psm_rval = PSM_FAILURE; 224 int types = 0; 225 int pciepci = 0; 226 int i, j, count; 227 int behavior; 228 ddi_intrspec_t isp; 229 struct intrspec *ispec; 230 ddi_intr_handle_impl_t tmp_hdl; 231 ddi_intr_msix_t *msix_p; 232 ihdl_plat_t *ihdl_plat_datap; 233 ddi_intr_handle_t *h_array; 234 235 DDI_INTR_NEXDBG((CE_CONT, 236 "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 237 (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 238 239 /* Process the request */ 240 switch (intr_op) { 241 case DDI_INTROP_SUPPORTED_TYPES: 242 /* Fixed supported by default */ 243 *(int *)result = DDI_INTR_TYPE_FIXED; 244 245 /* Figure out if MSI or MSI-X is supported? */ 246 if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS) 247 return (DDI_SUCCESS); 248 249 if (psm_intr_ops != NULL) { 250 /* MSI or MSI-X is supported, OR it in */ 251 *(int *)result |= types; 252 253 tmp_hdl.ih_type = *(int *)result; 254 (void) (*psm_intr_ops)(rdip, &tmp_hdl, 255 PSM_INTR_OP_CHECK_MSI, result); 256 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 257 "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 258 *(int *)result)); 259 } 260 break; 261 case DDI_INTROP_NINTRS: 262 if (pci_get_nintrs(rdip, hdlp->ih_type, result) != DDI_SUCCESS) 263 return (DDI_FAILURE); 264 break; 265 case DDI_INTROP_ALLOC: 266 /* 267 * MSI or MSIX (figure out number of vectors available) 268 * FIXED interrupts: just return available interrupts 269 */ 270 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 271 (psm_intr_ops != NULL) && 272 (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 273 /* 274 * Following check is a special case for 'pcie_pci'. 275 * This makes sure vectors with the right priority 276 * are allocated for pcie_pci during ALLOC time. 277 */ 278 if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) { 279 hdlp->ih_pri = 280 (pcie_pci_intr_pri_counter % 2) ? 4 : 7; 281 pciepci = 1; 282 } else 283 hdlp->ih_pri = priority; 284 behavior = (int)hdlp->ih_scratch2; 285 (void) (*psm_intr_ops)(rdip, hdlp, 286 PSM_INTR_OP_ALLOC_VECTORS, result); 287 288 /* verify behavior flag and take appropriate action */ 289 if ((behavior == DDI_INTR_ALLOC_STRICT) && 290 (*(int *)result < hdlp->ih_scratch1)) { 291 DDI_INTR_NEXDBG((CE_CONT, 292 "pci_common_intr_ops: behavior %x, " 293 "couldn't get enough intrs\n", behavior)); 294 hdlp->ih_scratch1 = *(int *)result; 295 (void) (*psm_intr_ops)(rdip, hdlp, 296 PSM_INTR_OP_FREE_VECTORS, NULL); 297 return (DDI_EAGAIN); 298 } 299 300 if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 301 if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 302 msix_p = pci_msix_init(hdlp->ih_dip); 303 if (msix_p) 304 i_ddi_set_msix(hdlp->ih_dip, 305 msix_p); 306 } 307 msix_p->msix_intrs_in_use += *(int *)result; 308 } 309 310 if (pciepci) { 311 /* update priority in ispec */ 312 isp = pci_intx_get_ispec(pdip, rdip, 313 (int)hdlp->ih_inum); 314 ispec = (struct intrspec *)isp; 315 if (ispec) 316 ispec->intrspec_pri = hdlp->ih_pri; 317 ++pcie_pci_intr_pri_counter; 318 } 319 320 } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 321 /* Figure out if this device supports MASKING */ 322 pci_rval = pci_intx_get_cap(rdip, &pci_status); 323 if (pci_rval == DDI_SUCCESS && pci_status) 324 hdlp->ih_cap |= pci_status; 325 *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 326 } else 327 return (DDI_FAILURE); 328 break; 329 case DDI_INTROP_FREE: 330 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 331 (psm_intr_ops != NULL)) { 332 (void) (*psm_intr_ops)(rdip, hdlp, 333 PSM_INTR_OP_FREE_VECTORS, NULL); 334 335 if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 336 msix_p = i_ddi_get_msix(hdlp->ih_dip); 337 if (msix_p && 338 --msix_p->msix_intrs_in_use == 0) { 339 pci_msix_fini(msix_p); 340 i_ddi_set_msix(hdlp->ih_dip, NULL); 341 } 342 } 343 } 344 break; 345 case DDI_INTROP_GETPRI: 346 /* Get the priority */ 347 if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 348 return (DDI_FAILURE); 349 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 350 "priority = 0x%x\n", priority)); 351 *(int *)result = priority; 352 break; 353 case DDI_INTROP_SETPRI: 354 /* Validate the interrupt priority passed */ 355 if (*(int *)result > LOCK_LEVEL) 356 return (DDI_FAILURE); 357 358 /* Ensure that PSM is all initialized */ 359 if (psm_intr_ops == NULL) 360 return (DDI_FAILURE); 361 362 /* Change the priority */ 363 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 364 PSM_FAILURE) 365 return (DDI_FAILURE); 366 367 /* update ispec */ 368 isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 369 ispec = (struct intrspec *)isp; 370 if (ispec) 371 ispec->intrspec_pri = *(int *)result; 372 break; 373 case DDI_INTROP_ADDISR: 374 /* update ispec */ 375 isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 376 ispec = (struct intrspec *)isp; 377 if (ispec) { 378 ispec->intrspec_func = hdlp->ih_cb_func; 379 ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 380 pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 381 } 382 break; 383 case DDI_INTROP_REMISR: 384 /* Get the interrupt structure pointer */ 385 isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 386 ispec = (struct intrspec *)isp; 387 if (ispec) { 388 ispec->intrspec_func = (uint_t (*)()) 0; 389 ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 390 if (ihdl_plat_datap->ip_ksp != NULL) 391 pci_kstat_delete(ihdl_plat_datap->ip_ksp); 392 } 393 break; 394 case DDI_INTROP_GETCAP: 395 /* 396 * First check the config space and/or 397 * MSI capability register(s) 398 */ 399 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 400 pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 401 &pci_status); 402 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 403 pci_rval = pci_intx_get_cap(rdip, &pci_status); 404 405 /* next check with pcplusmp */ 406 if (psm_intr_ops != NULL) 407 psm_rval = (*psm_intr_ops)(rdip, hdlp, 408 PSM_INTR_OP_GET_CAP, &psm_status); 409 410 DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 411 "psm_status = %x, pci_rval = %x, pci_status = %x\n", 412 psm_rval, psm_status, pci_rval, pci_status)); 413 414 if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 415 *(int *)result = 0; 416 return (DDI_FAILURE); 417 } 418 419 if (psm_rval == PSM_SUCCESS) 420 *(int *)result = psm_status; 421 422 if (pci_rval == DDI_SUCCESS) 423 *(int *)result |= pci_status; 424 425 DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 426 *(int *)result)); 427 break; 428 case DDI_INTROP_SETCAP: 429 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 430 "SETCAP cap=0x%x\n", *(int *)result)); 431 if (psm_intr_ops == NULL) 432 return (DDI_FAILURE); 433 434 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 435 DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 436 " returned failure\n")); 437 return (DDI_FAILURE); 438 } 439 break; 440 case DDI_INTROP_ENABLE: 441 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 442 if (psm_intr_ops == NULL) 443 return (DDI_FAILURE); 444 445 if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 446 DDI_SUCCESS) 447 return (DDI_FAILURE); 448 449 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 450 "vector=0x%x\n", hdlp->ih_vector)); 451 break; 452 case DDI_INTROP_DISABLE: 453 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 454 if (psm_intr_ops == NULL) 455 return (DDI_FAILURE); 456 457 pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 458 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 459 "vector = %x\n", hdlp->ih_vector)); 460 break; 461 case DDI_INTROP_BLOCKENABLE: 462 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 463 "BLOCKENABLE\n")); 464 if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 465 DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 466 return (DDI_FAILURE); 467 } 468 469 /* Check if psm_intr_ops is NULL? */ 470 if (psm_intr_ops == NULL) 471 return (DDI_FAILURE); 472 473 count = hdlp->ih_scratch1; 474 h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 475 for (i = 0; i < count; i++) { 476 hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 477 if (pci_enable_intr(pdip, rdip, hdlp, 478 hdlp->ih_inum) != DDI_SUCCESS) { 479 DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 480 "pci_enable_intr failed for %d\n", i)); 481 for (j = 0; j < i; j++) { 482 hdlp = (ddi_intr_handle_impl_t *)h_array[j]; 483 pci_disable_intr(pdip, rdip, hdlp, 484 hdlp->ih_inum); 485 } 486 return (DDI_FAILURE); 487 } 488 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 489 "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 490 } 491 break; 492 case DDI_INTROP_BLOCKDISABLE: 493 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 494 "BLOCKDISABLE\n")); 495 if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 496 DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 497 return (DDI_FAILURE); 498 } 499 500 /* Check if psm_intr_ops is present */ 501 if (psm_intr_ops == NULL) 502 return (DDI_FAILURE); 503 504 count = hdlp->ih_scratch1; 505 h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 506 for (i = 0; i < count; i++) { 507 hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 508 pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 509 DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 510 "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 511 } 512 break; 513 case DDI_INTROP_SETMASK: 514 case DDI_INTROP_CLRMASK: 515 /* 516 * First handle in the config space 517 */ 518 if (intr_op == DDI_INTROP_SETMASK) { 519 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 520 pci_status = pci_msi_set_mask(rdip, 521 hdlp->ih_type, hdlp->ih_inum); 522 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 523 pci_status = pci_intx_set_mask(rdip); 524 } else { 525 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 526 pci_status = pci_msi_clr_mask(rdip, 527 hdlp->ih_type, hdlp->ih_inum); 528 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 529 pci_status = pci_intx_clr_mask(rdip); 530 } 531 532 /* For MSI/X; no need to check with pcplusmp */ 533 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 534 return (pci_status); 535 536 /* For fixed interrupts only: handle config space first */ 537 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 538 pci_status == DDI_SUCCESS) 539 break; 540 541 /* For fixed interrupts only: confer with pcplusmp next */ 542 if (psm_intr_ops != NULL) { 543 /* If interrupt is shared; do nothing */ 544 psm_rval = (*psm_intr_ops)(rdip, hdlp, 545 PSM_INTR_OP_GET_SHARED, &psm_status); 546 547 if (psm_rval == PSM_FAILURE || psm_status == 1) 548 return (pci_status); 549 550 /* Now, pcplusmp should try to set/clear the mask */ 551 if (intr_op == DDI_INTROP_SETMASK) 552 psm_rval = (*psm_intr_ops)(rdip, hdlp, 553 PSM_INTR_OP_SET_MASK, NULL); 554 else 555 psm_rval = (*psm_intr_ops)(rdip, hdlp, 556 PSM_INTR_OP_CLEAR_MASK, NULL); 557 } 558 return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 559 case DDI_INTROP_GETPENDING: 560 /* 561 * First check the config space and/or 562 * MSI capability register(s) 563 */ 564 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 565 pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 566 hdlp->ih_inum, &pci_status); 567 else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 568 pci_rval = pci_intx_get_pending(rdip, &pci_status); 569 570 /* On failure; next try with pcplusmp */ 571 if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 572 psm_rval = (*psm_intr_ops)(rdip, hdlp, 573 PSM_INTR_OP_GET_PENDING, &psm_status); 574 575 DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 576 "psm_rval = %x, psm_status = %x, pci_rval = %x, " 577 "pci_status = %x\n", psm_rval, psm_status, pci_rval, 578 pci_status)); 579 if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 580 *(int *)result = 0; 581 return (DDI_FAILURE); 582 } 583 584 if (psm_rval != PSM_FAILURE) 585 *(int *)result = psm_status; 586 else if (pci_rval != DDI_FAILURE) 587 *(int *)result = pci_status; 588 DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 589 *(int *)result)); 590 break; 591 case DDI_INTROP_NAVAIL: 592 if ((psm_intr_ops != NULL) && (pci_get_priority(rdip, 593 hdlp, &priority) == DDI_SUCCESS)) { 594 /* Priority in the handle not initialized yet */ 595 hdlp->ih_pri = priority; 596 (void) (*psm_intr_ops)(rdip, hdlp, 597 PSM_INTR_OP_NAVAIL_VECTORS, result); 598 } else { 599 *(int *)result = 1; 600 } 601 DDI_INTR_NEXDBG((CE_CONT, "pci: NAVAIL returned = %x\n", 602 *(int *)result)); 603 break; 604 default: 605 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 606 } 607 608 return (DDI_SUCCESS); 609 } 610 611 int 612 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 613 int vecirq, boolean_t is_irq) 614 { 615 ddi_intr_handle_impl_t get_info_ii_hdl; 616 617 if (is_irq) 618 intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 619 620 /* 621 * For this locally-declared and used handle, ih_private will contain a 622 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 623 * global interrupt handling. 624 */ 625 get_info_ii_hdl.ih_private = intrinfo_p; 626 get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 627 628 if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 629 PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 630 return (DDI_FAILURE); 631 632 return (DDI_SUCCESS); 633 } 634 635 636 int 637 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 638 { 639 int rval; 640 641 apic_get_intr_t intrinfo; 642 intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 643 rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 644 645 if (rval == DDI_SUCCESS) 646 return (intrinfo.avgi_cpu_id); 647 else 648 return (-1); 649 } 650 651 652 static int 653 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 654 ddi_intr_handle_impl_t *hdlp, uint32_t inum) 655 { 656 struct intrspec *ispec; 657 int irq; 658 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 659 660 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 661 (void *)hdlp, inum)); 662 663 /* Translate the interrupt if needed */ 664 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 665 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && ispec) 666 ispec->intrspec_vec = inum; 667 ihdl_plat_datap->ip_ispecp = ispec; 668 669 /* translate the interrupt if needed */ 670 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 671 DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 672 hdlp->ih_pri, irq)); 673 674 /* Add the interrupt handler */ 675 if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 676 DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 677 hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 678 return (DDI_FAILURE); 679 680 /* Note this really is an irq. */ 681 hdlp->ih_vector = (ushort_t)irq; 682 683 return (DDI_SUCCESS); 684 } 685 686 687 static void 688 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 689 ddi_intr_handle_impl_t *hdlp, uint32_t inum) 690 { 691 int irq; 692 struct intrspec *ispec; 693 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 694 695 DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 696 ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 697 if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && ispec) 698 ispec->intrspec_vec = inum; 699 ihdl_plat_datap->ip_ispecp = ispec; 700 701 /* translate the interrupt if needed */ 702 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 703 704 /* Disable the interrupt handler */ 705 rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 706 ihdl_plat_datap->ip_ispecp = NULL; 707 } 708 709 /* 710 * Miscellaneous library function 711 */ 712 int 713 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 714 { 715 int i; 716 int number; 717 int assigned_addr_len; 718 uint_t phys_hi = pci_rp->pci_phys_hi; 719 pci_regspec_t *assigned_addr; 720 721 if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 722 (phys_hi & PCI_RELOCAT_B)) 723 return (DDI_SUCCESS); 724 725 /* 726 * the "reg" property specifies relocatable, get and interpret the 727 * "assigned-addresses" property. 728 */ 729 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 730 "assigned-addresses", (int **)&assigned_addr, 731 (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 732 return (DDI_FAILURE); 733 734 /* 735 * Scan the "assigned-addresses" for one that matches the specified 736 * "reg" property entry. 737 */ 738 phys_hi &= PCI_CONF_ADDR_MASK; 739 number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 740 for (i = 0; i < number; i++) { 741 if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 742 phys_hi) { 743 pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 744 pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 745 ddi_prop_free(assigned_addr); 746 return (DDI_SUCCESS); 747 } 748 } 749 750 ddi_prop_free(assigned_addr); 751 return (DDI_FAILURE); 752 } 753 754 755 /* 756 * For pci_tools 757 */ 758 759 int 760 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 761 int mode, cred_t *credp, int *rvalp) 762 { 763 int rv = ENOTTY; 764 765 minor_t minor = getminor(dev); 766 767 switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 768 case PCI_TOOL_REG_MINOR_NUM: 769 770 switch (cmd) { 771 case PCITOOL_DEVICE_SET_REG: 772 case PCITOOL_DEVICE_GET_REG: 773 774 /* Require full privileges. */ 775 if (secpolicy_kmdb(credp)) 776 rv = EPERM; 777 else 778 rv = pcitool_dev_reg_ops(dip, (void *)arg, 779 cmd, mode); 780 break; 781 782 case PCITOOL_NEXUS_SET_REG: 783 case PCITOOL_NEXUS_GET_REG: 784 785 /* Require full privileges. */ 786 if (secpolicy_kmdb(credp)) 787 rv = EPERM; 788 else 789 rv = pcitool_bus_reg_ops(dip, (void *)arg, 790 cmd, mode); 791 break; 792 } 793 break; 794 795 case PCI_TOOL_INTR_MINOR_NUM: 796 797 switch (cmd) { 798 case PCITOOL_DEVICE_SET_INTR: 799 800 /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 801 if (secpolicy_ponline(credp)) { 802 rv = EPERM; 803 break; 804 } 805 806 /*FALLTHRU*/ 807 /* These require no special privileges. */ 808 case PCITOOL_DEVICE_GET_INTR: 809 case PCITOOL_DEVICE_NUM_INTR: 810 rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 811 break; 812 } 813 break; 814 815 /* 816 * All non-PCItool ioctls go through here, including: 817 * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 818 * those for attachment points with where minor number is the 819 * device number. 820 */ 821 default: 822 rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 823 credp, rvalp); 824 break; 825 } 826 827 return (rv); 828 } 829 830 831 /* 832 * These are the get and put functions to be shared with drivers. The 833 * mutex locking is done inside the functions referenced, rather than 834 * here, and is thus shared across PCI child drivers and any other 835 * consumers of PCI config space (such as the ACPI subsystem). 836 * 837 * The configuration space addresses come in as pointers. This is fine on 838 * a 32-bit system, where the VM space and configuration space are the same 839 * size. It's not such a good idea on a 64-bit system, where memory 840 * addresses are twice as large as configuration space addresses. At some 841 * point in the call tree we need to take a stand and say "you are 32-bit 842 * from this time forth", and this seems like a nice self-contained place. 843 */ 844 845 uint8_t 846 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 847 { 848 pci_acc_cfblk_t *cfp; 849 uint8_t rval; 850 int reg; 851 852 ASSERT64(((uintptr_t)addr >> 32) == 0); 853 854 reg = (int)(uintptr_t)addr; 855 856 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 857 858 rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 859 reg); 860 861 return (rval); 862 } 863 864 void 865 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 866 uint8_t *dev_addr, size_t repcount, uint_t flags) 867 { 868 uint8_t *h, *d; 869 870 h = host_addr; 871 d = dev_addr; 872 873 if (flags == DDI_DEV_AUTOINCR) 874 for (; repcount; repcount--) 875 *h++ = pci_config_rd8(hdlp, d++); 876 else 877 for (; repcount; repcount--) 878 *h++ = pci_config_rd8(hdlp, d); 879 } 880 881 uint16_t 882 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 883 { 884 pci_acc_cfblk_t *cfp; 885 uint16_t rval; 886 int reg; 887 888 ASSERT64(((uintptr_t)addr >> 32) == 0); 889 890 reg = (int)(uintptr_t)addr; 891 892 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 893 894 rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 895 reg); 896 897 return (rval); 898 } 899 900 void 901 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 902 uint16_t *dev_addr, size_t repcount, uint_t flags) 903 { 904 uint16_t *h, *d; 905 906 h = host_addr; 907 d = dev_addr; 908 909 if (flags == DDI_DEV_AUTOINCR) 910 for (; repcount; repcount--) 911 *h++ = pci_config_rd16(hdlp, d++); 912 else 913 for (; repcount; repcount--) 914 *h++ = pci_config_rd16(hdlp, d); 915 } 916 917 uint32_t 918 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 919 { 920 pci_acc_cfblk_t *cfp; 921 uint32_t rval; 922 int reg; 923 924 ASSERT64(((uintptr_t)addr >> 32) == 0); 925 926 reg = (int)(uintptr_t)addr; 927 928 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 929 930 rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 931 cfp->c_funcnum, reg); 932 933 return (rval); 934 } 935 936 void 937 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 938 uint32_t *dev_addr, size_t repcount, uint_t flags) 939 { 940 uint32_t *h, *d; 941 942 h = host_addr; 943 d = dev_addr; 944 945 if (flags == DDI_DEV_AUTOINCR) 946 for (; repcount; repcount--) 947 *h++ = pci_config_rd32(hdlp, d++); 948 else 949 for (; repcount; repcount--) 950 *h++ = pci_config_rd32(hdlp, d); 951 } 952 953 954 void 955 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 956 { 957 pci_acc_cfblk_t *cfp; 958 int reg; 959 960 ASSERT64(((uintptr_t)addr >> 32) == 0); 961 962 reg = (int)(uintptr_t)addr; 963 964 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 965 966 (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 967 cfp->c_funcnum, reg, value); 968 } 969 970 void 971 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 972 uint8_t *dev_addr, size_t repcount, uint_t flags) 973 { 974 uint8_t *h, *d; 975 976 h = host_addr; 977 d = dev_addr; 978 979 if (flags == DDI_DEV_AUTOINCR) 980 for (; repcount; repcount--) 981 pci_config_wr8(hdlp, d++, *h++); 982 else 983 for (; repcount; repcount--) 984 pci_config_wr8(hdlp, d, *h++); 985 } 986 987 void 988 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 989 { 990 pci_acc_cfblk_t *cfp; 991 int reg; 992 993 ASSERT64(((uintptr_t)addr >> 32) == 0); 994 995 reg = (int)(uintptr_t)addr; 996 997 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 998 999 (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 1000 cfp->c_funcnum, reg, value); 1001 } 1002 1003 void 1004 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1005 uint16_t *dev_addr, size_t repcount, uint_t flags) 1006 { 1007 uint16_t *h, *d; 1008 1009 h = host_addr; 1010 d = dev_addr; 1011 1012 if (flags == DDI_DEV_AUTOINCR) 1013 for (; repcount; repcount--) 1014 pci_config_wr16(hdlp, d++, *h++); 1015 else 1016 for (; repcount; repcount--) 1017 pci_config_wr16(hdlp, d, *h++); 1018 } 1019 1020 void 1021 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 1022 { 1023 pci_acc_cfblk_t *cfp; 1024 int reg; 1025 1026 ASSERT64(((uintptr_t)addr >> 32) == 0); 1027 1028 reg = (int)(uintptr_t)addr; 1029 1030 cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1031 1032 (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 1033 cfp->c_funcnum, reg, value); 1034 } 1035 1036 void 1037 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1038 uint32_t *dev_addr, size_t repcount, uint_t flags) 1039 { 1040 uint32_t *h, *d; 1041 1042 h = host_addr; 1043 d = dev_addr; 1044 1045 if (flags == DDI_DEV_AUTOINCR) 1046 for (; repcount; repcount--) 1047 pci_config_wr32(hdlp, d++, *h++); 1048 else 1049 for (; repcount; repcount--) 1050 pci_config_wr32(hdlp, d, *h++); 1051 } 1052 1053 uint64_t 1054 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 1055 { 1056 uint32_t lw_val; 1057 uint32_t hi_val; 1058 uint32_t *dp; 1059 uint64_t val; 1060 1061 dp = (uint32_t *)addr; 1062 lw_val = pci_config_rd32(hdlp, dp); 1063 dp++; 1064 hi_val = pci_config_rd32(hdlp, dp); 1065 val = ((uint64_t)hi_val << 32) | lw_val; 1066 return (val); 1067 } 1068 1069 void 1070 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 1071 { 1072 uint32_t lw_val; 1073 uint32_t hi_val; 1074 uint32_t *dp; 1075 1076 dp = (uint32_t *)addr; 1077 lw_val = (uint32_t)(value & 0xffffffff); 1078 hi_val = (uint32_t)(value >> 32); 1079 pci_config_wr32(hdlp, dp, lw_val); 1080 dp++; 1081 pci_config_wr32(hdlp, dp, hi_val); 1082 } 1083 1084 void 1085 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1086 uint64_t *dev_addr, size_t repcount, uint_t flags) 1087 { 1088 if (flags == DDI_DEV_AUTOINCR) { 1089 for (; repcount; repcount--) 1090 *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 1091 } else { 1092 for (; repcount; repcount--) 1093 *host_addr++ = pci_config_rd64(hdlp, dev_addr); 1094 } 1095 } 1096 1097 void 1098 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1099 uint64_t *dev_addr, size_t repcount, uint_t flags) 1100 { 1101 if (flags == DDI_DEV_AUTOINCR) { 1102 for (; repcount; repcount--) 1103 pci_config_wr64(hdlp, host_addr++, *dev_addr++); 1104 } else { 1105 for (; repcount; repcount--) 1106 pci_config_wr64(hdlp, host_addr++, *dev_addr); 1107 } 1108 } 1109 1110 1111 /* 1112 * Enable Legacy PCI config space access for the following four north bridges 1113 * Host bridge: AMD HyperTransport Technology Configuration 1114 * Host bridge: AMD Address Map 1115 * Host bridge: AMD DRAM Controller 1116 * Host bridge: AMD Miscellaneous Control 1117 */ 1118 int 1119 is_amd_northbridge(dev_info_t *dip) 1120 { 1121 int vendor_id, device_id; 1122 1123 vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1124 "vendor-id", -1); 1125 device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1126 "device-id", -1); 1127 1128 if (IS_AMD_NTBRIDGE(vendor_id, device_id)) 1129 return (0); 1130 1131 return (1); 1132 } 1133