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.
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.
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]
22 /* Copyright © 2003-2011 Emulex. All rights reserved. */
25 * Source file interrupt registration
26 * and related helper functions
32 static uint_t
oce_isr(caddr_t arg1
, caddr_t arg2
);
35 * top level function to setup interrupts
37 * dev - software handle to the device
39 * return DDI_SUCCESS => success, failure otherwise
42 oce_setup_intr(struct oce_dev
*dev
)
52 /* get supported intr types */
53 ret
= ddi_intr_get_supported_types(dev
->dip
, &intr_types
);
54 if (ret
!= DDI_SUCCESS
) {
55 oce_log(dev
, CE_WARN
, MOD_CONFIG
, "%s",
56 "Failed to retrieve intr types ");
61 if (intr_types
& DDI_INTR_TYPE_MSIX
) {
62 dev
->intr_type
= DDI_INTR_TYPE_MSIX
;
63 /* one vector is shared by MCC and Tx */
64 nreqd
= dev
->rx_rings
+ 1;
65 min
= OCE_MIN_VECTORS
;
66 } else if (intr_types
& DDI_INTR_TYPE_FIXED
) {
67 dev
->intr_type
= DDI_INTR_TYPE_FIXED
;
68 nreqd
= OCE_MIN_VECTORS
;
69 min
= OCE_MIN_VECTORS
;
72 ret
= ddi_intr_get_nintrs(dev
->dip
, dev
->intr_type
, &nsupported
);
73 if (ret
!= DDI_SUCCESS
) {
74 oce_log(dev
, CE_WARN
, MOD_CONFIG
,
75 "Could not get nintrs:0x%d", ret
);
79 /* get the number of vectors available */
80 ret
= ddi_intr_get_navail(dev
->dip
, dev
->intr_type
, &navail
);
81 if (ret
!= DDI_SUCCESS
|| navail
< min
) {
82 oce_log(dev
, CE_WARN
, MOD_CONFIG
,
83 "Could not get msix vectors:0x%x",
92 /* if the requested number is more than available reset reqd */
98 dev
->hsize
= nreqd
* sizeof (ddi_intr_handle_t
);
99 dev
->htable
= kmem_zalloc(dev
->hsize
, KM_NOSLEEP
);
101 if (dev
->htable
== NULL
)
102 return (DDI_FAILURE
);
105 /* allocate interrupt handlers */
106 ret
= ddi_intr_alloc(dev
->dip
, dev
->htable
, dev
->intr_type
,
107 0, nreqd
, &nallocd
, DDI_INTR_ALLOC_NORMAL
);
109 if (ret
!= DDI_SUCCESS
) {
113 dev
->num_vectors
= nallocd
;
119 * get the interrupt priority. Assumption is that all handlers have
123 ret
= ddi_intr_get_pri(dev
->htable
[0], &dev
->intr_pri
);
125 if (ret
!= DDI_SUCCESS
) {
129 (void) ddi_intr_get_cap(dev
->htable
[0], &dev
->intr_cap
);
131 if ((intr_types
& DDI_INTR_TYPE_MSIX
) && (nallocd
> 1)) {
132 dev
->rx_rings
= nallocd
- 1;
137 return (DDI_SUCCESS
);
140 (void) oce_teardown_intr(dev
);
141 if ((dev
->intr_type
== DDI_INTR_TYPE_MSIX
) &&
142 (intr_types
& DDI_INTR_TYPE_FIXED
)) {
143 intr_types
&= ~DDI_INTR_TYPE_MSIX
;
144 oce_log(dev
, CE_NOTE
, MOD_CONFIG
, "%s",
145 "Could not get MSIX vectors, trying for FIXED vectors");
148 return (DDI_FAILURE
);
152 * top level function to undo initialization in oce_setup_intr
154 * dev - software handle to the device
156 * return DDI_SUCCESS => success, failure otherwise
159 oce_teardown_intr(struct oce_dev
*dev
)
163 /* release handlers */
164 for (i
= 0; i
< dev
->num_vectors
; i
++) {
165 (void) ddi_intr_free(dev
->htable
[i
]);
169 kmem_free(dev
->htable
, dev
->hsize
);
172 return (DDI_SUCCESS
);
176 * helper function to add ISR based on interrupt type
178 * dev - software handle to the device
180 * return DDI_SUCCESS => success, failure otherwise
183 oce_setup_handlers(struct oce_dev
*dev
)
187 for (i
= 0; i
< dev
->num_vectors
; i
++) {
188 ret
= ddi_intr_add_handler(dev
->htable
[i
], oce_isr
,
189 (caddr_t
)dev
->eq
[i
], NULL
);
190 if (ret
!= DDI_SUCCESS
) {
191 oce_log(dev
, CE_WARN
, MOD_CONFIG
, "%s",
192 "Failed to add interrupt handlers");
193 for (i
--; i
>= 0; i
--) {
194 (void) ddi_intr_remove_handler(dev
->htable
[i
]);
196 return (DDI_FAILURE
);
199 return (DDI_SUCCESS
);
203 * helper function to remove ISRs added in oce_setup_handlers
205 * dev - software handle to the device
207 * return DDI_SUCCESS => success, failure otherwise
210 oce_remove_handler(struct oce_dev
*dev
)
213 for (nvec
= 0; nvec
< dev
->num_vectors
; nvec
++) {
214 (void) ddi_intr_remove_handler(dev
->htable
[nvec
]);
219 oce_chip_ei(struct oce_dev
*dev
)
223 reg
= OCE_CFG_READ32(dev
, PCICFG_INTR_CTRL
);
224 reg
|= HOSTINTR_MASK
;
225 OCE_CFG_WRITE32(dev
, PCICFG_INTR_CTRL
, reg
);
229 * function to enable interrupts
231 * dev - software handle to the device
233 * return DDI_SUCCESS => success, failure otherwise
236 oce_ei(struct oce_dev
*dev
)
241 if (dev
->intr_cap
& DDI_INTR_FLAG_BLOCK
) {
242 (void) ddi_intr_block_enable(dev
->htable
, dev
->num_vectors
);
245 for (i
= 0; i
< dev
->num_vectors
; i
++) {
246 ret
= ddi_intr_enable(dev
->htable
[i
]);
247 if (ret
!= DDI_SUCCESS
) {
248 for (i
--; i
>= 0; i
--) {
249 (void) ddi_intr_disable(dev
->htable
[i
]);
258 oce_chip_di(struct oce_dev
*dev
)
262 reg
= OCE_CFG_READ32(dev
, PCICFG_INTR_CTRL
);
263 reg
&= ~HOSTINTR_MASK
;
264 OCE_CFG_WRITE32(dev
, PCICFG_INTR_CTRL
, reg
);
268 * function to disable interrupts
270 * dev - software handle to the device
272 * return DDI_SUCCESS => success, failure otherwise
275 oce_di(struct oce_dev
*dev
)
281 if (dev
->intr_cap
& DDI_INTR_FLAG_BLOCK
) {
282 (void) ddi_intr_block_disable(dev
->htable
, dev
->num_vectors
);
284 for (i
= 0; i
< dev
->num_vectors
; i
++) {
285 ret
= ddi_intr_disable(dev
->htable
[i
]);
286 if (ret
!= DDI_SUCCESS
) {
287 oce_log(dev
, CE_WARN
, MOD_CONFIG
,
288 "Failed to disable interrupts 0x%x", ret
);
296 * command interrupt handler routine added to all vectors
298 * arg1 = callback data
299 * arg2 - callback data
301 * return DDI_INTR_CLAIMED => interrupt was claimed by the ISR
304 oce_isr(caddr_t arg1
, caddr_t arg2
)
308 uint16_t num_eqe
= 0;
313 _NOTE(ARGUNUSED(arg2
));
315 eq
= (struct oce_eq
*)(void *)(arg1
);
319 eqe
= RING_GET_CONSUMER_ITEM_VA(eq
->ring
, struct oce_eqe
);
321 while (eqe
->u0
.dw0
) {
323 eqe
->u0
.dw0
= LE_32(eqe
->u0
.dw0
);
325 /* if not CQ then continue else flag an error */
326 if (EQ_MAJOR_CODE_COMPLETION
!= eqe
->u0
.s
.major_code
) {
327 oce_log(dev
, CE_WARN
, MOD_ISR
,
328 "NOT a CQ event. 0x%x",
329 eqe
->u0
.s
.major_code
);
332 /* get the cq from the eqe */
333 cq_id
= eqe
->u0
.s
.resource_id
% OCE_MAX_CQ
;
336 /* Call the completion handler */
337 (void) cq
->cq_handler(cq
->cb_arg
);
339 /* clear valid bit and progress eqe */
341 RING_GET(eq
->ring
, 1);
342 eqe
= RING_GET_CONSUMER_ITEM_VA(eq
->ring
, struct oce_eqe
);
346 /* ring the eq doorbell, signify that it's done processing */
347 oce_arm_eq(dev
, eq
->eq_id
, num_eqe
, B_TRUE
, B_TRUE
);
349 return (DDI_INTR_CLAIMED
);
351 return (DDI_INTR_UNCLAIMED
);
353 } /* oce_msix_handler */