Print this page
3235 pci: pci_common_intr_ops() leaks ddi_acc_handle_t
Reviewed by: Dan McDonald <danmcd@nexenta.com>
Reviewed by: Boris Protopopov <boris.protopopov@nexenta.com>


   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>


 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


 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 &&




   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>


 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


 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 &&