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