]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/sfxge/sfxge_intr.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / sfxge / sfxge_intr.c
1 /*-
2  * Copyright (c) 2010-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * This software was developed in part by Philip Paeps under contract for
6  * Solarflare Communications, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and documentation are
30  * those of the authors and should not be interpreted as representing official
31  * policies, either expressed or implied, of the FreeBSD Project.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/syslog.h>
41
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcivar.h>
47
48 #include "common/efx.h"
49
50 #include "sfxge.h"
51
52 static int
53 sfxge_intr_line_filter(void *arg)
54 {
55         struct sfxge_evq *evq;
56         struct sfxge_softc *sc;
57         efx_nic_t *enp;
58         struct sfxge_intr *intr;
59         boolean_t fatal;
60         uint32_t qmask;
61
62         evq = (struct sfxge_evq *)arg;
63         sc = evq->sc;
64         enp = sc->enp;
65         intr = &sc->intr;
66
67         KASSERT(intr != NULL, ("intr == NULL"));
68         KASSERT(intr->type == EFX_INTR_LINE,
69             ("intr->type != EFX_INTR_LINE"));
70
71         if (intr->state != SFXGE_INTR_STARTED)
72                 return (FILTER_STRAY);
73
74         (void)efx_intr_status_line(enp, &fatal, &qmask);
75
76         if (fatal) {
77                 (void) efx_intr_disable(enp);
78                 (void) efx_intr_fatal(enp);
79                 return (FILTER_HANDLED);
80         }
81
82         if (qmask != 0) {
83                 intr->zero_count = 0;
84                 return (FILTER_SCHEDULE_THREAD);
85         }
86
87         /* SF bug 15783: If the function is not asserting its IRQ and
88          * we read the queue mask on the cycle before a flag is added
89          * to the mask, this inhibits the function from asserting the
90          * IRQ even though we don't see the flag set.  To work around
91          * this, we must re-prime all event queues and report the IRQ
92          * as handled when we see a mask of zero.  To allow for shared
93          * IRQs, we don't repeat this if we see a mask of zero twice
94          * or more in a row.
95          */
96         if (intr->zero_count++ == 0) {
97                 if (evq->init_state == SFXGE_EVQ_STARTED) {
98                         if (efx_ev_qpending(evq->common, evq->read_ptr))
99                                 return (FILTER_SCHEDULE_THREAD);
100                         efx_ev_qprime(evq->common, evq->read_ptr);
101                         return (FILTER_HANDLED);
102                 }
103         }
104
105         return (FILTER_STRAY);
106 }
107
108 static void
109 sfxge_intr_line(void *arg)
110 {
111         struct sfxge_evq *evq = arg;
112
113         (void)sfxge_ev_qpoll(evq);
114 }
115
116 static void
117 sfxge_intr_message(void *arg)
118 {
119         struct sfxge_evq *evq;
120         struct sfxge_softc *sc;
121         efx_nic_t *enp;
122         struct sfxge_intr *intr;
123         unsigned int index;
124         boolean_t fatal;
125
126         evq = (struct sfxge_evq *)arg;
127         sc = evq->sc;
128         enp = sc->enp;
129         intr = &sc->intr;
130         index = evq->index;
131
132         KASSERT(intr != NULL, ("intr == NULL"));
133         KASSERT(intr->type == EFX_INTR_MESSAGE,
134             ("intr->type != EFX_INTR_MESSAGE"));
135
136         if (__predict_false(intr->state != SFXGE_INTR_STARTED))
137                 return;
138
139         (void)efx_intr_status_message(enp, index, &fatal);
140
141         if (fatal) {
142                 (void)efx_intr_disable(enp);
143                 (void)efx_intr_fatal(enp);
144                 return;
145         }
146
147         (void)sfxge_ev_qpoll(evq);
148 }
149
150 static int
151 sfxge_intr_bus_enable(struct sfxge_softc *sc)
152 {
153         struct sfxge_intr *intr;
154         struct sfxge_intr_hdl *table;
155         driver_filter_t *filter;
156         driver_intr_t *handler;
157         int index;
158         int err;
159
160         intr = &sc->intr;
161         table = intr->table;
162
163         switch (intr->type) {
164         case EFX_INTR_MESSAGE:
165                 filter = NULL; /* not shared */
166                 handler = sfxge_intr_message;
167                 break;
168
169         case EFX_INTR_LINE:
170                 filter = sfxge_intr_line_filter;
171                 handler = sfxge_intr_line;
172                 break;
173
174         default:
175                 KASSERT(0, ("Invalid interrupt type"));
176                 return (EINVAL);
177         }
178
179         /* Try to add the handlers */
180         for (index = 0; index < intr->n_alloc; index++) {
181                 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
182                             INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
183                             sc->evq[index], &table[index].eih_tag)) != 0) {
184                         goto fail;
185                 }
186 #ifdef SFXGE_HAVE_DESCRIBE_INTR
187                 if (intr->n_alloc > 1)
188                         bus_describe_intr(sc->dev, table[index].eih_res,
189                             table[index].eih_tag, "%d", index);
190 #endif
191                 bus_bind_intr(sc->dev, table[index].eih_res, index);
192
193         }
194
195         return (0);
196
197 fail:
198         /* Remove remaining handlers */
199         while (--index >= 0)
200                 bus_teardown_intr(sc->dev, table[index].eih_res,
201                     table[index].eih_tag);
202
203         return (err);
204 }
205
206 static void
207 sfxge_intr_bus_disable(struct sfxge_softc *sc)
208 {
209         struct sfxge_intr *intr;
210         struct sfxge_intr_hdl *table;
211         int i;
212
213         intr = &sc->intr;
214         table = intr->table;
215
216         /* Remove all handlers */
217         for (i = 0; i < intr->n_alloc; i++)
218                 bus_teardown_intr(sc->dev, table[i].eih_res,
219                     table[i].eih_tag);
220 }
221
222 static int
223 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
224 {
225         device_t dev;
226         struct sfxge_intr_hdl *table;
227         struct sfxge_intr *intr;
228         struct resource *res;
229         int rid;
230         int error;
231         int i;
232
233         dev = sc->dev;
234         intr = &sc->intr;
235         error = 0;
236
237         table = malloc(count * sizeof(struct sfxge_intr_hdl),
238             M_SFXGE, M_WAITOK);
239         intr->table = table;
240
241         for (i = 0; i < count; i++) {
242                 rid = i + 1;
243                 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
244                     RF_SHAREABLE | RF_ACTIVE);
245                 if (res == NULL) {
246                         device_printf(dev, "Couldn't allocate interrupts for "
247                             "message %d\n", rid);
248                         error = ENOMEM;
249                         break;
250                 }
251                 table[i].eih_rid = rid;
252                 table[i].eih_res = res;
253         }
254
255         if (error != 0) {
256                 count = i - 1;
257                 for (i = 0; i < count; i++)
258                         bus_release_resource(dev, SYS_RES_IRQ,
259                             table[i].eih_rid, table[i].eih_res);
260         }
261
262         return (error);
263 }
264
265 static void
266 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
267 {
268         device_t dev;
269         struct resource *resp;
270         int rid;
271
272         dev = sc->dev;
273         resp = sc->intr.msix_res;
274
275         rid = rman_get_rid(resp);
276         bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
277 }
278
279 static int
280 sfxge_intr_setup_msix(struct sfxge_softc *sc)
281 {
282         struct sfxge_intr *intr;
283         struct resource *resp;
284         device_t dev;
285         int count;
286         int rid;
287
288         dev = sc->dev;
289         intr = &sc->intr;
290
291         /* Check if MSI-X is available. */
292         count = pci_msix_count(dev);
293         if (count == 0)
294                 return (EINVAL);
295
296         /* Do not try to allocate more than already estimated EVQ maximum */
297         KASSERT(sc->evq_max > 0, ("evq_max is zero"));
298         count = MIN(count, sc->evq_max);
299
300         rid = PCIR_BAR(4);
301         resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
302         if (resp == NULL)
303                 return (ENOMEM);
304
305         if (pci_alloc_msix(dev, &count) != 0) {
306                 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
307                 return (ENOMEM);
308         }
309
310         /* Allocate interrupt handlers. */
311         if (sfxge_intr_alloc(sc, count) != 0) {
312                 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
313                 pci_release_msi(dev);
314                 return (ENOMEM);
315         }
316
317         intr->type = EFX_INTR_MESSAGE;
318         intr->n_alloc = count;
319         intr->msix_res = resp;
320
321         return (0);
322 }
323
324 static int
325 sfxge_intr_setup_msi(struct sfxge_softc *sc)
326 {
327         struct sfxge_intr_hdl *table;
328         struct sfxge_intr *intr;
329         device_t dev;
330         int count;
331         int error;
332
333         dev = sc->dev;
334         intr = &sc->intr;
335         table = intr->table;
336
337         /*
338          * Check if MSI is available.  All messages must be written to
339          * the same address and on x86 this means the IRQs have the
340          * same CPU affinity.  So we only ever allocate 1.
341          */
342         count = pci_msi_count(dev) ? 1 : 0;
343         if (count == 0)
344                 return (EINVAL);
345
346         if ((error = pci_alloc_msi(dev, &count)) != 0)
347                 return (ENOMEM);
348
349         /* Allocate interrupt handler. */
350         if (sfxge_intr_alloc(sc, count) != 0) {
351                 pci_release_msi(dev);
352                 return (ENOMEM);
353         }
354
355         intr->type = EFX_INTR_MESSAGE;
356         intr->n_alloc = count;
357
358         return (0);
359 }
360
361 static int
362 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
363 {
364         struct sfxge_intr_hdl *table;
365         struct sfxge_intr *intr;
366         struct resource *res;
367         device_t dev;
368         int rid;
369
370         dev = sc->dev;
371         intr = &sc->intr;
372
373         rid = 0;
374         res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
375             RF_SHAREABLE | RF_ACTIVE);
376         if (res == NULL)
377                 return (ENOMEM);
378
379         table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
380         table[0].eih_rid = rid;
381         table[0].eih_res = res;
382
383         intr->type = EFX_INTR_LINE;
384         intr->n_alloc = 1;
385         intr->table = table;
386
387         return (0);
388 }
389
390 static const char *const __sfxge_err[] = {
391         "",
392         "SRAM out-of-bounds",
393         "Buffer ID out-of-bounds",
394         "Internal memory parity",
395         "Receive buffer ownership",
396         "Transmit buffer ownership",
397         "Receive descriptor ownership",
398         "Transmit descriptor ownership",
399         "Event queue ownership",
400         "Event queue FIFO overflow",
401         "Illegal address",
402         "SRAM parity"
403 };
404
405 void
406 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
407           uint32_t dword1)
408 {
409         struct sfxge_softc *sc = (struct sfxge_softc *)arg;
410         device_t dev = sc->dev;
411
412         log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
413             device_get_name(dev), device_get_unit(dev),
414                 __sfxge_err[code], dword1, dword0);
415 }
416
417 void
418 sfxge_intr_stop(struct sfxge_softc *sc)
419 {
420         struct sfxge_intr *intr;
421
422         intr = &sc->intr;
423
424         KASSERT(intr->state == SFXGE_INTR_STARTED,
425             ("Interrupts not started"));
426
427         intr->state = SFXGE_INTR_INITIALIZED;
428
429         /* Disable interrupts at the NIC */
430         efx_intr_disable(sc->enp);
431
432         /* Disable interrupts at the bus */
433         sfxge_intr_bus_disable(sc);
434
435         /* Tear down common code interrupt bits. */
436         efx_intr_fini(sc->enp);
437 }
438
439 int
440 sfxge_intr_start(struct sfxge_softc *sc)
441 {
442         struct sfxge_intr *intr;
443         efsys_mem_t *esmp;
444         int rc;
445
446         intr = &sc->intr;
447         esmp = &intr->status;
448
449         KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
450             ("Interrupts not initialized"));
451
452         /* Zero the memory. */
453         (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
454
455         /* Initialize common code interrupt bits. */
456         (void)efx_intr_init(sc->enp, intr->type, esmp);
457
458         /* Enable interrupts at the bus */
459         if ((rc = sfxge_intr_bus_enable(sc)) != 0)
460                 goto fail;
461
462         intr->state = SFXGE_INTR_STARTED;
463
464         /* Enable interrupts at the NIC */
465         efx_intr_enable(sc->enp);
466
467         return (0);
468
469 fail:
470         /* Tear down common code interrupt bits. */
471         efx_intr_fini(sc->enp);
472
473         intr->state = SFXGE_INTR_INITIALIZED;
474
475         return (rc);
476 }
477
478 void
479 sfxge_intr_fini(struct sfxge_softc *sc)
480 {
481         struct sfxge_intr_hdl *table;
482         struct sfxge_intr *intr;
483         efsys_mem_t *esmp;
484         device_t dev;
485         int i;
486
487         dev = sc->dev;
488         intr = &sc->intr;
489         esmp = &intr->status;
490         table = intr->table;
491
492         KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
493             ("intr->state != SFXGE_INTR_INITIALIZED"));
494
495         /* Free DMA memory. */
496         sfxge_dma_free(esmp);
497
498         /* Free interrupt handles. */
499         for (i = 0; i < intr->n_alloc; i++)
500                 bus_release_resource(dev, SYS_RES_IRQ,
501                     table[i].eih_rid, table[i].eih_res);
502
503         if (table[0].eih_rid != 0)
504                 pci_release_msi(dev);
505
506         if (intr->msix_res != NULL)
507                 sfxge_intr_teardown_msix(sc);
508
509         /* Free the handle table */
510         free(table, M_SFXGE);
511         intr->table = NULL;
512         intr->n_alloc = 0;
513
514         /* Clear the interrupt type */
515         intr->type = EFX_INTR_INVALID;
516
517         intr->state = SFXGE_INTR_UNINITIALIZED;
518 }
519
520 int
521 sfxge_intr_init(struct sfxge_softc *sc)
522 {
523         device_t dev;
524         struct sfxge_intr *intr;
525         efsys_mem_t *esmp;
526         int rc;
527
528         dev = sc->dev;
529         intr = &sc->intr;
530         esmp = &intr->status;
531
532         KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
533             ("Interrupts already initialized"));
534
535         /* Try to setup MSI-X or MSI interrupts if available. */
536         if ((rc = sfxge_intr_setup_msix(sc)) == 0)
537                 device_printf(dev, "Using MSI-X interrupts\n");
538         else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
539                 device_printf(dev, "Using MSI interrupts\n");
540         else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
541                 device_printf(dev, "Using fixed interrupts\n");
542         } else {
543                 device_printf(dev, "Couldn't setup interrupts\n");
544                 return (ENOMEM);
545         }
546
547         /* Set up DMA for interrupts. */
548         if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
549                 return (ENOMEM);
550
551         intr->state = SFXGE_INTR_INITIALIZED;
552
553         return (0);
554 }