942dac6b78e457571ee08243252fd9ee386fbe45
[dpdk.git] / drivers / net / sfc / base / efx_ev.c
1 /*
2  * Copyright (c) 2007-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34 #define EFX_EV_QSTAT_INCR(_eep, _stat)
35
36 #define EFX_EV_PRESENT(_qword)                                          \
37         (EFX_QWORD_FIELD((_qword), EFX_DWORD_0) != 0xffffffff &&        \
38         EFX_QWORD_FIELD((_qword), EFX_DWORD_1) != 0xffffffff)
39
40
41
42         __checkReturn   efx_rc_t
43 efx_ev_init(
44         __in            efx_nic_t *enp)
45 {
46         const efx_ev_ops_t *eevop;
47         efx_rc_t rc;
48
49         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
50         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
51
52         if (enp->en_mod_flags & EFX_MOD_EV) {
53                 rc = EINVAL;
54                 goto fail1;
55         }
56
57         switch (enp->en_family) {
58
59         default:
60                 EFSYS_ASSERT(0);
61                 rc = ENOTSUP;
62                 goto fail1;
63         }
64
65         EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0);
66
67         if ((rc = eevop->eevo_init(enp)) != 0)
68                 goto fail2;
69
70         enp->en_eevop = eevop;
71         enp->en_mod_flags |= EFX_MOD_EV;
72         return (0);
73
74 fail2:
75         EFSYS_PROBE(fail2);
76
77 fail1:
78         EFSYS_PROBE1(fail1, efx_rc_t, rc);
79
80         enp->en_eevop = NULL;
81         enp->en_mod_flags &= ~EFX_MOD_EV;
82         return (rc);
83 }
84
85                 void
86 efx_ev_fini(
87         __in    efx_nic_t *enp)
88 {
89         const efx_ev_ops_t *eevop = enp->en_eevop;
90
91         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
92         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
93         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV);
94         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX));
95         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX));
96         EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0);
97
98         eevop->eevo_fini(enp);
99
100         enp->en_eevop = NULL;
101         enp->en_mod_flags &= ~EFX_MOD_EV;
102 }
103
104
105         __checkReturn   efx_rc_t
106 efx_ev_qcreate(
107         __in            efx_nic_t *enp,
108         __in            unsigned int index,
109         __in            efsys_mem_t *esmp,
110         __in            size_t n,
111         __in            uint32_t id,
112         __in            uint32_t us,
113         __in            uint32_t flags,
114         __deref_out     efx_evq_t **eepp)
115 {
116         const efx_ev_ops_t *eevop = enp->en_eevop;
117         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
118         efx_evq_t *eep;
119         efx_rc_t rc;
120
121         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
122         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV);
123
124         EFSYS_ASSERT3U(enp->en_ev_qcount + 1, <, encp->enc_evq_limit);
125
126         switch (flags & EFX_EVQ_FLAGS_NOTIFY_MASK) {
127         case EFX_EVQ_FLAGS_NOTIFY_INTERRUPT:
128                 break;
129         case EFX_EVQ_FLAGS_NOTIFY_DISABLED:
130                 if (us != 0) {
131                         rc = EINVAL;
132                         goto fail1;
133                 }
134                 break;
135         default:
136                 rc = EINVAL;
137                 goto fail2;
138         }
139
140         /* Allocate an EVQ object */
141         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_evq_t), eep);
142         if (eep == NULL) {
143                 rc = ENOMEM;
144                 goto fail3;
145         }
146
147         eep->ee_magic = EFX_EVQ_MAGIC;
148         eep->ee_enp = enp;
149         eep->ee_index = index;
150         eep->ee_mask = n - 1;
151         eep->ee_flags = flags;
152         eep->ee_esmp = esmp;
153
154         /*
155          * Set outputs before the queue is created because interrupts may be
156          * raised for events immediately after the queue is created, before the
157          * function call below returns. See bug58606.
158          *
159          * The eepp pointer passed in by the client must therefore point to data
160          * shared with the client's event processing context.
161          */
162         enp->en_ev_qcount++;
163         *eepp = eep;
164
165         if ((rc = eevop->eevo_qcreate(enp, index, esmp, n, id, us, flags,
166             eep)) != 0)
167                 goto fail4;
168
169         return (0);
170
171 fail4:
172         EFSYS_PROBE(fail4);
173
174         *eepp = NULL;
175         enp->en_ev_qcount--;
176         EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep);
177 fail3:
178         EFSYS_PROBE(fail3);
179 fail2:
180         EFSYS_PROBE(fail2);
181 fail1:
182         EFSYS_PROBE1(fail1, efx_rc_t, rc);
183         return (rc);
184 }
185
186                 void
187 efx_ev_qdestroy(
188         __in    efx_evq_t *eep)
189 {
190         efx_nic_t *enp = eep->ee_enp;
191         const efx_ev_ops_t *eevop = enp->en_eevop;
192
193         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
194
195         EFSYS_ASSERT(enp->en_ev_qcount != 0);
196         --enp->en_ev_qcount;
197
198         eevop->eevo_qdestroy(eep);
199
200         /* Free the EVQ object */
201         EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep);
202 }
203
204         __checkReturn   efx_rc_t
205 efx_ev_qprime(
206         __in            efx_evq_t *eep,
207         __in            unsigned int count)
208 {
209         efx_nic_t *enp = eep->ee_enp;
210         const efx_ev_ops_t *eevop = enp->en_eevop;
211         efx_rc_t rc;
212
213         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
214
215         if (!(enp->en_mod_flags & EFX_MOD_INTR)) {
216                 rc = EINVAL;
217                 goto fail1;
218         }
219
220         if ((rc = eevop->eevo_qprime(eep, count)) != 0)
221                 goto fail2;
222
223         return (0);
224
225 fail2:
226         EFSYS_PROBE(fail2);
227 fail1:
228         EFSYS_PROBE1(fail1, efx_rc_t, rc);
229         return (rc);
230 }
231
232         __checkReturn   boolean_t
233 efx_ev_qpending(
234         __in            efx_evq_t *eep,
235         __in            unsigned int count)
236 {
237         size_t offset;
238         efx_qword_t qword;
239
240         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
241
242         offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
243         EFSYS_MEM_READQ(eep->ee_esmp, offset, &qword);
244
245         return (EFX_EV_PRESENT(qword));
246 }
247
248 #define EFX_EV_BATCH    8
249
250                         void
251 efx_ev_qpoll(
252         __in            efx_evq_t *eep,
253         __inout         unsigned int *countp,
254         __in            const efx_ev_callbacks_t *eecp,
255         __in_opt        void *arg)
256 {
257         efx_qword_t ev[EFX_EV_BATCH];
258         unsigned int batch;
259         unsigned int total;
260         unsigned int count;
261         unsigned int index;
262         size_t offset;
263
264         /* Ensure events codes match for EF10 (Huntington/Medford) and Siena */
265         EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_LBN == FSF_AZ_EV_CODE_LBN);
266         EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_WIDTH == FSF_AZ_EV_CODE_WIDTH);
267
268         EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_RX_EV == FSE_AZ_EV_CODE_RX_EV);
269         EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_TX_EV == FSE_AZ_EV_CODE_TX_EV);
270         EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRIVER_EV == FSE_AZ_EV_CODE_DRIVER_EV);
271         EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRV_GEN_EV ==
272             FSE_AZ_EV_CODE_DRV_GEN_EV);
273 #if EFSYS_OPT_MCDI
274         EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_MCDI_EV ==
275             FSE_AZ_EV_CODE_MCDI_EVRESPONSE);
276 #endif
277
278         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
279         EFSYS_ASSERT(countp != NULL);
280         EFSYS_ASSERT(eecp != NULL);
281
282         count = *countp;
283         do {
284                 /* Read up until the end of the batch period */
285                 batch = EFX_EV_BATCH - (count & (EFX_EV_BATCH - 1));
286                 offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
287                 for (total = 0; total < batch; ++total) {
288                         EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total]));
289
290                         if (!EFX_EV_PRESENT(ev[total]))
291                                 break;
292
293                         EFSYS_PROBE3(event, unsigned int, eep->ee_index,
294                             uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1),
295                             uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0));
296
297                         offset += sizeof (efx_qword_t);
298                 }
299
300                 /* Process the batch of events */
301                 for (index = 0; index < total; ++index) {
302                         boolean_t should_abort;
303                         uint32_t code;
304
305                         EFX_EV_QSTAT_INCR(eep, EV_ALL);
306
307                         code = EFX_QWORD_FIELD(ev[index], FSF_AZ_EV_CODE);
308                         switch (code) {
309                         case FSE_AZ_EV_CODE_RX_EV:
310                                 should_abort = eep->ee_rx(eep,
311                                     &(ev[index]), eecp, arg);
312                                 break;
313                         case FSE_AZ_EV_CODE_TX_EV:
314                                 should_abort = eep->ee_tx(eep,
315                                     &(ev[index]), eecp, arg);
316                                 break;
317                         case FSE_AZ_EV_CODE_DRIVER_EV:
318                                 should_abort = eep->ee_driver(eep,
319                                     &(ev[index]), eecp, arg);
320                                 break;
321                         case FSE_AZ_EV_CODE_DRV_GEN_EV:
322                                 should_abort = eep->ee_drv_gen(eep,
323                                     &(ev[index]), eecp, arg);
324                                 break;
325 #if EFSYS_OPT_MCDI
326                         case FSE_AZ_EV_CODE_MCDI_EVRESPONSE:
327                                 should_abort = eep->ee_mcdi(eep,
328                                     &(ev[index]), eecp, arg);
329                                 break;
330 #endif
331                         case FSE_AZ_EV_CODE_GLOBAL_EV:
332                                 if (eep->ee_global) {
333                                         should_abort = eep->ee_global(eep,
334                                             &(ev[index]), eecp, arg);
335                                         break;
336                                 }
337                                 /* else fallthrough */
338                         default:
339                                 EFSYS_PROBE3(bad_event,
340                                     unsigned int, eep->ee_index,
341                                     uint32_t,
342                                     EFX_QWORD_FIELD(ev[index], EFX_DWORD_1),
343                                     uint32_t,
344                                     EFX_QWORD_FIELD(ev[index], EFX_DWORD_0));
345
346                                 EFSYS_ASSERT(eecp->eec_exception != NULL);
347                                 (void) eecp->eec_exception(arg,
348                                         EFX_EXCEPTION_EV_ERROR, code);
349                                 should_abort = B_TRUE;
350                         }
351                         if (should_abort) {
352                                 /* Ignore subsequent events */
353                                 total = index + 1;
354                                 break;
355                         }
356                 }
357
358                 /*
359                  * Now that the hardware has most likely moved onto dma'ing
360                  * into the next cache line, clear the processed events. Take
361                  * care to only clear out events that we've processed
362                  */
363                 EFX_SET_QWORD(ev[0]);
364                 offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
365                 for (index = 0; index < total; ++index) {
366                         EFSYS_MEM_WRITEQ(eep->ee_esmp, offset, &(ev[0]));
367                         offset += sizeof (efx_qword_t);
368                 }
369
370                 count += total;
371
372         } while (total == batch);
373
374         *countp = count;
375 }
376
377                         void
378 efx_ev_qpost(
379         __in    efx_evq_t *eep,
380         __in    uint16_t data)
381 {
382         efx_nic_t *enp = eep->ee_enp;
383         const efx_ev_ops_t *eevop = enp->en_eevop;
384
385         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
386
387         EFSYS_ASSERT(eevop != NULL &&
388             eevop->eevo_qpost != NULL);
389
390         eevop->eevo_qpost(eep, data);
391 }
392
393         __checkReturn   efx_rc_t
394 efx_ev_usecs_to_ticks(
395         __in            efx_nic_t *enp,
396         __in            unsigned int us,
397         __out           unsigned int *ticksp)
398 {
399         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
400         unsigned int ticks;
401
402         /* Convert microseconds to a timer tick count */
403         if (us == 0)
404                 ticks = 0;
405         else if (us * 1000 < encp->enc_evq_timer_quantum_ns)
406                 ticks = 1;      /* Never round down to zero */
407         else
408                 ticks = us * 1000 / encp->enc_evq_timer_quantum_ns;
409
410         *ticksp = ticks;
411         return (0);
412 }
413
414         __checkReturn   efx_rc_t
415 efx_ev_qmoderate(
416         __in            efx_evq_t *eep,
417         __in            unsigned int us)
418 {
419         efx_nic_t *enp = eep->ee_enp;
420         const efx_ev_ops_t *eevop = enp->en_eevop;
421         efx_rc_t rc;
422
423         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
424
425         if ((eep->ee_flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
426             EFX_EVQ_FLAGS_NOTIFY_DISABLED) {
427                 rc = EINVAL;
428                 goto fail1;
429         }
430
431         if ((rc = eevop->eevo_qmoderate(eep, us)) != 0)
432                 goto fail2;
433
434         return (0);
435
436 fail2:
437         EFSYS_PROBE(fail2);
438 fail1:
439         EFSYS_PROBE1(fail1, efx_rc_t, rc);
440         return (rc);
441 }
442