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