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