net/sfc/base: import libefx base
[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
274         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
275         EFSYS_ASSERT(countp != NULL);
276         EFSYS_ASSERT(eecp != NULL);
277
278         count = *countp;
279         do {
280                 /* Read up until the end of the batch period */
281                 batch = EFX_EV_BATCH - (count & (EFX_EV_BATCH - 1));
282                 offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
283                 for (total = 0; total < batch; ++total) {
284                         EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total]));
285
286                         if (!EFX_EV_PRESENT(ev[total]))
287                                 break;
288
289                         EFSYS_PROBE3(event, unsigned int, eep->ee_index,
290                             uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1),
291                             uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0));
292
293                         offset += sizeof (efx_qword_t);
294                 }
295
296                 /* Process the batch of events */
297                 for (index = 0; index < total; ++index) {
298                         boolean_t should_abort;
299                         uint32_t code;
300
301                         EFX_EV_QSTAT_INCR(eep, EV_ALL);
302
303                         code = EFX_QWORD_FIELD(ev[index], FSF_AZ_EV_CODE);
304                         switch (code) {
305                         case FSE_AZ_EV_CODE_RX_EV:
306                                 should_abort = eep->ee_rx(eep,
307                                     &(ev[index]), eecp, arg);
308                                 break;
309                         case FSE_AZ_EV_CODE_TX_EV:
310                                 should_abort = eep->ee_tx(eep,
311                                     &(ev[index]), eecp, arg);
312                                 break;
313                         case FSE_AZ_EV_CODE_DRIVER_EV:
314                                 should_abort = eep->ee_driver(eep,
315                                     &(ev[index]), eecp, arg);
316                                 break;
317                         case FSE_AZ_EV_CODE_DRV_GEN_EV:
318                                 should_abort = eep->ee_drv_gen(eep,
319                                     &(ev[index]), eecp, arg);
320                                 break;
321                         case FSE_AZ_EV_CODE_GLOBAL_EV:
322                                 if (eep->ee_global) {
323                                         should_abort = eep->ee_global(eep,
324                                             &(ev[index]), eecp, arg);
325                                         break;
326                                 }
327                                 /* else fallthrough */
328                         default:
329                                 EFSYS_PROBE3(bad_event,
330                                     unsigned int, eep->ee_index,
331                                     uint32_t,
332                                     EFX_QWORD_FIELD(ev[index], EFX_DWORD_1),
333                                     uint32_t,
334                                     EFX_QWORD_FIELD(ev[index], EFX_DWORD_0));
335
336                                 EFSYS_ASSERT(eecp->eec_exception != NULL);
337                                 (void) eecp->eec_exception(arg,
338                                         EFX_EXCEPTION_EV_ERROR, code);
339                                 should_abort = B_TRUE;
340                         }
341                         if (should_abort) {
342                                 /* Ignore subsequent events */
343                                 total = index + 1;
344                                 break;
345                         }
346                 }
347
348                 /*
349                  * Now that the hardware has most likely moved onto dma'ing
350                  * into the next cache line, clear the processed events. Take
351                  * care to only clear out events that we've processed
352                  */
353                 EFX_SET_QWORD(ev[0]);
354                 offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
355                 for (index = 0; index < total; ++index) {
356                         EFSYS_MEM_WRITEQ(eep->ee_esmp, offset, &(ev[0]));
357                         offset += sizeof (efx_qword_t);
358                 }
359
360                 count += total;
361
362         } while (total == batch);
363
364         *countp = count;
365 }
366
367                         void
368 efx_ev_qpost(
369         __in    efx_evq_t *eep,
370         __in    uint16_t data)
371 {
372         efx_nic_t *enp = eep->ee_enp;
373         const efx_ev_ops_t *eevop = enp->en_eevop;
374
375         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
376
377         EFSYS_ASSERT(eevop != NULL &&
378             eevop->eevo_qpost != NULL);
379
380         eevop->eevo_qpost(eep, data);
381 }
382
383         __checkReturn   efx_rc_t
384 efx_ev_usecs_to_ticks(
385         __in            efx_nic_t *enp,
386         __in            unsigned int us,
387         __out           unsigned int *ticksp)
388 {
389         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
390         unsigned int ticks;
391
392         /* Convert microseconds to a timer tick count */
393         if (us == 0)
394                 ticks = 0;
395         else if (us * 1000 < encp->enc_evq_timer_quantum_ns)
396                 ticks = 1;      /* Never round down to zero */
397         else
398                 ticks = us * 1000 / encp->enc_evq_timer_quantum_ns;
399
400         *ticksp = ticks;
401         return (0);
402 }
403
404         __checkReturn   efx_rc_t
405 efx_ev_qmoderate(
406         __in            efx_evq_t *eep,
407         __in            unsigned int us)
408 {
409         efx_nic_t *enp = eep->ee_enp;
410         const efx_ev_ops_t *eevop = enp->en_eevop;
411         efx_rc_t rc;
412
413         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
414
415         if ((eep->ee_flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
416             EFX_EVQ_FLAGS_NOTIFY_DISABLED) {
417                 rc = EINVAL;
418                 goto fail1;
419         }
420
421         if ((rc = eevop->eevo_qmoderate(eep, us)) != 0)
422                 goto fail2;
423
424         return (0);
425
426 fail2:
427         EFSYS_PROBE(fail2);
428 fail1:
429         EFSYS_PROBE1(fail1, efx_rc_t, rc);
430         return (rc);
431 }
432