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