1241 Need support for latest Emulex 10GbE
[illumos-gate.git] / usr / src / uts / common / io / fibre-channel / fca / oce / oce_intr.c
blob009aa46c58ada3f7fa875b75ac3f32f054e702d2
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 /* Copyright © 2003-2011 Emulex. All rights reserved. */
25 * Source file interrupt registration
26 * and related helper functions
29 #include <oce_impl.h>
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
41 int
42 oce_setup_intr(struct oce_dev *dev)
44 int ret;
45 int intr_types = 0;
46 int navail = 0;
47 int nsupported = 0;
48 int min = 0;
49 int nreqd = 0;
50 int nallocd = 0;
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 ");
57 return (DDI_FAILURE);
60 retry_intr:
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);
76 return (DDI_FAILURE);
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",
84 navail);
85 return (DDI_FAILURE);
88 if (navail < min) {
89 return (DDI_FAILURE);
92 /* if the requested number is more than available reset reqd */
93 if (navail < nreqd) {
94 nreqd = navail;
97 /* allocate htable */
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);
104 nallocd = 0;
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) {
110 goto fail_intr;
113 dev->num_vectors = nallocd;
114 if (nallocd < min) {
115 goto fail_intr;
119 * get the interrupt priority. Assumption is that all handlers have
120 * equal priority
123 ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
125 if (ret != DDI_SUCCESS) {
126 goto fail_intr;
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;
133 } else {
134 dev->rx_rings = 1;
137 return (DDI_SUCCESS);
139 fail_intr:
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");
146 goto retry_intr;
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)
161 int i;
163 /* release handlers */
164 for (i = 0; i < dev->num_vectors; i++) {
165 (void) ddi_intr_free(dev->htable[i]);
168 /* release htable */
169 kmem_free(dev->htable, dev->hsize);
170 dev->htable = NULL;
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)
185 int i = 0;
186 int ret;
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
209 void
210 oce_remove_handler(struct oce_dev *dev)
212 int nvec;
213 for (nvec = 0; nvec < dev->num_vectors; nvec++) {
214 (void) ddi_intr_remove_handler(dev->htable[nvec]);
218 void
219 oce_chip_ei(struct oce_dev *dev)
221 uint32_t reg;
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
235 void
236 oce_ei(struct oce_dev *dev)
238 int i;
239 int ret;
241 if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
242 (void) ddi_intr_block_enable(dev->htable, dev->num_vectors);
243 } else {
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]);
254 oce_chip_ei(dev);
255 } /* oce_ei */
257 void
258 oce_chip_di(struct oce_dev *dev)
260 uint32_t reg;
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
274 void
275 oce_di(struct oce_dev *dev)
277 int i;
278 int ret;
280 oce_chip_di(dev);
281 if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
282 (void) ddi_intr_block_disable(dev->htable, dev->num_vectors);
283 } else {
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);
293 } /* oce_di */
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
303 static uint_t
304 oce_isr(caddr_t arg1, caddr_t arg2)
306 struct oce_eq *eq;
307 struct oce_eqe *eqe;
308 uint16_t num_eqe = 0;
309 uint16_t cq_id;
310 struct oce_cq *cq;
311 struct oce_dev *dev;
313 _NOTE(ARGUNUSED(arg2));
315 eq = (struct oce_eq *)(void *)(arg1);
317 dev = eq->parent;
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;
334 cq = dev->cq[cq_id];
336 /* Call the completion handler */
337 (void) cq->cq_handler(cq->cb_arg);
339 /* clear valid bit and progress eqe */
340 eqe->u0.dw0 = 0;
341 RING_GET(eq->ring, 1);
342 eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
343 num_eqe++;
344 } /* for all EQEs */
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);
348 if (num_eqe > 0) {
349 return (DDI_INTR_CLAIMED);
350 } else {
351 return (DDI_INTR_UNCLAIMED);
353 } /* oce_msix_handler */