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>
*** 19,28 ****
--- 19,30 ----
* CDDL HEADER END
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright (c) 2012, Nexenta Systems, Inc. All rights reserved.
*/
/*
* File that has code which is common between pci(7d) and npe(7d)
* It shares the following:
*** 198,207 ****
--- 200,212 ----
int pciepci = 0;
int i, j, count;
int rv;
int behavior;
int cap_ptr;
+ boolean_t did_pci_config_setup = B_FALSE;
+ boolean_t did_intr_vec_alloc = B_FALSE;
+ boolean_t did_msi_cap_set = B_FALSE;
uint16_t msi_cap_base, msix_cap_base, cap_ctrl;
char *prop;
ddi_intrspec_t isp;
struct intrspec *ispec;
ddi_intr_handle_impl_t tmp_hdl;
*** 338,347 ****
--- 343,353 ----
if (i_ddi_get_pci_config_handle(rdip) == NULL) {
if (pci_config_setup(rdip, &handle) !=
DDI_SUCCESS)
return (DDI_FAILURE);
i_ddi_set_pci_config_handle(rdip, handle);
+ did_pci_config_setup = B_TRUE;
}
prop = NULL;
cap_ptr = 0;
if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
*** 363,392 ****
"cap property\n", (void *)rdip));
return (DDI_FAILURE);
}
}
i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
/*
* Allocate interrupt vectors
*/
(void) (*psm_intr_ops)(rdip, hdlp,
PSM_INTR_OP_ALLOC_VECTORS, result);
! if (*(int *)result == 0)
! return (DDI_INTR_NOTFOUND);
/* verify behavior flag and take appropriate action */
if ((behavior == DDI_INTR_ALLOC_STRICT) &&
(*(int *)result < hdlp->ih_scratch1)) {
DDI_INTR_NEXDBG((CE_CONT,
"pci_common_intr_ops: behavior %x, "
"couldn't get enough intrs\n", behavior));
hdlp->ih_scratch1 = *(int *)result;
! (void) (*psm_intr_ops)(rdip, hdlp,
! PSM_INTR_OP_FREE_VECTORS, NULL);
! return (DDI_EAGAIN);
}
if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
msix_p = pci_msix_init(hdlp->ih_dip);
--- 369,401 ----
"cap property\n", (void *)rdip));
return (DDI_FAILURE);
}
}
i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
+ did_msi_cap_set = B_TRUE;
/*
* Allocate interrupt vectors
*/
(void) (*psm_intr_ops)(rdip, hdlp,
PSM_INTR_OP_ALLOC_VECTORS, result);
! if (*(int *)result == 0) {
! rv = DDI_INTR_NOTFOUND;
! goto HANDLE_ALLOC_FAILURE;
! }
! did_intr_vec_alloc = B_TRUE;
/* verify behavior flag and take appropriate action */
if ((behavior == DDI_INTR_ALLOC_STRICT) &&
(*(int *)result < hdlp->ih_scratch1)) {
DDI_INTR_NEXDBG((CE_CONT,
"pci_common_intr_ops: behavior %x, "
"couldn't get enough intrs\n", behavior));
hdlp->ih_scratch1 = *(int *)result;
! rv = DDI_EAGAIN;
! goto HANDLE_ALLOC_FAILURE;
}
if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
msix_p = pci_msix_init(hdlp->ih_dip);
*** 399,414 ****
"table initilization failed"
", rdip 0x%p inum 0x%x\n",
(void *)rdip,
hdlp->ih_inum));
! (void) (*psm_intr_ops)(rdip,
! hdlp,
! PSM_INTR_OP_FREE_VECTORS,
! NULL);
!
! return (DDI_FAILURE);
}
}
}
if (pciepci) {
--- 408,419 ----
"table initilization failed"
", rdip 0x%p inum 0x%x\n",
(void *)rdip,
hdlp->ih_inum));
! rv = DDI_FAILURE;
! goto HANDLE_ALLOC_FAILURE;
}
}
}
if (pciepci) {
*** 422,431 ****
--- 427,449 ----
}
} else
return (DDI_FAILURE);
break;
+
+ HANDLE_ALLOC_FAILURE:
+ if (did_intr_vec_alloc == B_TRUE)
+ (void) (*psm_intr_ops)(rdip, hdlp,
+ PSM_INTR_OP_FREE_VECTORS, NULL);
+ if (did_msi_cap_set == B_TRUE)
+ i_ddi_set_msi_msix_cap_ptr(rdip, 0);
+ if (did_pci_config_setup == B_TRUE) {
+ (void) pci_config_teardown(&handle);
+ i_ddi_set_pci_config_handle(rdip, NULL);
+ }
+ return (rv);
+
case DDI_INTROP_FREE:
if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
(psm_intr_ops != NULL)) {
if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
0) {