]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/sfxge/common/efx_intr.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / sfxge / common / efx_intr.c
1 /*-
2  * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_types.h"
32 #include "efx_regs.h"
33 #include "efx_impl.h"
34
35         __checkReturn   int
36 efx_intr_init(
37         __in            efx_nic_t *enp,
38         __in            efx_intr_type_t type,
39         __in            efsys_mem_t *esmp)
40 {
41         efx_intr_t *eip = &(enp->en_intr);
42         efx_oword_t oword;
43         int rc;
44
45         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
46         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
47
48         if (enp->en_mod_flags & EFX_MOD_INTR) {
49                 rc = EINVAL;
50                 goto fail1;
51         }
52
53         enp->en_mod_flags |= EFX_MOD_INTR;
54
55         eip->ei_type = type;
56         eip->ei_esmp = esmp;
57
58         /*
59          * bug17213 workaround.
60          *
61          * Under legacy interrupts, don't share a level between fatal
62          * interrupts and event queue interrupts. Under MSI-X, they
63          * must share, or we won't get an interrupt.
64          */
65         if (enp->en_family == EFX_FAMILY_SIENA &&
66             eip->ei_type == EFX_INTR_LINE)
67                 eip->ei_level = 0x1f;
68         else
69                 eip->ei_level = 0;
70
71         /* Enable all the genuinely fatal interrupts */
72         EFX_SET_OWORD(oword);
73         EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
74         EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
75         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
76         if (enp->en_family >= EFX_FAMILY_SIENA)
77                 EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
78         EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
79
80         /* Set up the interrupt address register */
81         EFX_POPULATE_OWORD_3(oword,
82             FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
83             FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
84             FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
85         EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
86
87         return (0);
88
89 fail1:
90         EFSYS_PROBE1(fail1, int, rc);
91
92         return (rc);
93 }
94
95                         void
96 efx_intr_enable(
97         __in            efx_nic_t *enp)
98 {
99         efx_intr_t *eip = &(enp->en_intr);
100         efx_oword_t oword;
101
102         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
103         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
104
105         EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
106
107         EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
108         EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
109         EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
110 }
111
112                         void
113 efx_intr_disable(
114         __in            efx_nic_t *enp)
115 {
116         efx_oword_t oword;
117
118         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
119         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
120
121         EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
122         EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
123         EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
124
125         EFSYS_SPIN(10);
126 }
127
128                         void
129 efx_intr_disable_unlocked(
130         __in            efx_nic_t *enp)
131 {
132         efx_oword_t oword;
133
134         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
135         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
136
137         EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
138                         &oword, B_FALSE);
139         EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
140         EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
141             &oword, B_FALSE);
142 }
143
144         __checkReturn   int
145 efx_intr_trigger(
146         __in            efx_nic_t *enp,
147         __in            unsigned int level)
148 {
149         efx_intr_t *eip = &(enp->en_intr);
150         efx_oword_t oword;
151         unsigned int count;
152         uint32_t sel;
153         int rc;
154
155         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
157
158         /* bug16757: No event queues can be initialized */
159         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
160
161         switch (enp->en_family) {
162         case EFX_FAMILY_FALCON:
163                 if (level > EFX_NINTR_FALCON) {
164                         rc = EINVAL;
165                         goto fail1;
166                 }
167                 break;
168
169         case EFX_FAMILY_SIENA:
170                 if (level > EFX_NINTR_SIENA) {
171                         rc = EINVAL;
172                         goto fail1;
173                 }
174                 break;
175
176         default:
177                 EFSYS_ASSERT(B_FALSE);
178                 break;
179         }
180
181         if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
182                 return (ENOTSUP); /* avoid EFSYS_PROBE() */
183
184         sel = level;
185
186         /* Trigger a test interrupt */
187         EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
188         EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
189         EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
190         EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
191
192         /*
193          * Wait up to 100ms for the interrupt to be raised before restoring
194          * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
195          * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
196          */
197         count = 0;
198         do {
199                 EFSYS_SPIN(100);        /* 100us */
200
201                 EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
202         } while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
203
204         EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
205         EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
206
207         return (0);
208
209 fail1:
210         EFSYS_PROBE1(fail1, int, rc);
211
212         return (rc);
213 }
214
215 static  __checkReturn   boolean_t
216 efx_intr_check_fatal(
217         __in            efx_nic_t *enp)
218 {
219         efx_intr_t *eip = &(enp->en_intr);
220         efsys_mem_t *esmp = eip->ei_esmp;
221         efx_oword_t oword;
222
223         /* Read the syndrome */
224         EFSYS_MEM_READO(esmp, 0, &oword);
225
226         if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
227                 EFSYS_PROBE(fatal);
228
229                 /* Clear the fatal interrupt condition */
230                 EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
231                 EFSYS_MEM_WRITEO(esmp, 0, &oword);
232
233                 return (B_TRUE);
234         }
235
236         return (B_FALSE);
237 }
238
239                         void
240 efx_intr_status_line(
241         __in            efx_nic_t *enp,
242         __out           boolean_t *fatalp,
243         __out           uint32_t *qmaskp)
244 {
245         efx_intr_t *eip = &(enp->en_intr);
246         efx_dword_t dword;
247
248         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
249         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
250
251         /*
252          * Read the queue mask and implicitly acknowledge the
253          * interrupt.
254          */
255         EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
256         *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
257
258         EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
259
260         if (*qmaskp & (1U << eip->ei_level))
261                 *fatalp = efx_intr_check_fatal(enp);
262         else
263                 *fatalp = B_FALSE;
264 }
265
266                         void
267 efx_intr_status_message(
268         __in            efx_nic_t *enp,
269         __in            unsigned int message,
270         __out           boolean_t *fatalp)
271 {
272         efx_intr_t *eip = &(enp->en_intr);
273
274         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
275         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
276
277         if (message == eip->ei_level)
278                 *fatalp = efx_intr_check_fatal(enp);
279         else
280                 *fatalp = B_FALSE;
281 }
282
283                 void
284 efx_intr_fatal(
285         __in    efx_nic_t *enp)
286 {
287 #if EFSYS_OPT_DECODE_INTR_FATAL
288         efx_oword_t fatal;
289         efx_oword_t mem_per;
290
291         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
292         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
293
294         EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
295         EFX_ZERO_OWORD(mem_per);
296
297         if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
298             EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
299                 EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
300
301         if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
302                 EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
303
304         if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
305                 EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
306
307         if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
308                 EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
309                     EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
310                     EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
311
312         if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
313                 EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
314
315         if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
316                 EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
317
318         if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
319                 EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
320
321         if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
322                 EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
323
324         if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
325                 EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
326
327         if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
328                 EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
329
330         if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
331                 EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
332
333         if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
334                 EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
335                     EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
336                     EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
337 #else
338         EFSYS_ASSERT(0);
339 #endif
340 }
341
342                 void
343 efx_intr_fini(
344         __in    efx_nic_t *enp)
345 {
346         efx_oword_t oword;
347
348         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
349         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
350         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
351
352         /* Clear the interrupt address register */
353         EFX_ZERO_OWORD(oword);
354         EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
355
356         enp->en_mod_flags &= ~EFX_MOD_INTR;
357 }