2 * CDDL HEADER START
3 *
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 /* Copyright © 2003-2011 Emulex. All rights reserved. */
23
24 /*
25 * Source file interrupt registration
26 * and related helper functions
27 */
28
29 #include <oce_impl.h>
30
31
32 static uint_t oce_isr(caddr_t arg1, caddr_t arg2);
33
34 /*
35 * top level function to setup interrupts
36 *
37 * dev - software handle to the device
38 *
39 * return DDI_SUCCESS => success, failure otherwise
40 */
41 int
42 oce_setup_intr(struct oce_dev *dev)
43 {
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;
51
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);
58 }
59
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;
70 }
71
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);
77 }
78
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);
86 }
87
88 if (navail < min) {
89 return (DDI_FAILURE);
90 }
91
92 /* if the requested number is more than available reset reqd */
93 if (navail < nreqd) {
94 nreqd = navail;
95 }
96
97 /* allocate htable */
98 dev->hsize = nreqd * sizeof (ddi_intr_handle_t);
99 dev->htable = kmem_zalloc(dev->hsize, KM_NOSLEEP);
100
101 if (dev->htable == NULL)
102 return (DDI_FAILURE);
103
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);
108
109 if (ret != DDI_SUCCESS) {
110 goto fail_intr;
111 }
112
113 dev->num_vectors = nallocd;
114 if (nallocd < min) {
115 goto fail_intr;
116 }
117
118 /*
119 * get the interrupt priority. Assumption is that all handlers have
120 * equal priority
121 */
122
123 ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
124
125 if (ret != DDI_SUCCESS) {
126 goto fail_intr;
127 }
128
129 (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
130
131 if ((intr_types & DDI_INTR_TYPE_MSIX) && (nallocd > 1)) {
132 dev->rx_rings = nallocd - 1;
133 } else {
134 dev->rx_rings = 1;
135 }
136
137 return (DDI_SUCCESS);
138
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;
147 }
148 return (DDI_FAILURE);
149 }
150
151 /*
152 * top level function to undo initialization in oce_setup_intr
153 *
154 * dev - software handle to the device
155 *
156 * return DDI_SUCCESS => success, failure otherwise
157 */
158 int
159 oce_teardown_intr(struct oce_dev *dev)
160 {
161 int i;
162
163 /* release handlers */
164 for (i = 0; i < dev->num_vectors; i++) {
165 (void) ddi_intr_free(dev->htable[i]);
166 }
167
168 /* release htable */
169 kmem_free(dev->htable, dev->hsize);
170 dev->htable = NULL;
171
172 return (DDI_SUCCESS);
173 }
174
175 /*
176 * helper function to add ISR based on interrupt type
177 *
178 * dev - software handle to the device
179 *
180 * return DDI_SUCCESS => success, failure otherwise
181 */
182 int
183 oce_setup_handlers(struct oce_dev *dev)
184 {
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]);
195 }
196 return (DDI_FAILURE);
197 }
198 }
199 return (DDI_SUCCESS);
200 }
201
202 /*
203 * helper function to remove ISRs added in oce_setup_handlers
204 *
205 * dev - software handle to the device
206 *
207 * return DDI_SUCCESS => success, failure otherwise
208 */
209 void
210 oce_remove_handler(struct oce_dev *dev)
211 {
212 int nvec;
215 }
216 }
217
218 void
219 oce_chip_ei(struct oce_dev *dev)
220 {
221 uint32_t reg;
222
223 reg = OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
224 reg |= HOSTINTR_MASK;
225 OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
226 }
227
228 /*
229 * function to enable interrupts
230 *
231 * dev - software handle to the device
232 *
233 * return DDI_SUCCESS => success, failure otherwise
234 */
235 void
236 oce_ei(struct oce_dev *dev)
237 {
238 int i;
239 int ret;
240
241 if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
242 (void) ddi_intr_block_enable(dev->htable, dev->num_vectors);
243 } else {
244
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]);
250 }
251 }
252 }
253 }
254 oce_chip_ei(dev);
255 } /* oce_ei */
256
257 void
258 oce_chip_di(struct oce_dev *dev)
259 {
260 uint32_t reg;
261
262 reg = OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
263 reg &= ~HOSTINTR_MASK;
264 OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
265 }
266
267 /*
268 * function to disable interrupts
269 *
270 * dev - software handle to the device
271 *
272 * return DDI_SUCCESS => success, failure otherwise
273 */
274 void
275 oce_di(struct oce_dev *dev)
276 {
277 int i;
278 int ret;
279
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);
289 }
290 }
291 }
292
293 } /* oce_di */
294
295 /*
296 * command interrupt handler routine added to all vectors
297 *
298 * arg1 = callback data
299 * arg2 - callback data
300 *
301 * return DDI_INTR_CLAIMED => interrupt was claimed by the ISR
302 */
303 static uint_t
304 oce_isr(caddr_t arg1, caddr_t arg2)
305 {
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;
312
313 _NOTE(ARGUNUSED(arg2));
314
315 eq = (struct oce_eq *)(void *)(arg1);
316
317 dev = eq->parent;
318
319 eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
320
321 while (eqe->u0.dw0) {
322
323 eqe->u0.dw0 = LE_32(eqe->u0.dw0);
324
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);
330 }
331
332 /* get the cq from the eqe */
333 cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ;
334 cq = dev->cq[cq_id];
335
336 /* Call the completion handler */
337 (void) cq->cq_handler(cq->cb_arg);
338
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 */
345
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);
352 }
353 } /* oce_msix_handler */
|
2 * CDDL HEADER START
3 *
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) 2009-2012 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28
29 /*
30 * Source file interrupt registration
31 * and related helper functions
32 */
33
34 #include <oce_impl.h>
35
36 static uint_t oce_isr(caddr_t arg1, caddr_t arg2);
37 static int
38 oce_adjust_intrs(struct oce_dev *dev, ddi_cb_action_t action, int count);
39
40 /*
41 * top level function to setup interrupts
42 *
43 * dev - software handle to the device
44 *
45 * return DDI_SUCCESS => success, failure otherwise
46 */
47 int
48 oce_setup_intr(struct oce_dev *dev)
49 {
50 int ret, i;
51 int intr_types = 0;
52 int navail = 0;
53 int nsupported = 0;
54 int min = 0;
55 int nreqd = 0;
56 int nallocd = 0;
57 extern int oce_irm_enable;
58
59 /* get supported intr types */
60 ret = ddi_intr_get_supported_types(dev->dip, &intr_types);
61 if (ret != DDI_SUCCESS) {
62 oce_log(dev, CE_WARN, MOD_CONFIG,
63 "Failed to retrieve intr types 0x%x", ret);
64 return (DDI_FAILURE);
65 }
66
67 dev->rx_rings = min(dev->rx_rings, ncpus + dev->rss_cnt);
68 dev->tx_rings = min(dev->tx_rings, ncpus);
69 #ifdef __sparc
70 nreqd = min(dev->tx_rings + dev->rx_rings - dev->rss_cnt, ncpus);
71 dev->rx_group[0].eq_idx = dev->tx_rings;
72 #else
73 nreqd = max(dev->tx_rings, dev->rx_rings - dev->rss_cnt);
74 #endif
75 min = OCE_MIN_VECTORS;
76
77 retry_intr:
78
79 if (intr_types & DDI_INTR_TYPE_MSIX) {
80 dev->intr_type = DDI_INTR_TYPE_MSIX;
81 } else {
82 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
83 "MSIX not available");
84
85 if (intr_types & DDI_INTR_TYPE_FIXED) {
86 dev->intr_type = DDI_INTR_TYPE_FIXED;
87 dev->rx_rings = dev->tx_rings = min;
88 } else {
89 return (DDI_FAILURE);
90 }
91 nreqd = OCE_MIN_VECTORS;
92 }
93
94 ret = ddi_intr_get_nintrs(dev->dip, dev->intr_type, &nsupported);
95 if (ret != DDI_SUCCESS) {
96 oce_log(dev, CE_WARN, MOD_CONFIG,
97 "Could not get supported intrs:0x%x", ret);
98 return (DDI_FAILURE);
99 }
100
101 /* get the number of vectors available */
102 ret = ddi_intr_get_navail(dev->dip, dev->intr_type, &navail);
103 if (ret != DDI_SUCCESS || navail < min) {
104 oce_log(dev, CE_NOTE, MOD_CONFIG,
105 "Vectors: supported:0x%x, available:0x%x, ret:0x%x",
106 nsupported, navail, ret);
107 intr_types &= ~dev->intr_type;
108 goto retry_intr;
109 }
110
111 if (navail < nreqd) {
112 nreqd = navail;
113 }
114
115 /* allocate htable */
116 dev->hsize = nreqd * sizeof (ddi_intr_handle_t);
117 dev->htable = kmem_zalloc(dev->hsize, KM_NOSLEEP);
118
119 if (dev->htable == NULL)
120 return (DDI_FAILURE);
121
122 /* allocate interrupt */
123 ret = ddi_intr_alloc(dev->dip, dev->htable, dev->intr_type,
124 0, nreqd, &nallocd, DDI_INTR_ALLOC_NORMAL);
125
126 if (ret != DDI_SUCCESS || nallocd < min) {
127 oce_log(dev, CE_WARN, MOD_CONFIG,
128 "Alloc intr failed: %d %d",
129 navail, ret);
130 kmem_free(dev->htable, nreqd * sizeof (ddi_intr_handle_t));
131 intr_types &= ~dev->intr_type;
132 goto retry_intr;
133 }
134
135 /*
136 * get the interrupt priority. Assumption is that all handlers have
137 * equal priority
138 */
139
140 ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
141
142 if (ret != DDI_SUCCESS) {
143 oce_log(dev, CE_WARN, MOD_CONFIG,
144 "Unable to get intr priority: 0x%x", ret);
145
146 for (i = 0; i < dev->num_vectors; i++) {
147 (void) ddi_intr_free(dev->htable[i]);
148 }
149 kmem_free(dev->htable, nreqd * sizeof (ddi_intr_handle_t));
150 return (DDI_FAILURE);
151 }
152
153 (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
154
155 /* update the actual number of interrupts allocated */
156 dev->num_vectors = nallocd;
157 if (oce_irm_enable && dev->intr_type == DDI_INTR_TYPE_MSIX) {
158 dev->max_vectors = nreqd;
159 } else {
160 dev->max_vectors = nallocd;
161 dev->tx_rings = min(dev->tx_rings, nallocd);
162 dev->rx_rings = min(dev->rx_rings, nallocd + dev->rss_cnt);
163 }
164
165 oce_group_rings(dev);
166 return (DDI_SUCCESS);
167 }
168
169
170 /*
171 * top level function to undo initialization in oce_setup_intr
172 *
173 * dev - software handle to the device
174 *
175 * return DDI_SUCCESS => success, failure otherwise
176 */
177 int
178 oce_teardown_intr(struct oce_dev *dev)
179 {
180 int i;
181
182 /* release handlers */
183 for (i = 0; i < dev->num_vectors; i++) {
184 (void) ddi_intr_free(dev->htable[i]);
185 }
186
187 /* release htable */
188 kmem_free(dev->htable, dev->hsize);
189 dev->htable = NULL;
190 if (dev->attach_state & ATTACH_CB_REG) {
191 (void) ddi_cb_unregister(dev->cb_handle);
192 }
193 return (DDI_SUCCESS);
194 }
195
196 /*
197 * helper function to add ISR based on interrupt type
198 *
199 * dev - software handle to the device
200 *
201 * return DDI_SUCCESS => success, failure otherwise
202 */
203 int
204 oce_setup_handlers(struct oce_dev *dev)
205 {
206 int i = 0;
207 int ret;
208 for (i = 0; i < dev->num_vectors; i++) {
209 ret = ddi_intr_add_handler(dev->htable[i], oce_isr,
210 (caddr_t)&dev->eq[i], NULL);
211 if (ret != DDI_SUCCESS) {
212 oce_log(dev, CE_WARN, MOD_CONFIG,
213 "Failed to add interrupt handler %d, ret = 0x%x",
214 i, ret);
215 for (i--; i >= 0; i--) {
216 (void) ddi_intr_remove_handler(dev->htable[i]);
217 }
218 return (DDI_FAILURE);
219 }
220 }
221 return (DDI_SUCCESS);
222 }
223
224 /*
225 * helper function to remove ISRs added in oce_setup_handlers
226 *
227 * dev - software handle to the device
228 *
229 * return DDI_SUCCESS => success, failure otherwise
230 */
231 void
232 oce_remove_handler(struct oce_dev *dev)
233 {
234 int nvec;
237 }
238 }
239
240 void
241 oce_chip_ei(struct oce_dev *dev)
242 {
243 uint32_t reg;
244
245 reg = OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
246 reg |= HOSTINTR_MASK;
247 OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
248 }
249
250 /*
251 * function to enable interrupts
252 *
253 * dev - software handle to the device
254 *
255 * return DDI_SUCCESS => success, failure otherwise
256 */
257 int
258 oce_ei(struct oce_dev *dev)
259 {
260 int i;
261 int ret;
262
263 if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
264 ret = ddi_intr_block_enable(dev->htable, dev->num_vectors);
265 if (ret != DDI_SUCCESS) {
266 oce_log(dev, CE_WARN, MOD_CONFIG,
267 "Interrupts block enable failed :%d\n", ret);
268 return (DDI_FAILURE);
269 }
270 } else {
271 for (i = 0; i < dev->num_vectors; i++) {
272 ret = ddi_intr_enable(dev->htable[i]);
273 if (ret != DDI_SUCCESS) {
274 oce_log(dev, CE_WARN, MOD_CONFIG,
275 "Failed to enable, ret %d, interrupt %d,"
276 " type %d, cnt %d ",
277 ret, i, dev->intr_type, dev->num_vectors);
278 for (i--; i >= 0; i--) {
279 (void) ddi_intr_disable(dev->htable[i]);
280 }
281 return (DDI_FAILURE);
282 }
283 }
284 }
285
286 return (DDI_SUCCESS);
287 } /* oce_ei */
288
289 void
290 oce_chip_di(struct oce_dev *dev)
291 {
292 uint32_t reg;
293
294 reg = OCE_CFG_READ32(dev, PCICFG_INTR_CTRL);
295 reg &= ~HOSTINTR_MASK;
296 OCE_CFG_WRITE32(dev, PCICFG_INTR_CTRL, reg);
297 }
298
299 /*
300 * function to disable interrupts
301 *
302 * dev - software handle to the device
303 *
304 * return DDI_SUCCESS => success, failure otherwise
305 */
306 int
307 oce_di(struct oce_dev *dev)
308 {
309 int i;
310 int ret;
311
312 dev->state &= ~STATE_INTR_ENABLED;
313 if (!LANCER_CHIP(dev))
314 oce_chip_di(dev);
315
316 if (dev->intr_cap & DDI_INTR_FLAG_BLOCK) {
317 ret = ddi_intr_block_disable(dev->htable, dev->num_vectors);
318 if (ret != DDI_SUCCESS) {
319 oce_log(dev, CE_WARN, MOD_CONFIG,
320 "Interrupt block disable failed :%d\n", ret);
321 return (DDI_FAILURE);
322 }
323 } else {
324 for (i = 0; i < dev->num_vectors; i++) {
325 ret = ddi_intr_disable(dev->htable[i]);
326 if (ret != DDI_SUCCESS) {
327 oce_log(dev, CE_WARN, MOD_CONFIG,
328 "Failed to disable the interrupts 0x%x",
329 ret);
330 return (DDI_FAILURE);
331 }
332 }
333 }
334 return (DDI_SUCCESS);
335 } /* oce_di */
336
337
338 int
339 oce_ring_intr_enable(mac_intr_handle_t ring_handle)
340 {
341 struct oce_rq *rx_ring = (struct oce_rq *)ring_handle;
342 struct oce_dev *dev;
343 dev = rx_ring->parent;
344 oce_group_t *grp = rx_ring->grp;
345 mutex_enter(&grp->grp_lock);
346 if (grp->state & GROUP_SUSPEND) {
347 mutex_exit(&grp->grp_lock);
348 return (DDI_SUCCESS);
349 }
350 mutex_enter(&rx_ring->rx_lock);
351 oce_arm_cq(dev, rx_ring->cq->cq_id, 0, B_TRUE);
352 rx_ring->qmode = OCE_MODE_INTR;
353 mutex_exit(&rx_ring->rx_lock);
354 mutex_exit(&grp->grp_lock);
355 return (DDI_SUCCESS);
356 }
357
358
359 int
360 oce_ring_intr_disable(mac_intr_handle_t ring_handle)
361 {
362 struct oce_rq *rx_ring = (struct oce_rq *)ring_handle;
363 struct oce_dev *dev;
364
365 dev = rx_ring->parent;
366 mutex_enter(&rx_ring->rx_lock);
367 oce_arm_cq(dev, rx_ring->cq->cq_id, 0, B_FALSE);
368 rx_ring->qmode = OCE_MODE_POLL;
369 mutex_exit(&rx_ring->rx_lock);
370 return (DDI_SUCCESS);
371 }
372
373 uint_t
374 oce_ring_common_drain(struct oce_eq *eq)
375 {
376 struct oce_eqe *eqe;
377 uint16_t num_eqe = 0;
378 uint16_t cq_id;
379 struct oce_cq *cq;
380 struct oce_dev *dev;
381
382 dev = eq->parent;
383
384 eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
385
386 if (eqe->u0.dw0) {
387 eqe->u0.dw0 = LE_32(eqe->u0.dw0);
388
389 /* get the cq from the eqe */
390 cq_id = eqe->u0.s.resource_id % OCE_MAX_CQ;
391 cq = dev->cq[cq_id];
392
393 /* clear valid bit and progress eqe */
394 eqe->u0.dw0 = 0;
395 RING_GET(eq->ring, 1);
396 num_eqe++;
397
398 if (cq) {
399 /* Call the completion handler */
400 (void) cq->cq_handler(cq->cb_arg, 0, 0);
401 }
402 }
403
404 /* ring the eq doorbell, signify that it's done processing */
405 oce_arm_eq(dev, eq->eq_id, num_eqe, B_TRUE, B_TRUE);
406
407 return (num_eqe);
408
409 } /* oce_ring_common_drain */
410
411
412 /* MSI/INTX handler: common vector for TX/RX/MQ */
413 uint_t
414 oce_isr(caddr_t arg1, caddr_t arg2)
415 {
416 struct oce_eq *eq;
417 struct oce_dev *dev;
418 uint16_t num_eqe = 0;
419
420 _NOTE(ARGUNUSED(arg2));
421
422 eq = (struct oce_eq *)(void *)(arg1);
423 dev = eq->parent;
424
425 if ((dev == NULL) ||
426 !(dev->state & STATE_INTR_ENABLED)) {
427 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
428 "Dummy interrupt received");
429 return (DDI_INTR_CLAIMED);
430 }
431
432 mutex_enter(&eq->lock);
433 if (eq->qstate != QSTARTED) {
434 mutex_exit(&eq->lock);
435 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
436 "oce_isr EQ Not started");
437 return (DDI_INTR_CLAIMED);
438 }
439 num_eqe = oce_ring_common_drain(eq);
440 mutex_exit(&eq->lock);
441 if (num_eqe) {
442 return (DDI_INTR_CLAIMED);
443 } else {
444 return (DDI_INTR_UNCLAIMED);
445 }
446 }
447
448 /*
449 * IRM callback routine
450 */
451 int
452 oce_cbfunc(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
453 void *arg1, void *arg2)
454 {
455 struct oce_dev *dev = (struct oce_dev *)arg1;
456 int count = (int)(uintptr_t)cbarg, ret = DDI_ENOTSUP;
457
458 _NOTE(ARGUNUSED(dip));
459 _NOTE(ARGUNUSED(arg2));
460
461 switch (cbaction) {
462 case DDI_CB_INTR_ADD:
463 case DDI_CB_INTR_REMOVE:
464
465 oce_log(dev, CE_NOTE, MOD_CONFIG,
466 "IRM cbaction %d count %d vectors %d max_vectors %d",
467 cbaction, count, dev->num_vectors, dev->max_vectors);
468 ret = oce_adjust_intrs(dev, cbaction, count);
469 if (ret != DDI_SUCCESS) {
470 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
471 "IRM: Failed to adjust interrupts");
472 return (ret);
473 }
474 break;
475
476 default:
477 return (ret);
478 }
479 return (ret);
480 }
481
482
483 static int
484 oce_adjust_intrs(struct oce_dev *dev, ddi_cb_action_t action, int count)
485 {
486 int i, nallocd, ret;
487
488 if (count == 0)
489 return (DDI_SUCCESS);
490
491 if ((action == DDI_CB_INTR_ADD &&
492 dev->num_vectors + count > dev->max_vectors) ||
493 (action == DDI_CB_INTR_REMOVE &&
494 dev->num_vectors - count < OCE_MIN_VECTORS)) {
495 return (DDI_FAILURE);
496 }
497
498 if (!(dev->state & STATE_MAC_STARTED)) {
499 return (DDI_FAILURE);
500 }
501
502 mutex_enter(&dev->dev_lock);
503 dev->state |= STATE_INTR_ADJUST;
504 dev->suspended = B_TRUE;
505
506 /* stop the groups */
507 for (i = 0; i < dev->num_rx_groups; i++) {
508 mutex_enter(&dev->rx_group[i].grp_lock);
509 oce_suspend_group_rings(&dev->rx_group[i]);
510 oce_stop_group(&dev->rx_group[i], B_FALSE);
511 mutex_exit(&dev->rx_group[i].grp_lock);
512 }
513
514 oce_stop(dev);
515 oce_remove_handler(dev);
516 if (action == DDI_CB_INTR_ADD) {
517 /* allocate additional vectors */
518 ret = ddi_intr_alloc(dev->dip, dev->htable, DDI_INTR_TYPE_MSIX,
519 dev->num_vectors, count, &nallocd, DDI_INTR_ALLOC_NORMAL);
520
521 if (ret != DDI_SUCCESS) {
522 goto irm_fail;
523 }
524
525 /* update actual count of available interrupts */
526 dev->num_vectors += nallocd;
527 oce_log(dev, CE_NOTE, MOD_CONFIG,
528 "IRM: INTR_ADD - count=0x%x allocated=0x%x vectors=0x%x",
529 count, nallocd, dev->num_vectors);
530 } else {
531 /* free interrupt vectors */
532 for (i = dev->num_vectors - count;
533 i < dev->num_vectors; i++) {
534 ret = ddi_intr_free(dev->htable[i]);
535 if (ret != DDI_SUCCESS) {
536 oce_log(dev, CE_WARN, MOD_CONFIG,
537 "IRM: can't free vectors ret 0x%x", ret);
538 goto irm_fail;
539 }
540 dev->htable[i] = NULL;
541 }
542
543 /* update actual count of available interrupts */
544 dev->num_vectors -= count;
545 oce_log(dev, CE_NOTE, MOD_CONFIG,
546 "IRM: INTR_REMOVE - count = 0x%x vectors = 0x%x",
547 count, dev->num_vectors);
548 }
549
550 if (oce_setup_handlers(dev) != DDI_SUCCESS) {
551 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
552 "Failed to Setup handlers during IRM");
553 goto irm_fail;
554 }
555
556 /* re-start the device instance */
557 if (oce_start(dev) != DDI_SUCCESS) {
558 goto irm_fail;
559 }
560
561 ret = ddi_intr_get_pri(dev->htable[0], &dev->intr_pri);
562
563 if (ret != DDI_SUCCESS) {
564 goto irm_fail;
565 }
566
567 (void) ddi_intr_get_cap(dev->htable[0], &dev->intr_cap);
568
569 /* re-start the groups */
570 for (i = 0; i < dev->num_rx_groups; i++) {
571 mutex_enter(&dev->rx_group[i].grp_lock);
572 ret = oce_start_group(&dev->rx_group[i], B_FALSE);
573 if (ret == DDI_SUCCESS) {
574 ret = oce_resume_group_rings(&dev->rx_group[i]);
575 }
576 mutex_exit(&dev->rx_group[i].grp_lock);
577 if (ret != DDI_SUCCESS) {
578 goto irm_fail;
579 }
580 }
581 dev->state &= ~STATE_INTR_ADJUST;
582 dev->suspended = B_FALSE;
583 mutex_exit(&dev->dev_lock);
584
585 /* Wakeup all Tx rings */
586 for (i = 0; i < dev->tx_rings; i++) {
587 mac_tx_ring_update(dev->mac_handle,
588 dev->default_tx_rings[i].tx->handle);
589 }
590
591 return (DDI_SUCCESS);
592
593 irm_fail:
594 ddi_fm_service_impact(dev->dip, DDI_SERVICE_LOST);
595 mutex_exit(&dev->dev_lock);
596 return (DDI_FAILURE);
597 }
|