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