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,10 +19,12 @@
* 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,10 +200,13 @@
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,10 +343,11 @@
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,30 +369,33 @@
"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)
- return (DDI_INTR_NOTFOUND);
+ 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;
- (void) (*psm_intr_ops)(rdip, hdlp,
- PSM_INTR_OP_FREE_VECTORS, NULL);
- return (DDI_EAGAIN);
+ 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,16 +408,12 @@
"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);
+ rv = DDI_FAILURE;
+ goto HANDLE_ALLOC_FAILURE;
}
}
}
if (pciepci) {
@@ -422,10 +427,23 @@
}
} 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) {