1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore * Copyright (c) 2008-2016 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore * All rights reserved.
4*49ef7e06SGarrett D'Amore *
5*49ef7e06SGarrett D'Amore * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore *
8*49ef7e06SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore * this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore * this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore * and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore *
14*49ef7e06SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore *
26*49ef7e06SGarrett D'Amore * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore */
30*49ef7e06SGarrett D'Amore
31*49ef7e06SGarrett D'Amore #include <sys/types.h>
32*49ef7e06SGarrett D'Amore #include <sys/ddi.h>
33*49ef7e06SGarrett D'Amore #include <sys/sunddi.h>
34*49ef7e06SGarrett D'Amore #include <sys/atomic.h>
35*49ef7e06SGarrett D'Amore #include <sys/modctl.h>
36*49ef7e06SGarrett D'Amore #include <sys/conf.h>
37*49ef7e06SGarrett D'Amore #include <sys/ethernet.h>
38*49ef7e06SGarrett D'Amore #include <sys/pci.h>
39*49ef7e06SGarrett D'Amore #include <sys/pcie.h>
40*49ef7e06SGarrett D'Amore
41*49ef7e06SGarrett D'Amore #include "sfxge.h"
42*49ef7e06SGarrett D'Amore
43*49ef7e06SGarrett D'Amore #include "efx.h"
44*49ef7e06SGarrett D'Amore
45*49ef7e06SGarrett D'Amore
46*49ef7e06SGarrett D'Amore /* Interrupt table DMA attributes */
47*49ef7e06SGarrett D'Amore static ddi_device_acc_attr_t sfxge_intr_devacc = {
48*49ef7e06SGarrett D'Amore
49*49ef7e06SGarrett D'Amore DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
50*49ef7e06SGarrett D'Amore DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
51*49ef7e06SGarrett D'Amore DDI_STRICTORDER_ACC /* devacc_attr_dataorder */
52*49ef7e06SGarrett D'Amore };
53*49ef7e06SGarrett D'Amore
54*49ef7e06SGarrett D'Amore static ddi_dma_attr_t sfxge_intr_dma_attr = {
55*49ef7e06SGarrett D'Amore DMA_ATTR_V0, /* dma_attr_version */
56*49ef7e06SGarrett D'Amore 0, /* dma_attr_addr_lo */
57*49ef7e06SGarrett D'Amore 0xffffffffffffffffull, /* dma_attr_addr_hi */
58*49ef7e06SGarrett D'Amore 0xffffffffffffffffull, /* dma_attr_count_max */
59*49ef7e06SGarrett D'Amore EFX_INTR_SIZE, /* dma_attr_align */
60*49ef7e06SGarrett D'Amore 0xffffffff, /* dma_attr_burstsizes */
61*49ef7e06SGarrett D'Amore 1, /* dma_attr_minxfer */
62*49ef7e06SGarrett D'Amore 0xffffffffffffffffull, /* dma_attr_maxxfer */
63*49ef7e06SGarrett D'Amore 0xffffffffffffffffull, /* dma_attr_seg */
64*49ef7e06SGarrett D'Amore 1, /* dma_attr_sgllen */
65*49ef7e06SGarrett D'Amore 1, /* dma_attr_granular */
66*49ef7e06SGarrett D'Amore 0 /* dma_attr_flags */
67*49ef7e06SGarrett D'Amore };
68*49ef7e06SGarrett D'Amore
69*49ef7e06SGarrett D'Amore static unsigned int
sfxge_intr_line(caddr_t arg1,caddr_t arg2)70*49ef7e06SGarrett D'Amore sfxge_intr_line(caddr_t arg1, caddr_t arg2)
71*49ef7e06SGarrett D'Amore {
72*49ef7e06SGarrett D'Amore sfxge_t *sp = (void *)arg1;
73*49ef7e06SGarrett D'Amore efx_nic_t *enp = sp->s_enp;
74*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
75*49ef7e06SGarrett D'Amore unsigned int index;
76*49ef7e06SGarrett D'Amore boolean_t fatal;
77*49ef7e06SGarrett D'Amore uint32_t qmask;
78*49ef7e06SGarrett D'Amore int rc;
79*49ef7e06SGarrett D'Amore
80*49ef7e06SGarrett D'Amore _NOTE(ARGUNUSED(arg2))
81*49ef7e06SGarrett D'Amore
82*49ef7e06SGarrett D'Amore ASSERT3U(sip->si_type, ==, EFX_INTR_LINE);
83*49ef7e06SGarrett D'Amore
84*49ef7e06SGarrett D'Amore if (sip->si_state != SFXGE_INTR_STARTED &&
85*49ef7e06SGarrett D'Amore sip->si_state != SFXGE_INTR_TESTING) {
86*49ef7e06SGarrett D'Amore rc = DDI_INTR_UNCLAIMED;
87*49ef7e06SGarrett D'Amore goto done;
88*49ef7e06SGarrett D'Amore }
89*49ef7e06SGarrett D'Amore
90*49ef7e06SGarrett D'Amore if (sip->si_state == SFXGE_INTR_TESTING) {
91*49ef7e06SGarrett D'Amore sip->si_mask |= 1; /* only one interrupt */
92*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
93*49ef7e06SGarrett D'Amore goto done;
94*49ef7e06SGarrett D'Amore }
95*49ef7e06SGarrett D'Amore
96*49ef7e06SGarrett D'Amore efx_intr_status_line(enp, &fatal, &qmask);
97*49ef7e06SGarrett D'Amore
98*49ef7e06SGarrett D'Amore if (fatal) {
99*49ef7e06SGarrett D'Amore sfxge_intr_fatal(sp);
100*49ef7e06SGarrett D'Amore
101*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
102*49ef7e06SGarrett D'Amore goto done;
103*49ef7e06SGarrett D'Amore }
104*49ef7e06SGarrett D'Amore
105*49ef7e06SGarrett D'Amore if (qmask != 0) {
106*49ef7e06SGarrett D'Amore for (index = 0; index < EFX_INTR_NEVQS; index++) {
107*49ef7e06SGarrett D'Amore if (qmask & (1 << index))
108*49ef7e06SGarrett D'Amore (void) sfxge_ev_qpoll(sp, index);
109*49ef7e06SGarrett D'Amore }
110*49ef7e06SGarrett D'Amore
111*49ef7e06SGarrett D'Amore sip->si_zero_count = 0;
112*49ef7e06SGarrett D'Amore sfxge_gld_rx_push(sp);
113*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
114*49ef7e06SGarrett D'Amore goto done;
115*49ef7e06SGarrett D'Amore }
116*49ef7e06SGarrett D'Amore
117*49ef7e06SGarrett D'Amore /*
118*49ef7e06SGarrett D'Amore * bug15671/bug17203 workaround. Return CLAIMED for the first ISR=0
119*49ef7e06SGarrett D'Amore * interrupt, and poll all evqs for work. For subsequent ISR=0
120*49ef7e06SGarrett D'Amore * interrupts (the line must be shared in this case), just rearm the
121*49ef7e06SGarrett D'Amore * event queues to ensure we don't miss an interrupt.
122*49ef7e06SGarrett D'Amore */
123*49ef7e06SGarrett D'Amore if (sip->si_zero_count++ == 0) {
124*49ef7e06SGarrett D'Amore for (index = 0; index < EFX_INTR_NEVQS; index++) {
125*49ef7e06SGarrett D'Amore if (sp->s_sep[index] != NULL)
126*49ef7e06SGarrett D'Amore (void) sfxge_ev_qpoll(sp, index);
127*49ef7e06SGarrett D'Amore }
128*49ef7e06SGarrett D'Amore
129*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
130*49ef7e06SGarrett D'Amore } else {
131*49ef7e06SGarrett D'Amore for (index = 0; index < EFX_INTR_NEVQS; index++) {
132*49ef7e06SGarrett D'Amore if (sp->s_sep[index] != NULL)
133*49ef7e06SGarrett D'Amore (void) sfxge_ev_qprime(sp, index);
134*49ef7e06SGarrett D'Amore }
135*49ef7e06SGarrett D'Amore
136*49ef7e06SGarrett D'Amore rc = DDI_INTR_UNCLAIMED;
137*49ef7e06SGarrett D'Amore }
138*49ef7e06SGarrett D'Amore
139*49ef7e06SGarrett D'Amore done:
140*49ef7e06SGarrett D'Amore return (rc);
141*49ef7e06SGarrett D'Amore }
142*49ef7e06SGarrett D'Amore
143*49ef7e06SGarrett D'Amore static unsigned int
sfxge_intr_message(caddr_t arg1,caddr_t arg2)144*49ef7e06SGarrett D'Amore sfxge_intr_message(caddr_t arg1, caddr_t arg2)
145*49ef7e06SGarrett D'Amore {
146*49ef7e06SGarrett D'Amore sfxge_t *sp = (void *)arg1;
147*49ef7e06SGarrett D'Amore efx_nic_t *enp = sp->s_enp;
148*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
149*49ef7e06SGarrett D'Amore unsigned int index = (unsigned int)(uintptr_t)arg2;
150*49ef7e06SGarrett D'Amore boolean_t fatal;
151*49ef7e06SGarrett D'Amore int rc;
152*49ef7e06SGarrett D'Amore
153*49ef7e06SGarrett D'Amore ASSERT3U(sip->si_type, ==, EFX_INTR_MESSAGE);
154*49ef7e06SGarrett D'Amore
155*49ef7e06SGarrett D'Amore if (sip->si_state != SFXGE_INTR_STARTED &&
156*49ef7e06SGarrett D'Amore sip->si_state != SFXGE_INTR_TESTING) {
157*49ef7e06SGarrett D'Amore rc = DDI_INTR_UNCLAIMED;
158*49ef7e06SGarrett D'Amore goto done;
159*49ef7e06SGarrett D'Amore }
160*49ef7e06SGarrett D'Amore
161*49ef7e06SGarrett D'Amore if (sip->si_state == SFXGE_INTR_TESTING) {
162*49ef7e06SGarrett D'Amore uint64_t mask;
163*49ef7e06SGarrett D'Amore
164*49ef7e06SGarrett D'Amore do {
165*49ef7e06SGarrett D'Amore mask = sip->si_mask;
166*49ef7e06SGarrett D'Amore } while (atomic_cas_64(&(sip->si_mask), mask,
167*49ef7e06SGarrett D'Amore mask | (1 << index)) != mask);
168*49ef7e06SGarrett D'Amore
169*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
170*49ef7e06SGarrett D'Amore goto done;
171*49ef7e06SGarrett D'Amore }
172*49ef7e06SGarrett D'Amore
173*49ef7e06SGarrett D'Amore efx_intr_status_message(enp, index, &fatal);
174*49ef7e06SGarrett D'Amore
175*49ef7e06SGarrett D'Amore if (fatal) {
176*49ef7e06SGarrett D'Amore sfxge_intr_fatal(sp);
177*49ef7e06SGarrett D'Amore
178*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
179*49ef7e06SGarrett D'Amore goto done;
180*49ef7e06SGarrett D'Amore }
181*49ef7e06SGarrett D'Amore
182*49ef7e06SGarrett D'Amore (void) sfxge_ev_qpoll(sp, index);
183*49ef7e06SGarrett D'Amore
184*49ef7e06SGarrett D'Amore sfxge_gld_rx_push(sp);
185*49ef7e06SGarrett D'Amore rc = DDI_INTR_CLAIMED;
186*49ef7e06SGarrett D'Amore
187*49ef7e06SGarrett D'Amore done:
188*49ef7e06SGarrett D'Amore return (rc);
189*49ef7e06SGarrett D'Amore }
190*49ef7e06SGarrett D'Amore
191*49ef7e06SGarrett D'Amore static int
sfxge_intr_bus_enable(sfxge_t * sp)192*49ef7e06SGarrett D'Amore sfxge_intr_bus_enable(sfxge_t *sp)
193*49ef7e06SGarrett D'Amore {
194*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
195*49ef7e06SGarrett D'Amore ddi_intr_handler_t *handler;
196*49ef7e06SGarrett D'Amore int add_index;
197*49ef7e06SGarrett D'Amore int en_index;
198*49ef7e06SGarrett D'Amore int err;
199*49ef7e06SGarrett D'Amore int rc;
200*49ef7e06SGarrett D'Amore
201*49ef7e06SGarrett D'Amore /* Serialise all instances to avoid problems seen in bug31184. */
202*49ef7e06SGarrett D'Amore mutex_enter(&sfxge_global_lock);
203*49ef7e06SGarrett D'Amore
204*49ef7e06SGarrett D'Amore switch (sip->si_type) {
205*49ef7e06SGarrett D'Amore case EFX_INTR_MESSAGE:
206*49ef7e06SGarrett D'Amore handler = sfxge_intr_message;
207*49ef7e06SGarrett D'Amore break;
208*49ef7e06SGarrett D'Amore
209*49ef7e06SGarrett D'Amore case EFX_INTR_LINE:
210*49ef7e06SGarrett D'Amore handler = sfxge_intr_line;
211*49ef7e06SGarrett D'Amore break;
212*49ef7e06SGarrett D'Amore
213*49ef7e06SGarrett D'Amore default:
214*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
215*49ef7e06SGarrett D'Amore "bus_enable: unknown intr type (si_type=%d nalloc=%d)",
216*49ef7e06SGarrett D'Amore sip->si_type, sip->si_nalloc);
217*49ef7e06SGarrett D'Amore ASSERT(B_FALSE);
218*49ef7e06SGarrett D'Amore rc = EINVAL;
219*49ef7e06SGarrett D'Amore goto fail1;
220*49ef7e06SGarrett D'Amore }
221*49ef7e06SGarrett D'Amore
222*49ef7e06SGarrett D'Amore /* Try to add the handlers */
223*49ef7e06SGarrett D'Amore for (add_index = 0; add_index < sip->si_nalloc; add_index++) {
224*49ef7e06SGarrett D'Amore unsigned int pri;
225*49ef7e06SGarrett D'Amore
226*49ef7e06SGarrett D'Amore /* This cannot fail unless given invalid inputs. */
227*49ef7e06SGarrett D'Amore err = ddi_intr_get_pri(sip->si_table[add_index], &pri);
228*49ef7e06SGarrett D'Amore ASSERT(err == DDI_SUCCESS);
229*49ef7e06SGarrett D'Amore
230*49ef7e06SGarrett D'Amore DTRACE_PROBE2(pri, unsigned int, add_index, unsigned int, pri);
231*49ef7e06SGarrett D'Amore
232*49ef7e06SGarrett D'Amore err = ddi_intr_add_handler(sip->si_table[add_index], handler,
233*49ef7e06SGarrett D'Amore (caddr_t)sp, (caddr_t)(uintptr_t)add_index);
234*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
235*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
236*49ef7e06SGarrett D'Amore "bus_enable: ddi_intr_add_handler failed"
237*49ef7e06SGarrett D'Amore " err=%d (h=%p idx=%d nalloc=%d)",
238*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[add_index], add_index,
239*49ef7e06SGarrett D'Amore sip->si_nalloc);
240*49ef7e06SGarrett D'Amore
241*49ef7e06SGarrett D'Amore rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
242*49ef7e06SGarrett D'Amore goto fail2;
243*49ef7e06SGarrett D'Amore }
244*49ef7e06SGarrett D'Amore }
245*49ef7e06SGarrett D'Amore
246*49ef7e06SGarrett D'Amore /* Get interrupt capabilities */
247*49ef7e06SGarrett D'Amore err = ddi_intr_get_cap(sip->si_table[0], &(sip->si_cap));
248*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
249*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
250*49ef7e06SGarrett D'Amore "bus_enable: ddi_intr_get_cap failed"
251*49ef7e06SGarrett D'Amore " err=%d (h=%p idx=%d nalloc=%d)",
252*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[0], 0, sip->si_nalloc);
253*49ef7e06SGarrett D'Amore
254*49ef7e06SGarrett D'Amore if (err == DDI_EINVAL)
255*49ef7e06SGarrett D'Amore rc = EINVAL;
256*49ef7e06SGarrett D'Amore else if (err == DDI_ENOTSUP)
257*49ef7e06SGarrett D'Amore rc = ENOTSUP;
258*49ef7e06SGarrett D'Amore else
259*49ef7e06SGarrett D'Amore rc = EFAULT;
260*49ef7e06SGarrett D'Amore
261*49ef7e06SGarrett D'Amore goto fail3;
262*49ef7e06SGarrett D'Amore }
263*49ef7e06SGarrett D'Amore
264*49ef7e06SGarrett D'Amore /* Enable interrupts at the bus */
265*49ef7e06SGarrett D'Amore if (sip->si_cap & DDI_INTR_FLAG_BLOCK) {
266*49ef7e06SGarrett D'Amore en_index = 0; /* Silence gcc */
267*49ef7e06SGarrett D'Amore err = ddi_intr_block_enable(sip->si_table, sip->si_nalloc);
268*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
269*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
270*49ef7e06SGarrett D'Amore "bus_enable: ddi_intr_block_enable failed"
271*49ef7e06SGarrett D'Amore " err=%d (table=%p nalloc=%d)",
272*49ef7e06SGarrett D'Amore err, (void *)sip->si_table, sip->si_nalloc);
273*49ef7e06SGarrett D'Amore
274*49ef7e06SGarrett D'Amore rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
275*49ef7e06SGarrett D'Amore goto fail4;
276*49ef7e06SGarrett D'Amore }
277*49ef7e06SGarrett D'Amore } else {
278*49ef7e06SGarrett D'Amore for (en_index = 0; en_index < sip->si_nalloc; en_index++) {
279*49ef7e06SGarrett D'Amore err = ddi_intr_enable(sip->si_table[en_index]);
280*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
281*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
282*49ef7e06SGarrett D'Amore "bus_enable: ddi_intr_enable failed"
283*49ef7e06SGarrett D'Amore " err=%d (h=%p idx=%d nalloc=%d)",
284*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[en_index],
285*49ef7e06SGarrett D'Amore en_index, sip->si_nalloc);
286*49ef7e06SGarrett D'Amore
287*49ef7e06SGarrett D'Amore rc = (err == DDI_EINVAL) ? EINVAL : EFAULT;
288*49ef7e06SGarrett D'Amore goto fail4;
289*49ef7e06SGarrett D'Amore }
290*49ef7e06SGarrett D'Amore }
291*49ef7e06SGarrett D'Amore }
292*49ef7e06SGarrett D'Amore
293*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
294*49ef7e06SGarrett D'Amore return (0);
295*49ef7e06SGarrett D'Amore
296*49ef7e06SGarrett D'Amore fail4:
297*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail4);
298*49ef7e06SGarrett D'Amore
299*49ef7e06SGarrett D'Amore /* Disable the enabled handlers */
300*49ef7e06SGarrett D'Amore if (!(sip->si_cap & DDI_INTR_FLAG_BLOCK)) {
301*49ef7e06SGarrett D'Amore while (--en_index >= 0) {
302*49ef7e06SGarrett D'Amore err = ddi_intr_disable(sip->si_table[en_index]);
303*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
304*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
305*49ef7e06SGarrett D'Amore "bus_enable: ddi_intr_disable"
306*49ef7e06SGarrett D'Amore " failed err=%d (h=%p idx=%d nalloc=%d)",
307*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[en_index],
308*49ef7e06SGarrett D'Amore en_index, sip->si_nalloc);
309*49ef7e06SGarrett D'Amore }
310*49ef7e06SGarrett D'Amore }
311*49ef7e06SGarrett D'Amore }
312*49ef7e06SGarrett D'Amore
313*49ef7e06SGarrett D'Amore fail3:
314*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail3);
315*49ef7e06SGarrett D'Amore
316*49ef7e06SGarrett D'Amore /* Remove all handlers */
317*49ef7e06SGarrett D'Amore add_index = sip->si_nalloc;
318*49ef7e06SGarrett D'Amore
319*49ef7e06SGarrett D'Amore fail2:
320*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail2);
321*49ef7e06SGarrett D'Amore
322*49ef7e06SGarrett D'Amore /* Remove remaining handlers */
323*49ef7e06SGarrett D'Amore while (--add_index >= 0) {
324*49ef7e06SGarrett D'Amore err = ddi_intr_remove_handler(sip->si_table[add_index]);
325*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
326*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
327*49ef7e06SGarrett D'Amore "bus_enable: ddi_intr_remove_handler"
328*49ef7e06SGarrett D'Amore " failed err=%d (h=%p idx=%d nalloc=%d)",
329*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[add_index], add_index,
330*49ef7e06SGarrett D'Amore sip->si_nalloc);
331*49ef7e06SGarrett D'Amore }
332*49ef7e06SGarrett D'Amore }
333*49ef7e06SGarrett D'Amore
334*49ef7e06SGarrett D'Amore fail1:
335*49ef7e06SGarrett D'Amore DTRACE_PROBE1(fail1, int, rc);
336*49ef7e06SGarrett D'Amore
337*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
338*49ef7e06SGarrett D'Amore return (rc);
339*49ef7e06SGarrett D'Amore }
340*49ef7e06SGarrett D'Amore
341*49ef7e06SGarrett D'Amore static void
sfxge_intr_bus_disable(sfxge_t * sp)342*49ef7e06SGarrett D'Amore sfxge_intr_bus_disable(sfxge_t *sp)
343*49ef7e06SGarrett D'Amore {
344*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
345*49ef7e06SGarrett D'Amore int index;
346*49ef7e06SGarrett D'Amore int err;
347*49ef7e06SGarrett D'Amore
348*49ef7e06SGarrett D'Amore /* Serialise all instances to avoid problems seen in bug31184. */
349*49ef7e06SGarrett D'Amore mutex_enter(&sfxge_global_lock);
350*49ef7e06SGarrett D'Amore
351*49ef7e06SGarrett D'Amore /* Disable interrupts at the bus */
352*49ef7e06SGarrett D'Amore if (sip->si_cap & DDI_INTR_FLAG_BLOCK) {
353*49ef7e06SGarrett D'Amore err = ddi_intr_block_disable(sip->si_table, sip->si_nalloc);
354*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
355*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
356*49ef7e06SGarrett D'Amore "bus_disable: ddi_intr_block_disable"
357*49ef7e06SGarrett D'Amore " failed err=%d (table=%p nalloc=%d)",
358*49ef7e06SGarrett D'Amore err, (void *)sip->si_table, sip->si_nalloc);
359*49ef7e06SGarrett D'Amore }
360*49ef7e06SGarrett D'Amore } else {
361*49ef7e06SGarrett D'Amore index = sip->si_nalloc;
362*49ef7e06SGarrett D'Amore while (--index >= 0) {
363*49ef7e06SGarrett D'Amore err = ddi_intr_disable(sip->si_table[index]);
364*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
365*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
366*49ef7e06SGarrett D'Amore "bus_disable: ddi_intr_disable"
367*49ef7e06SGarrett D'Amore " failed err=%d (h=%p idx=%d nalloc=%d)",
368*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[index], index,
369*49ef7e06SGarrett D'Amore sip->si_nalloc);
370*49ef7e06SGarrett D'Amore }
371*49ef7e06SGarrett D'Amore }
372*49ef7e06SGarrett D'Amore }
373*49ef7e06SGarrett D'Amore
374*49ef7e06SGarrett D'Amore sip->si_cap = 0;
375*49ef7e06SGarrett D'Amore
376*49ef7e06SGarrett D'Amore /* Remove all handlers */
377*49ef7e06SGarrett D'Amore index = sip->si_nalloc;
378*49ef7e06SGarrett D'Amore while (--index >= 0) {
379*49ef7e06SGarrett D'Amore err = ddi_intr_remove_handler(sip->si_table[index]);
380*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
381*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
382*49ef7e06SGarrett D'Amore "bus_disable: ddi_intr_remove_handler"
383*49ef7e06SGarrett D'Amore " failed err=%d (h=%p idx=%d nalloc=%d)",
384*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[index], index,
385*49ef7e06SGarrett D'Amore sip->si_nalloc);
386*49ef7e06SGarrett D'Amore }
387*49ef7e06SGarrett D'Amore }
388*49ef7e06SGarrett D'Amore
389*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
390*49ef7e06SGarrett D'Amore }
391*49ef7e06SGarrett D'Amore
392*49ef7e06SGarrett D'Amore static int
sfxge_intr_nic_enable(sfxge_t * sp)393*49ef7e06SGarrett D'Amore sfxge_intr_nic_enable(sfxge_t *sp)
394*49ef7e06SGarrett D'Amore {
395*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
396*49ef7e06SGarrett D'Amore efsys_mem_t *esmp = &(sip->si_mem);
397*49ef7e06SGarrett D'Amore efx_nic_t *enp = sp->s_enp;
398*49ef7e06SGarrett D'Amore unsigned int index;
399*49ef7e06SGarrett D'Amore uint64_t mask;
400*49ef7e06SGarrett D'Amore unsigned int count;
401*49ef7e06SGarrett D'Amore int rc;
402*49ef7e06SGarrett D'Amore
403*49ef7e06SGarrett D'Amore /* Zero the memory */
404*49ef7e06SGarrett D'Amore bzero(esmp->esm_base, EFX_INTR_SIZE);
405*49ef7e06SGarrett D'Amore
406*49ef7e06SGarrett D'Amore /* Enable interrupts at the NIC */
407*49ef7e06SGarrett D'Amore if ((rc = efx_intr_init(enp, sip->si_type, esmp)) != 0)
408*49ef7e06SGarrett D'Amore goto fail1;
409*49ef7e06SGarrett D'Amore
410*49ef7e06SGarrett D'Amore efx_intr_enable(enp);
411*49ef7e06SGarrett D'Amore
412*49ef7e06SGarrett D'Amore /* FIXME FIXME FIXME */
413*49ef7e06SGarrett D'Amore if (sp->s_family == EFX_FAMILY_HUNTINGTON) {
414*49ef7e06SGarrett D'Amore /* Disable interrupt test until supported on Huntington. */
415*49ef7e06SGarrett D'Amore return (0);
416*49ef7e06SGarrett D'Amore }
417*49ef7e06SGarrett D'Amore /* FIXME FIXME FIXME */
418*49ef7e06SGarrett D'Amore
419*49ef7e06SGarrett D'Amore /* Test the interrupts */
420*49ef7e06SGarrett D'Amore mask = 0;
421*49ef7e06SGarrett D'Amore for (index = 0; index < sip->si_nalloc; index++) {
422*49ef7e06SGarrett D'Amore mask |= (1 << index);
423*49ef7e06SGarrett D'Amore
424*49ef7e06SGarrett D'Amore rc = efx_intr_trigger(enp, index);
425*49ef7e06SGarrett D'Amore ASSERT3U(rc, ==, 0);
426*49ef7e06SGarrett D'Amore }
427*49ef7e06SGarrett D'Amore
428*49ef7e06SGarrett D'Amore /* Wait for the tests to complete */
429*49ef7e06SGarrett D'Amore count = 0;
430*49ef7e06SGarrett D'Amore do {
431*49ef7e06SGarrett D'Amore DTRACE_PROBE1(wait, unsigned int, count);
432*49ef7e06SGarrett D'Amore
433*49ef7e06SGarrett D'Amore /* Spin for 1 ms */
434*49ef7e06SGarrett D'Amore drv_usecwait(1000);
435*49ef7e06SGarrett D'Amore
436*49ef7e06SGarrett D'Amore /*
437*49ef7e06SGarrett D'Amore * Check to see that all the test interrupts have been
438*49ef7e06SGarrett D'Amore * processed.
439*49ef7e06SGarrett D'Amore */
440*49ef7e06SGarrett D'Amore if ((mask & sip->si_mask) == mask)
441*49ef7e06SGarrett D'Amore goto done;
442*49ef7e06SGarrett D'Amore
443*49ef7e06SGarrett D'Amore } while (++count < 20);
444*49ef7e06SGarrett D'Amore
445*49ef7e06SGarrett D'Amore rc = ETIMEDOUT;
446*49ef7e06SGarrett D'Amore goto fail2;
447*49ef7e06SGarrett D'Amore
448*49ef7e06SGarrett D'Amore done:
449*49ef7e06SGarrett D'Amore return (0);
450*49ef7e06SGarrett D'Amore
451*49ef7e06SGarrett D'Amore fail2:
452*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail2);
453*49ef7e06SGarrett D'Amore
454*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
455*49ef7e06SGarrett D'Amore "Interrupt test failed (mask=%"PRIx64" got=%"
456*49ef7e06SGarrett D'Amore PRIx64"). NIC is disabled",
457*49ef7e06SGarrett D'Amore mask, sip->si_mask);
458*49ef7e06SGarrett D'Amore
459*49ef7e06SGarrett D'Amore DTRACE_PROBE2(int_test_fail, uint64_t, mask, uint64_t, sip->si_mask);
460*49ef7e06SGarrett D'Amore
461*49ef7e06SGarrett D'Amore sip->si_mask = 0;
462*49ef7e06SGarrett D'Amore
463*49ef7e06SGarrett D'Amore /* Disable interrupts at the NIC */
464*49ef7e06SGarrett D'Amore efx_intr_disable(enp);
465*49ef7e06SGarrett D'Amore efx_intr_fini(enp);
466*49ef7e06SGarrett D'Amore
467*49ef7e06SGarrett D'Amore fail1:
468*49ef7e06SGarrett D'Amore DTRACE_PROBE1(fail1, int, rc);
469*49ef7e06SGarrett D'Amore
470*49ef7e06SGarrett D'Amore return (rc);
471*49ef7e06SGarrett D'Amore }
472*49ef7e06SGarrett D'Amore
473*49ef7e06SGarrett D'Amore static void
sfxge_intr_nic_disable(sfxge_t * sp)474*49ef7e06SGarrett D'Amore sfxge_intr_nic_disable(sfxge_t *sp)
475*49ef7e06SGarrett D'Amore {
476*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
477*49ef7e06SGarrett D'Amore efx_nic_t *enp = sp->s_enp;
478*49ef7e06SGarrett D'Amore
479*49ef7e06SGarrett D'Amore sip->si_mask = 0;
480*49ef7e06SGarrett D'Amore
481*49ef7e06SGarrett D'Amore /* Disable interrupts at the NIC */
482*49ef7e06SGarrett D'Amore efx_intr_disable(enp);
483*49ef7e06SGarrett D'Amore efx_intr_fini(enp);
484*49ef7e06SGarrett D'Amore }
485*49ef7e06SGarrett D'Amore
486*49ef7e06SGarrett D'Amore static inline unsigned
pow2_le(unsigned long n)487*49ef7e06SGarrett D'Amore pow2_le(unsigned long n)
488*49ef7e06SGarrett D'Amore {
489*49ef7e06SGarrett D'Amore unsigned int order = 1;
490*49ef7e06SGarrett D'Amore ASSERT3U(n, >, 0);
491*49ef7e06SGarrett D'Amore while ((1ul << order) <= n) ++order;
492*49ef7e06SGarrett D'Amore return (1ul << (order - 1));
493*49ef7e06SGarrett D'Amore }
494*49ef7e06SGarrett D'Amore
495*49ef7e06SGarrett D'Amore int
sfxge_intr_init(sfxge_t * sp)496*49ef7e06SGarrett D'Amore sfxge_intr_init(sfxge_t *sp)
497*49ef7e06SGarrett D'Amore {
498*49ef7e06SGarrett D'Amore dev_info_t *dip = sp->s_dip;
499*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
500*49ef7e06SGarrett D'Amore efsys_mem_t *esmp = &(sip->si_mem);
501*49ef7e06SGarrett D'Amore sfxge_dma_buffer_attr_t dma_attr;
502*49ef7e06SGarrett D'Amore int err;
503*49ef7e06SGarrett D'Amore int rc;
504*49ef7e06SGarrett D'Amore int types;
505*49ef7e06SGarrett D'Amore int type;
506*49ef7e06SGarrett D'Amore int index;
507*49ef7e06SGarrett D'Amore unsigned int nalloc;
508*49ef7e06SGarrett D'Amore int navail;
509*49ef7e06SGarrett D'Amore
510*49ef7e06SGarrett D'Amore SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
511*49ef7e06SGarrett D'Amore
512*49ef7e06SGarrett D'Amore ASSERT3U(sip->si_state, ==, SFXGE_INTR_UNINITIALIZED);
513*49ef7e06SGarrett D'Amore
514*49ef7e06SGarrett D'Amore #ifdef __sparc
515*49ef7e06SGarrett D'Amore /* PSARC 2007/453 */
516*49ef7e06SGarrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
517*49ef7e06SGarrett D'Amore "#msix-request", NULL, 0);
518*49ef7e06SGarrett D'Amore #endif
519*49ef7e06SGarrett D'Amore
520*49ef7e06SGarrett D'Amore /* Get the map of supported interrupt types */
521*49ef7e06SGarrett D'Amore err = ddi_intr_get_supported_types(dip, &types);
522*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
523*49ef7e06SGarrett D'Amore dev_err(dip, CE_WARN, SFXGE_CMN_ERR
524*49ef7e06SGarrett D'Amore "intr_init: ddi_intr_get_supported_types failed err=%d",
525*49ef7e06SGarrett D'Amore err);
526*49ef7e06SGarrett D'Amore
527*49ef7e06SGarrett D'Amore if (err == DDI_EINVAL)
528*49ef7e06SGarrett D'Amore rc = EINVAL;
529*49ef7e06SGarrett D'Amore else if (err == DDI_INTR_NOTFOUND)
530*49ef7e06SGarrett D'Amore rc = ENOENT;
531*49ef7e06SGarrett D'Amore else
532*49ef7e06SGarrett D'Amore rc = EFAULT;
533*49ef7e06SGarrett D'Amore
534*49ef7e06SGarrett D'Amore goto fail1;
535*49ef7e06SGarrett D'Amore }
536*49ef7e06SGarrett D'Amore
537*49ef7e06SGarrett D'Amore /* Choose most favourable type */
538*49ef7e06SGarrett D'Amore if (types & DDI_INTR_TYPE_MSIX) {
539*49ef7e06SGarrett D'Amore DTRACE_PROBE(msix);
540*49ef7e06SGarrett D'Amore
541*49ef7e06SGarrett D'Amore type = DDI_INTR_TYPE_MSIX;
542*49ef7e06SGarrett D'Amore sip->si_type = EFX_INTR_MESSAGE;
543*49ef7e06SGarrett D'Amore } else {
544*49ef7e06SGarrett D'Amore DTRACE_PROBE(fixed);
545*49ef7e06SGarrett D'Amore
546*49ef7e06SGarrett D'Amore ASSERT(types & DDI_INTR_TYPE_FIXED);
547*49ef7e06SGarrett D'Amore
548*49ef7e06SGarrett D'Amore type = DDI_INTR_TYPE_FIXED;
549*49ef7e06SGarrett D'Amore sip->si_type = EFX_INTR_LINE;
550*49ef7e06SGarrett D'Amore }
551*49ef7e06SGarrett D'Amore
552*49ef7e06SGarrett D'Amore /* Get the number of available interrupts */
553*49ef7e06SGarrett D'Amore navail = 0;
554*49ef7e06SGarrett D'Amore err = ddi_intr_get_navail(dip, type, &navail);
555*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
556*49ef7e06SGarrett D'Amore dev_err(dip, CE_WARN, SFXGE_CMN_ERR
557*49ef7e06SGarrett D'Amore "intr_init: ddi_intr_get_navail failed err=%d", err);
558*49ef7e06SGarrett D'Amore
559*49ef7e06SGarrett D'Amore if (err == DDI_EINVAL)
560*49ef7e06SGarrett D'Amore rc = EINVAL;
561*49ef7e06SGarrett D'Amore else if (err == DDI_INTR_NOTFOUND)
562*49ef7e06SGarrett D'Amore rc = ENOENT;
563*49ef7e06SGarrett D'Amore else
564*49ef7e06SGarrett D'Amore rc = EFAULT;
565*49ef7e06SGarrett D'Amore
566*49ef7e06SGarrett D'Amore goto fail2;
567*49ef7e06SGarrett D'Amore }
568*49ef7e06SGarrett D'Amore
569*49ef7e06SGarrett D'Amore /* Double-check */
570*49ef7e06SGarrett D'Amore if (navail == 0) {
571*49ef7e06SGarrett D'Amore rc = ENOENT;
572*49ef7e06SGarrett D'Amore goto fail2;
573*49ef7e06SGarrett D'Amore }
574*49ef7e06SGarrett D'Amore
575*49ef7e06SGarrett D'Amore /*
576*49ef7e06SGarrett D'Amore * Allow greater number of MSI-X interrupts than CPUs.
577*49ef7e06SGarrett D'Amore * This can be useful to prevent RX no desc drops; See task 32179.
578*49ef7e06SGarrett D'Amore * Limit non MSI-X interrupts to a single instance.
579*49ef7e06SGarrett D'Amore */
580*49ef7e06SGarrett D'Amore if (type != DDI_INTR_TYPE_MSIX)
581*49ef7e06SGarrett D'Amore navail = 1;
582*49ef7e06SGarrett D'Amore else
583*49ef7e06SGarrett D'Amore navail = min(navail, sfxge_rx_scale_prop_get(sp));
584*49ef7e06SGarrett D'Amore
585*49ef7e06SGarrett D'Amore DTRACE_PROBE1(navail, unsigned int, navail);
586*49ef7e06SGarrett D'Amore
587*49ef7e06SGarrett D'Amore /* Allocate a handle table */
588*49ef7e06SGarrett D'Amore sip->si_table_size = navail * sizeof (ddi_intr_handle_t);
589*49ef7e06SGarrett D'Amore sip->si_table = kmem_zalloc(sip->si_table_size, KM_SLEEP);
590*49ef7e06SGarrett D'Amore
591*49ef7e06SGarrett D'Amore /*
592*49ef7e06SGarrett D'Amore * Allocate interrupt handles.
593*49ef7e06SGarrett D'Amore * Serialise all device instances to avoid problems seen in bug31184.
594*49ef7e06SGarrett D'Amore */
595*49ef7e06SGarrett D'Amore mutex_enter(&sfxge_global_lock);
596*49ef7e06SGarrett D'Amore
597*49ef7e06SGarrett D'Amore err = ddi_intr_alloc(dip, sip->si_table, type, 0,
598*49ef7e06SGarrett D'Amore navail, &(sip->si_nalloc), DDI_INTR_ALLOC_NORMAL);
599*49ef7e06SGarrett D'Amore
600*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
601*49ef7e06SGarrett D'Amore
602*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
603*49ef7e06SGarrett D'Amore dev_err(dip, CE_WARN, SFXGE_CMN_ERR
604*49ef7e06SGarrett D'Amore "intr_init: ddi_intr_alloc failed err=%d"
605*49ef7e06SGarrett D'Amore " (navail=%d nalloc=%d)",
606*49ef7e06SGarrett D'Amore err, navail, sip->si_nalloc);
607*49ef7e06SGarrett D'Amore
608*49ef7e06SGarrett D'Amore if (err == DDI_EINVAL)
609*49ef7e06SGarrett D'Amore rc = EINVAL;
610*49ef7e06SGarrett D'Amore else if (err == DDI_EAGAIN)
611*49ef7e06SGarrett D'Amore rc = EAGAIN;
612*49ef7e06SGarrett D'Amore else if (err == DDI_INTR_NOTFOUND)
613*49ef7e06SGarrett D'Amore rc = ENOENT;
614*49ef7e06SGarrett D'Amore else
615*49ef7e06SGarrett D'Amore rc = EFAULT;
616*49ef7e06SGarrett D'Amore
617*49ef7e06SGarrett D'Amore goto fail3;
618*49ef7e06SGarrett D'Amore }
619*49ef7e06SGarrett D'Amore
620*49ef7e06SGarrett D'Amore /* Double-check */
621*49ef7e06SGarrett D'Amore if (sip->si_nalloc == 0) {
622*49ef7e06SGarrett D'Amore rc = ENOENT;
623*49ef7e06SGarrett D'Amore goto fail3;
624*49ef7e06SGarrett D'Amore }
625*49ef7e06SGarrett D'Amore
626*49ef7e06SGarrett D'Amore /* Round down to a power of 2 */
627*49ef7e06SGarrett D'Amore nalloc = pow2_le(sip->si_nalloc);
628*49ef7e06SGarrett D'Amore
629*49ef7e06SGarrett D'Amore /* Free off any excess handles */
630*49ef7e06SGarrett D'Amore mutex_enter(&sfxge_global_lock);
631*49ef7e06SGarrett D'Amore
632*49ef7e06SGarrett D'Amore index = sip->si_nalloc;
633*49ef7e06SGarrett D'Amore while (--index >= nalloc) {
634*49ef7e06SGarrett D'Amore (void) ddi_intr_free(sip->si_table[index]);
635*49ef7e06SGarrett D'Amore sip->si_table[index] = NULL;
636*49ef7e06SGarrett D'Amore }
637*49ef7e06SGarrett D'Amore
638*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
639*49ef7e06SGarrett D'Amore
640*49ef7e06SGarrett D'Amore sip->si_nalloc = nalloc;
641*49ef7e06SGarrett D'Amore DTRACE_PROBE1(nalloc, unsigned int, sip->si_nalloc);
642*49ef7e06SGarrett D'Amore
643*49ef7e06SGarrett D'Amore dma_attr.sdba_dip = sp->s_dip;
644*49ef7e06SGarrett D'Amore dma_attr.sdba_dattrp = &sfxge_intr_dma_attr;
645*49ef7e06SGarrett D'Amore dma_attr.sdba_callback = DDI_DMA_SLEEP;
646*49ef7e06SGarrett D'Amore dma_attr.sdba_length = EFX_INTR_SIZE;
647*49ef7e06SGarrett D'Amore dma_attr.sdba_memflags = DDI_DMA_CONSISTENT;
648*49ef7e06SGarrett D'Amore dma_attr.sdba_devaccp = &sfxge_intr_devacc;
649*49ef7e06SGarrett D'Amore dma_attr.sdba_bindflags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
650*49ef7e06SGarrett D'Amore dma_attr.sdba_maxcookies = 1;
651*49ef7e06SGarrett D'Amore dma_attr.sdba_zeroinit = B_TRUE;
652*49ef7e06SGarrett D'Amore
653*49ef7e06SGarrett D'Amore if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
654*49ef7e06SGarrett D'Amore goto fail4;
655*49ef7e06SGarrett D'Amore
656*49ef7e06SGarrett D'Amore /* Store the highest priority for convenience */
657*49ef7e06SGarrett D'Amore sip->si_intr_pri = 0;
658*49ef7e06SGarrett D'Amore for (index = 0; index < sip->si_nalloc; index++) {
659*49ef7e06SGarrett D'Amore uint_t pri;
660*49ef7e06SGarrett D'Amore if ((rc = ddi_intr_get_pri(sip->si_table[index], &pri)) != 0)
661*49ef7e06SGarrett D'Amore goto fail5;
662*49ef7e06SGarrett D'Amore if (pri > sip->si_intr_pri)
663*49ef7e06SGarrett D'Amore sip->si_intr_pri = pri;
664*49ef7e06SGarrett D'Amore }
665*49ef7e06SGarrett D'Amore
666*49ef7e06SGarrett D'Amore sip->si_state = SFXGE_INTR_INITIALIZED;
667*49ef7e06SGarrett D'Amore return (0);
668*49ef7e06SGarrett D'Amore
669*49ef7e06SGarrett D'Amore fail5:
670*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail5);
671*49ef7e06SGarrett D'Amore
672*49ef7e06SGarrett D'Amore fail4:
673*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail4);
674*49ef7e06SGarrett D'Amore
675*49ef7e06SGarrett D'Amore /* Free interrupt handles */
676*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
677*49ef7e06SGarrett D'Amore
678*49ef7e06SGarrett D'Amore index = sip->si_nalloc;
679*49ef7e06SGarrett D'Amore while (--index >= 0) {
680*49ef7e06SGarrett D'Amore err = ddi_intr_free(sip->si_table[index]);
681*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
682*49ef7e06SGarrett D'Amore dev_err(dip, CE_WARN, SFXGE_CMN_ERR
683*49ef7e06SGarrett D'Amore "intr_init: ddi_intr_free failed err=%d"
684*49ef7e06SGarrett D'Amore " (h=%p idx=%d nalloc=%d)",
685*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[index], index,
686*49ef7e06SGarrett D'Amore sip->si_nalloc);
687*49ef7e06SGarrett D'Amore }
688*49ef7e06SGarrett D'Amore sip->si_table[index] = NULL;
689*49ef7e06SGarrett D'Amore }
690*49ef7e06SGarrett D'Amore sip->si_nalloc = 0;
691*49ef7e06SGarrett D'Amore
692*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
693*49ef7e06SGarrett D'Amore
694*49ef7e06SGarrett D'Amore fail3:
695*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail3);
696*49ef7e06SGarrett D'Amore
697*49ef7e06SGarrett D'Amore /* Free the handle table */
698*49ef7e06SGarrett D'Amore kmem_free(sip->si_table, sip->si_table_size);
699*49ef7e06SGarrett D'Amore sip->si_table = NULL;
700*49ef7e06SGarrett D'Amore sip->si_table_size = 0;
701*49ef7e06SGarrett D'Amore
702*49ef7e06SGarrett D'Amore fail2:
703*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail2);
704*49ef7e06SGarrett D'Amore
705*49ef7e06SGarrett D'Amore /* Clear the interrupt type */
706*49ef7e06SGarrett D'Amore sip->si_type = EFX_INTR_INVALID;
707*49ef7e06SGarrett D'Amore
708*49ef7e06SGarrett D'Amore fail1:
709*49ef7e06SGarrett D'Amore DTRACE_PROBE1(fail1, int, rc);
710*49ef7e06SGarrett D'Amore
711*49ef7e06SGarrett D'Amore SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
712*49ef7e06SGarrett D'Amore
713*49ef7e06SGarrett D'Amore return (rc);
714*49ef7e06SGarrett D'Amore }
715*49ef7e06SGarrett D'Amore
716*49ef7e06SGarrett D'Amore int
sfxge_intr_start(sfxge_t * sp)717*49ef7e06SGarrett D'Amore sfxge_intr_start(sfxge_t *sp)
718*49ef7e06SGarrett D'Amore {
719*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
720*49ef7e06SGarrett D'Amore int rc;
721*49ef7e06SGarrett D'Amore
722*49ef7e06SGarrett D'Amore ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
723*49ef7e06SGarrett D'Amore
724*49ef7e06SGarrett D'Amore /* Enable interrupts at the bus */
725*49ef7e06SGarrett D'Amore if ((rc = sfxge_intr_bus_enable(sp)) != 0)
726*49ef7e06SGarrett D'Amore goto fail1;
727*49ef7e06SGarrett D'Amore
728*49ef7e06SGarrett D'Amore sip->si_state = SFXGE_INTR_TESTING;
729*49ef7e06SGarrett D'Amore
730*49ef7e06SGarrett D'Amore /* Enable interrupts at the NIC */
731*49ef7e06SGarrett D'Amore if ((rc = sfxge_intr_nic_enable(sp)) != 0)
732*49ef7e06SGarrett D'Amore goto fail2;
733*49ef7e06SGarrett D'Amore
734*49ef7e06SGarrett D'Amore sip->si_state = SFXGE_INTR_STARTED;
735*49ef7e06SGarrett D'Amore
736*49ef7e06SGarrett D'Amore return (0);
737*49ef7e06SGarrett D'Amore
738*49ef7e06SGarrett D'Amore fail2:
739*49ef7e06SGarrett D'Amore DTRACE_PROBE(fail2);
740*49ef7e06SGarrett D'Amore
741*49ef7e06SGarrett D'Amore /* Disable interrupts at the bus */
742*49ef7e06SGarrett D'Amore sfxge_intr_bus_disable(sp);
743*49ef7e06SGarrett D'Amore
744*49ef7e06SGarrett D'Amore fail1:
745*49ef7e06SGarrett D'Amore DTRACE_PROBE1(fail1, int, rc);
746*49ef7e06SGarrett D'Amore
747*49ef7e06SGarrett D'Amore sip->si_state = SFXGE_INTR_INITIALIZED;
748*49ef7e06SGarrett D'Amore
749*49ef7e06SGarrett D'Amore return (rc);
750*49ef7e06SGarrett D'Amore }
751*49ef7e06SGarrett D'Amore
752*49ef7e06SGarrett D'Amore void
sfxge_intr_stop(sfxge_t * sp)753*49ef7e06SGarrett D'Amore sfxge_intr_stop(sfxge_t *sp)
754*49ef7e06SGarrett D'Amore {
755*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
756*49ef7e06SGarrett D'Amore
757*49ef7e06SGarrett D'Amore ASSERT3U(sip->si_state, ==, SFXGE_INTR_STARTED);
758*49ef7e06SGarrett D'Amore
759*49ef7e06SGarrett D'Amore sip->si_state = SFXGE_INTR_INITIALIZED;
760*49ef7e06SGarrett D'Amore
761*49ef7e06SGarrett D'Amore /* Disable interrupts at the NIC */
762*49ef7e06SGarrett D'Amore sfxge_intr_nic_disable(sp);
763*49ef7e06SGarrett D'Amore
764*49ef7e06SGarrett D'Amore /* Disable interrupts at the bus */
765*49ef7e06SGarrett D'Amore sfxge_intr_bus_disable(sp);
766*49ef7e06SGarrett D'Amore }
767*49ef7e06SGarrett D'Amore
768*49ef7e06SGarrett D'Amore void
sfxge_intr_fini(sfxge_t * sp)769*49ef7e06SGarrett D'Amore sfxge_intr_fini(sfxge_t *sp)
770*49ef7e06SGarrett D'Amore {
771*49ef7e06SGarrett D'Amore sfxge_intr_t *sip = &(sp->s_intr);
772*49ef7e06SGarrett D'Amore efsys_mem_t *esmp = &(sip->si_mem);
773*49ef7e06SGarrett D'Amore int index;
774*49ef7e06SGarrett D'Amore int err;
775*49ef7e06SGarrett D'Amore
776*49ef7e06SGarrett D'Amore ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
777*49ef7e06SGarrett D'Amore
778*49ef7e06SGarrett D'Amore sip->si_state = SFXGE_INTR_UNINITIALIZED;
779*49ef7e06SGarrett D'Amore
780*49ef7e06SGarrett D'Amore /* Tear down dma setup */
781*49ef7e06SGarrett D'Amore sfxge_dma_buffer_destroy(esmp);
782*49ef7e06SGarrett D'Amore
783*49ef7e06SGarrett D'Amore
784*49ef7e06SGarrett D'Amore /* Free interrupt handles */
785*49ef7e06SGarrett D'Amore mutex_enter(&sfxge_global_lock);
786*49ef7e06SGarrett D'Amore
787*49ef7e06SGarrett D'Amore index = sip->si_nalloc;
788*49ef7e06SGarrett D'Amore while (--index >= 0) {
789*49ef7e06SGarrett D'Amore err = ddi_intr_free(sip->si_table[index]);
790*49ef7e06SGarrett D'Amore if (err != DDI_SUCCESS) {
791*49ef7e06SGarrett D'Amore dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
792*49ef7e06SGarrett D'Amore "intr_fini: ddi_intr_free failed err=%d"
793*49ef7e06SGarrett D'Amore " (h=%p idx=%d nalloc=%d)",
794*49ef7e06SGarrett D'Amore err, (void *)sip->si_table[index],
795*49ef7e06SGarrett D'Amore index, sip->si_nalloc);
796*49ef7e06SGarrett D'Amore }
797*49ef7e06SGarrett D'Amore sip->si_table[index] = NULL;
798*49ef7e06SGarrett D'Amore }
799*49ef7e06SGarrett D'Amore sip->si_nalloc = 0;
800*49ef7e06SGarrett D'Amore
801*49ef7e06SGarrett D'Amore mutex_exit(&sfxge_global_lock);
802*49ef7e06SGarrett D'Amore
803*49ef7e06SGarrett D'Amore /* Free the handle table */
804*49ef7e06SGarrett D'Amore kmem_free(sip->si_table, sip->si_table_size);
805*49ef7e06SGarrett D'Amore sip->si_table = NULL;
806*49ef7e06SGarrett D'Amore sip->si_table_size = 0;
807*49ef7e06SGarrett D'Amore
808*49ef7e06SGarrett D'Amore /* Clear the interrupt type */
809*49ef7e06SGarrett D'Amore sip->si_type = EFX_INTR_INVALID;
810*49ef7e06SGarrett D'Amore
811*49ef7e06SGarrett D'Amore SFXGE_OBJ_CHECK(sip, sfxge_intr_t);
812*49ef7e06SGarrett D'Amore }
813