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         hdlp->ih_vector = irq;
 954 
 955         return (DDI_SUCCESS);
 956 }
 957 
 958 
 959 static void
 960 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
 961     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
 962 {
 963         int             irq;
 964         struct intrspec *ispec;
 965         ihdl_plat_t     *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
 966 
 967         DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
 968         ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
 969         if (ispec == NULL)
 970                 return;
 971         if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
 972                 ispec->intrspec_vec = inum;
 973                 ispec->intrspec_pri = hdlp->ih_pri;
 974         }
 975         ihdl_plat_datap->ip_ispecp = ispec;
 976 
 977         /* translate the interrupt if needed */
 978         (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
 979 
 980         /* Disable the interrupt handler */
 981         rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
 982         ihdl_plat_datap->ip_ispecp = NULL;
 983 }
 984 
 985 /*
 986  * Miscellaneous library function
 987  */
 988 int
 989 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
 990 {
 991         int             i;
 992         int             number;
 993         int             assigned_addr_len;
 994         uint_t          phys_hi = pci_rp->pci_phys_hi;
 995         pci_regspec_t   *assigned_addr;
 996 
 997         if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
 998             (phys_hi & PCI_RELOCAT_B))
 999                 return (DDI_SUCCESS);
1000 
1001         /*
1002          * the "reg" property specifies relocatable, get and interpret the
1003          * "assigned-addresses" property.
1004          */
1005         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1006             "assigned-addresses", (int **)&assigned_addr,
1007             (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
1008                 return (DDI_FAILURE);
1009 
1010         /*
1011          * Scan the "assigned-addresses" for one that matches the specified
1012          * "reg" property entry.
1013          */
1014         phys_hi &= PCI_CONF_ADDR_MASK;
1015         number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
1016         for (i = 0; i < number; i++) {
1017                 if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
1018                     phys_hi) {
1019                         pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
1020                         pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
1021                         ddi_prop_free(assigned_addr);
1022                         return (DDI_SUCCESS);
1023                 }
1024         }
1025 
1026         ddi_prop_free(assigned_addr);
1027         return (DDI_FAILURE);
1028 }
1029 
1030 
1031 /*
1032  * To handle PCI tool ioctls
1033  */
1034 
1035 /*ARGSUSED*/
1036 int
1037 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
1038     int mode, cred_t *credp, int *rvalp)
1039 {
1040         minor_t minor = getminor(dev);
1041         int     rv = ENOTTY;
1042 
1043         switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1044         case PCI_TOOL_REG_MINOR_NUM:
1045 
1046                 switch (cmd) {
1047                 case PCITOOL_DEVICE_SET_REG:
1048                 case PCITOOL_DEVICE_GET_REG:
1049 
1050                         /* Require full privileges. */
1051                         if (secpolicy_kmdb(credp))
1052                                 rv = EPERM;
1053                         else
1054                                 rv = pcitool_dev_reg_ops(dip, (void *)arg,
1055                                     cmd, mode);
1056                         break;
1057 
1058                 case PCITOOL_NEXUS_SET_REG:
1059                 case PCITOOL_NEXUS_GET_REG:
1060 
1061                         /* Require full privileges. */
1062                         if (secpolicy_kmdb(credp))
1063                                 rv = EPERM;
1064                         else
1065                                 rv = pcitool_bus_reg_ops(dip, (void *)arg,
1066                                     cmd, mode);
1067                         break;
1068                 }
1069                 break;
1070 
1071         case PCI_TOOL_INTR_MINOR_NUM:
1072 
1073                 switch (cmd) {
1074                 case PCITOOL_DEVICE_SET_INTR:
1075 
1076                         /* Require PRIV_SYS_RES_CONFIG, same as psradm */
1077                         if (secpolicy_ponline(credp)) {
1078                                 rv = EPERM;
1079                                 break;
1080                         }
1081 
1082                 /*FALLTHRU*/
1083                 /* These require no special privileges. */
1084                 case PCITOOL_DEVICE_GET_INTR:
1085                 case PCITOOL_SYSTEM_INTR_INFO:
1086                         rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
1087                         break;
1088                 }
1089                 break;
1090 
1091         default:
1092                 break;
1093         }
1094 
1095         return (rv);
1096 }
1097 
1098 
1099 int
1100 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
1101 {
1102         size_t size = in_args->size;
1103         uintptr_t dev_addr = in_args->dev_addr;
1104         uintptr_t host_addr = in_args->host_addr;
1105         ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1106         ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1107         size_t repcount = in_args->repcount;
1108         uint_t flags = in_args->flags;
1109         int err = DDI_SUCCESS;
1110 
1111         /*
1112          * if no handle then this is a poke. We have to return failure here
1113          * as we have no way of knowing whether this is a MEM or IO space access
1114          */
1115         if (in_args->handle == NULL)
1116                 return (DDI_FAILURE);
1117 
1118         /*
1119          * rest of this function is actually for cautious puts
1120          */
1121         for (; repcount; repcount--) {
1122                 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1123                         switch (size) {
1124                         case sizeof (uint8_t):
1125                                 pci_config_wr8(hp, (uint8_t *)dev_addr,
1126                                     *(uint8_t *)host_addr);
1127                                 break;
1128                         case sizeof (uint16_t):
1129                                 pci_config_wr16(hp, (uint16_t *)dev_addr,
1130                                     *(uint16_t *)host_addr);
1131                                 break;
1132                         case sizeof (uint32_t):
1133                                 pci_config_wr32(hp, (uint32_t *)dev_addr,
1134                                     *(uint32_t *)host_addr);
1135                                 break;
1136                         case sizeof (uint64_t):
1137                                 pci_config_wr64(hp, (uint64_t *)dev_addr,
1138                                     *(uint64_t *)host_addr);
1139                                 break;
1140                         default:
1141                                 err = DDI_FAILURE;
1142                                 break;
1143                         }
1144                 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1145                         if (hdlp->ah_acc.devacc_attr_endian_flags ==
1146                             DDI_STRUCTURE_BE_ACC) {
1147                                 switch (size) {
1148                                 case sizeof (uint8_t):
1149                                         i_ddi_io_put8(hp,
1150                                             (uint8_t *)dev_addr,
1151                                             *(uint8_t *)host_addr);
1152                                         break;
1153                                 case sizeof (uint16_t):
1154                                         i_ddi_io_swap_put16(hp,
1155                                             (uint16_t *)dev_addr,
1156                                             *(uint16_t *)host_addr);
1157                                         break;
1158                                 case sizeof (uint32_t):
1159                                         i_ddi_io_swap_put32(hp,
1160                                             (uint32_t *)dev_addr,
1161                                             *(uint32_t *)host_addr);
1162                                         break;
1163                                 /*
1164                                  * note the 64-bit case is a dummy
1165                                  * function - so no need to swap
1166                                  */
1167                                 case sizeof (uint64_t):
1168                                         i_ddi_io_put64(hp,
1169                                             (uint64_t *)dev_addr,
1170                                             *(uint64_t *)host_addr);
1171                                         break;
1172                                 default:
1173                                         err = DDI_FAILURE;
1174                                         break;
1175                                 }
1176                         } else {
1177                                 switch (size) {
1178                                 case sizeof (uint8_t):
1179                                         i_ddi_io_put8(hp,
1180                                             (uint8_t *)dev_addr,
1181                                             *(uint8_t *)host_addr);
1182                                         break;
1183                                 case sizeof (uint16_t):
1184                                         i_ddi_io_put16(hp,
1185                                             (uint16_t *)dev_addr,
1186                                             *(uint16_t *)host_addr);
1187                                         break;
1188                                 case sizeof (uint32_t):
1189                                         i_ddi_io_put32(hp,
1190                                             (uint32_t *)dev_addr,
1191                                             *(uint32_t *)host_addr);
1192                                         break;
1193                                 case sizeof (uint64_t):
1194                                         i_ddi_io_put64(hp,
1195                                             (uint64_t *)dev_addr,
1196                                             *(uint64_t *)host_addr);
1197                                         break;
1198                                 default:
1199                                         err = DDI_FAILURE;
1200                                         break;
1201                                 }
1202                         }
1203                 } else {
1204                         if (hdlp->ah_acc.devacc_attr_endian_flags ==
1205                             DDI_STRUCTURE_BE_ACC) {
1206                                 switch (size) {
1207                                 case sizeof (uint8_t):
1208                                         *(uint8_t *)dev_addr =
1209                                             *(uint8_t *)host_addr;
1210                                         break;
1211                                 case sizeof (uint16_t):
1212                                         *(uint16_t *)dev_addr =
1213                                             ddi_swap16(*(uint16_t *)host_addr);
1214                                         break;
1215                                 case sizeof (uint32_t):
1216                                         *(uint32_t *)dev_addr =
1217                                             ddi_swap32(*(uint32_t *)host_addr);
1218                                         break;
1219                                 case sizeof (uint64_t):
1220                                         *(uint64_t *)dev_addr =
1221                                             ddi_swap64(*(uint64_t *)host_addr);
1222                                         break;
1223                                 default:
1224                                         err = DDI_FAILURE;
1225                                         break;
1226                                 }
1227                         } else {
1228                                 switch (size) {
1229                                 case sizeof (uint8_t):
1230                                         *(uint8_t *)dev_addr =
1231                                             *(uint8_t *)host_addr;
1232                                         break;
1233                                 case sizeof (uint16_t):
1234                                         *(uint16_t *)dev_addr =
1235                                             *(uint16_t *)host_addr;
1236                                         break;
1237                                 case sizeof (uint32_t):
1238                                         *(uint32_t *)dev_addr =
1239                                             *(uint32_t *)host_addr;
1240                                         break;
1241                                 case sizeof (uint64_t):
1242                                         *(uint64_t *)dev_addr =
1243                                             *(uint64_t *)host_addr;
1244                                         break;
1245                                 default:
1246                                         err = DDI_FAILURE;
1247                                         break;
1248                                 }
1249                         }
1250                 }
1251                 host_addr += size;
1252                 if (flags == DDI_DEV_AUTOINCR)
1253                         dev_addr += size;
1254         }
1255         return (err);
1256 }
1257 
1258 
1259 int
1260 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
1261 {
1262         ddi_acc_impl_t  *ap = (ddi_acc_impl_t *)hp->ah_platform_private;
1263 
1264         /* endian-ness check */
1265         if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
1266                 return (DDI_FAILURE);
1267 
1268         /*
1269          * range check
1270          */
1271         if ((offset >= PCI_CONF_HDR_SIZE) ||
1272             (len > PCI_CONF_HDR_SIZE) ||
1273             (offset + len > PCI_CONF_HDR_SIZE))
1274                 return (DDI_FAILURE);
1275 
1276         ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
1277         /*
1278          * always use cautious mechanism for config space gets
1279          */
1280         ap->ahi_get8 = i_ddi_caut_get8;
1281         ap->ahi_get16 = i_ddi_caut_get16;
1282         ap->ahi_get32 = i_ddi_caut_get32;
1283         ap->ahi_get64 = i_ddi_caut_get64;
1284         ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
1285         ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
1286         ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
1287         ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
1288         if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
1289                 ap->ahi_put8 = i_ddi_caut_put8;
1290                 ap->ahi_put16 = i_ddi_caut_put16;
1291                 ap->ahi_put32 = i_ddi_caut_put32;
1292                 ap->ahi_put64 = i_ddi_caut_put64;
1293                 ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
1294                 ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
1295                 ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
1296                 ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
1297         } else {
1298                 ap->ahi_put8 = pci_config_wr8;
1299                 ap->ahi_put16 = pci_config_wr16;
1300                 ap->ahi_put32 = pci_config_wr32;
1301                 ap->ahi_put64 = pci_config_wr64;
1302                 ap->ahi_rep_put8 = pci_config_rep_wr8;
1303                 ap->ahi_rep_put16 = pci_config_rep_wr16;
1304                 ap->ahi_rep_put32 = pci_config_rep_wr32;
1305                 ap->ahi_rep_put64 = pci_config_rep_wr64;
1306         }
1307 
1308         /* Initialize to default check/notify functions */
1309         ap->ahi_fault_check = i_ddi_acc_fault_check;
1310         ap->ahi_fault_notify = i_ddi_acc_fault_notify;
1311         ap->ahi_fault = 0;
1312         impl_acc_err_init(hp);
1313         return (DDI_SUCCESS);
1314 }
1315 
1316 
1317 int
1318 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
1319 {
1320         size_t size = in_args->size;
1321         uintptr_t dev_addr = in_args->dev_addr;
1322         uintptr_t host_addr = in_args->host_addr;
1323         ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
1324         ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
1325         size_t repcount = in_args->repcount;
1326         uint_t flags = in_args->flags;
1327         int err = DDI_SUCCESS;
1328 
1329         /*
1330          * if no handle then this is a peek. We have to return failure here
1331          * as we have no way of knowing whether this is a MEM or IO space access
1332          */
1333         if (in_args->handle == NULL)
1334                 return (DDI_FAILURE);
1335 
1336         for (; repcount; repcount--) {
1337                 if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
1338                         switch (size) {
1339                         case sizeof (uint8_t):
1340                                 *(uint8_t *)host_addr = pci_config_rd8(hp,
1341                                     (uint8_t *)dev_addr);
1342                                 break;
1343                         case sizeof (uint16_t):
1344                                 *(uint16_t *)host_addr = pci_config_rd16(hp,
1345                                     (uint16_t *)dev_addr);
1346                                 break;
1347                         case sizeof (uint32_t):
1348                                 *(uint32_t *)host_addr = pci_config_rd32(hp,
1349                                     (uint32_t *)dev_addr);
1350                                 break;
1351                         case sizeof (uint64_t):
1352                                 *(uint64_t *)host_addr = pci_config_rd64(hp,
1353                                     (uint64_t *)dev_addr);
1354                                 break;
1355                         default:
1356                                 err = DDI_FAILURE;
1357                                 break;
1358                         }
1359                 } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
1360                         if (hdlp->ah_acc.devacc_attr_endian_flags ==
1361                             DDI_STRUCTURE_BE_ACC) {
1362                                 switch (size) {
1363                                 case sizeof (uint8_t):
1364                                         *(uint8_t *)host_addr =
1365                                             i_ddi_io_get8(hp,
1366                                             (uint8_t *)dev_addr);
1367                                         break;
1368                                 case sizeof (uint16_t):
1369                                         *(uint16_t *)host_addr =
1370                                             i_ddi_io_swap_get16(hp,
1371                                             (uint16_t *)dev_addr);
1372                                         break;
1373                                 case sizeof (uint32_t):
1374                                         *(uint32_t *)host_addr =
1375                                             i_ddi_io_swap_get32(hp,
1376                                             (uint32_t *)dev_addr);
1377                                         break;
1378                                 /*
1379                                  * note the 64-bit case is a dummy
1380                                  * function - so no need to swap
1381                                  */
1382                                 case sizeof (uint64_t):
1383                                         *(uint64_t *)host_addr =
1384                                             i_ddi_io_get64(hp,
1385                                             (uint64_t *)dev_addr);
1386                                         break;
1387                                 default:
1388                                         err = DDI_FAILURE;
1389                                         break;
1390                                 }
1391                         } else {
1392                                 switch (size) {
1393                                 case sizeof (uint8_t):
1394                                         *(uint8_t *)host_addr =
1395                                             i_ddi_io_get8(hp,
1396                                             (uint8_t *)dev_addr);
1397                                         break;
1398                                 case sizeof (uint16_t):
1399                                         *(uint16_t *)host_addr =
1400                                             i_ddi_io_get16(hp,
1401                                             (uint16_t *)dev_addr);
1402                                         break;
1403                                 case sizeof (uint32_t):
1404                                         *(uint32_t *)host_addr =
1405                                             i_ddi_io_get32(hp,
1406                                             (uint32_t *)dev_addr);
1407                                         break;
1408                                 case sizeof (uint64_t):
1409                                         *(uint64_t *)host_addr =
1410                                             i_ddi_io_get64(hp,
1411                                             (uint64_t *)dev_addr);
1412                                         break;
1413                                 default:
1414                                         err = DDI_FAILURE;
1415                                         break;
1416                                 }
1417                         }
1418                 } else {
1419                         if (hdlp->ah_acc.devacc_attr_endian_flags ==
1420                             DDI_STRUCTURE_BE_ACC) {
1421                                 switch (in_args->size) {
1422                                 case sizeof (uint8_t):
1423                                         *(uint8_t *)host_addr =
1424                                             *(uint8_t *)dev_addr;
1425                                         break;
1426                                 case sizeof (uint16_t):
1427                                         *(uint16_t *)host_addr =
1428                                             ddi_swap16(*(uint16_t *)dev_addr);
1429                                         break;
1430                                 case sizeof (uint32_t):
1431                                         *(uint32_t *)host_addr =
1432                                             ddi_swap32(*(uint32_t *)dev_addr);
1433                                         break;
1434                                 case sizeof (uint64_t):
1435                                         *(uint64_t *)host_addr =
1436                                             ddi_swap64(*(uint64_t *)dev_addr);
1437                                         break;
1438                                 default:
1439                                         err = DDI_FAILURE;
1440                                         break;
1441                                 }
1442                         } else {
1443                                 switch (in_args->size) {
1444                                 case sizeof (uint8_t):
1445                                         *(uint8_t *)host_addr =
1446                                             *(uint8_t *)dev_addr;
1447                                         break;
1448                                 case sizeof (uint16_t):
1449                                         *(uint16_t *)host_addr =
1450                                             *(uint16_t *)dev_addr;
1451                                         break;
1452                                 case sizeof (uint32_t):
1453                                         *(uint32_t *)host_addr =
1454                                             *(uint32_t *)dev_addr;
1455                                         break;
1456                                 case sizeof (uint64_t):
1457                                         *(uint64_t *)host_addr =
1458                                             *(uint64_t *)dev_addr;
1459                                         break;
1460                                 default:
1461                                         err = DDI_FAILURE;
1462                                         break;
1463                                 }
1464                         }
1465                 }
1466                 host_addr += size;
1467                 if (flags == DDI_DEV_AUTOINCR)
1468                         dev_addr += size;
1469         }
1470         return (err);
1471 }
1472 
1473 /*ARGSUSED*/
1474 int
1475 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
1476         ddi_ctl_enum_t ctlop, void *arg, void *result)
1477 {
1478         if (ctlop == DDI_CTLOPS_PEEK)
1479                 return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
1480         else
1481                 return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
1482 }
1483 
1484 /*
1485  * These are the get and put functions to be shared with drivers. The
1486  * mutex locking is done inside the functions referenced, rather than
1487  * here, and is thus shared across PCI child drivers and any other
1488  * consumers of PCI config space (such as the ACPI subsystem).
1489  *
1490  * The configuration space addresses come in as pointers.  This is fine on
1491  * a 32-bit system, where the VM space and configuration space are the same
1492  * size.  It's not such a good idea on a 64-bit system, where memory
1493  * addresses are twice as large as configuration space addresses.  At some
1494  * point in the call tree we need to take a stand and say "you are 32-bit
1495  * from this time forth", and this seems like a nice self-contained place.
1496  */
1497 
1498 uint8_t
1499 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1500 {
1501         pci_acc_cfblk_t *cfp;
1502         uint8_t rval;
1503         int reg;
1504 
1505         ASSERT64(((uintptr_t)addr >> 32) == 0);
1506 
1507         reg = (int)(uintptr_t)addr;
1508 
1509         cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1510 
1511         rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1512             reg);
1513 
1514         return (rval);
1515 }
1516 
1517 void
1518 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1519         uint8_t *dev_addr, size_t repcount, uint_t flags)
1520 {
1521         uint8_t *h, *d;
1522 
1523         h = host_addr;
1524         d = dev_addr;
1525 
1526         if (flags == DDI_DEV_AUTOINCR)
1527                 for (; repcount; repcount--)
1528                         *h++ = pci_config_rd8(hdlp, d++);
1529         else
1530                 for (; repcount; repcount--)
1531                         *h++ = pci_config_rd8(hdlp, d);
1532 }
1533 
1534 uint16_t
1535 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1536 {
1537         pci_acc_cfblk_t *cfp;
1538         uint16_t rval;
1539         int reg;
1540 
1541         ASSERT64(((uintptr_t)addr >> 32) == 0);
1542 
1543         reg = (int)(uintptr_t)addr;
1544 
1545         cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1546 
1547         rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1548             reg);
1549 
1550         return (rval);
1551 }
1552 
1553 void
1554 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1555         uint16_t *dev_addr, size_t repcount, uint_t flags)
1556 {
1557         uint16_t *h, *d;
1558 
1559         h = host_addr;
1560         d = dev_addr;
1561 
1562         if (flags == DDI_DEV_AUTOINCR)
1563                 for (; repcount; repcount--)
1564                         *h++ = pci_config_rd16(hdlp, d++);
1565         else
1566                 for (; repcount; repcount--)
1567                         *h++ = pci_config_rd16(hdlp, d);
1568 }
1569 
1570 uint32_t
1571 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1572 {
1573         pci_acc_cfblk_t *cfp;
1574         uint32_t rval;
1575         int reg;
1576 
1577         ASSERT64(((uintptr_t)addr >> 32) == 0);
1578 
1579         reg = (int)(uintptr_t)addr;
1580 
1581         cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1582 
1583         rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1584             cfp->c_funcnum, reg);
1585 
1586         return (rval);
1587 }
1588 
1589 void
1590 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1591         uint32_t *dev_addr, size_t repcount, uint_t flags)
1592 {
1593         uint32_t *h, *d;
1594 
1595         h = host_addr;
1596         d = dev_addr;
1597 
1598         if (flags == DDI_DEV_AUTOINCR)
1599                 for (; repcount; repcount--)
1600                         *h++ = pci_config_rd32(hdlp, d++);
1601         else
1602                 for (; repcount; repcount--)
1603                         *h++ = pci_config_rd32(hdlp, d);
1604 }
1605 
1606 
1607 void
1608 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1609 {
1610         pci_acc_cfblk_t *cfp;
1611         int reg;
1612 
1613         ASSERT64(((uintptr_t)addr >> 32) == 0);
1614 
1615         reg = (int)(uintptr_t)addr;
1616 
1617         cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1618 
1619         (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1620             cfp->c_funcnum, reg, value);
1621 }
1622 
1623 void
1624 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1625         uint8_t *dev_addr, size_t repcount, uint_t flags)
1626 {
1627         uint8_t *h, *d;
1628 
1629         h = host_addr;
1630         d = dev_addr;
1631 
1632         if (flags == DDI_DEV_AUTOINCR)
1633                 for (; repcount; repcount--)
1634                         pci_config_wr8(hdlp, d++, *h++);
1635         else
1636                 for (; repcount; repcount--)
1637                         pci_config_wr8(hdlp, d, *h++);
1638 }
1639 
1640 void
1641 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1642 {
1643         pci_acc_cfblk_t *cfp;
1644         int reg;
1645 
1646         ASSERT64(((uintptr_t)addr >> 32) == 0);
1647 
1648         reg = (int)(uintptr_t)addr;
1649 
1650         cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1651 
1652         (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1653             cfp->c_funcnum, reg, value);
1654 }
1655 
1656 void
1657 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1658         uint16_t *dev_addr, size_t repcount, uint_t flags)
1659 {
1660         uint16_t *h, *d;
1661 
1662         h = host_addr;
1663         d = dev_addr;
1664 
1665         if (flags == DDI_DEV_AUTOINCR)
1666                 for (; repcount; repcount--)
1667                         pci_config_wr16(hdlp, d++, *h++);
1668         else
1669                 for (; repcount; repcount--)
1670                         pci_config_wr16(hdlp, d, *h++);
1671 }
1672 
1673 void
1674 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1675 {
1676         pci_acc_cfblk_t *cfp;
1677         int reg;
1678 
1679         ASSERT64(((uintptr_t)addr >> 32) == 0);
1680 
1681         reg = (int)(uintptr_t)addr;
1682 
1683         cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1684 
1685         (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1686             cfp->c_funcnum, reg, value);
1687 }
1688 
1689 void
1690 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1691         uint32_t *dev_addr, size_t repcount, uint_t flags)
1692 {
1693         uint32_t *h, *d;
1694 
1695         h = host_addr;
1696         d = dev_addr;
1697 
1698         if (flags == DDI_DEV_AUTOINCR)
1699                 for (; repcount; repcount--)
1700                         pci_config_wr32(hdlp, d++, *h++);
1701         else
1702                 for (; repcount; repcount--)
1703                         pci_config_wr32(hdlp, d, *h++);
1704 }
1705 
1706 uint64_t
1707 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1708 {
1709         uint32_t lw_val;
1710         uint32_t hi_val;
1711         uint32_t *dp;
1712         uint64_t val;
1713 
1714         dp = (uint32_t *)addr;
1715         lw_val = pci_config_rd32(hdlp, dp);
1716         dp++;
1717         hi_val = pci_config_rd32(hdlp, dp);
1718         val = ((uint64_t)hi_val << 32) | lw_val;
1719         return (val);
1720 }
1721 
1722 void
1723 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1724 {
1725         uint32_t lw_val;
1726         uint32_t hi_val;
1727         uint32_t *dp;
1728 
1729         dp = (uint32_t *)addr;
1730         lw_val = (uint32_t)(value & 0xffffffff);
1731         hi_val = (uint32_t)(value >> 32);
1732         pci_config_wr32(hdlp, dp, lw_val);
1733         dp++;
1734         pci_config_wr32(hdlp, dp, hi_val);
1735 }
1736 
1737 void
1738 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1739         uint64_t *dev_addr, size_t repcount, uint_t flags)
1740 {
1741         if (flags == DDI_DEV_AUTOINCR) {
1742                 for (; repcount; repcount--)
1743                         *host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1744         } else {
1745                 for (; repcount; repcount--)
1746                         *host_addr++ = pci_config_rd64(hdlp, dev_addr);
1747         }
1748 }
1749 
1750 void
1751 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1752         uint64_t *dev_addr, size_t repcount, uint_t flags)
1753 {
1754         if (flags == DDI_DEV_AUTOINCR) {
1755                 for (; repcount; repcount--)
1756                         pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1757         } else {
1758                 for (; repcount; repcount--)
1759                         pci_config_wr64(hdlp, host_addr++, *dev_addr);
1760         }
1761 }