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