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