36e355f209679ad71fc16c2be8317832d6389403
[dpdk.git] / drivers / common / sfc_efx / base / rhead_ev.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2020 Xilinx, Inc.
4  * Copyright(c) 2018-2019 Solarflare Communications Inc.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10 #if EFSYS_OPT_RIVERHEAD
11
12 /*
13  * Non-interrupting event queue requires interrupting event queue to
14  * refer to for wake-up events even if wake ups are never used.
15  * It could be even non-allocated event queue.
16  */
17 #define EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX (0)
18
19
20         __checkReturn   efx_rc_t
21 rhead_ev_init(
22         __in            efx_nic_t *enp)
23 {
24         _NOTE(ARGUNUSED(enp))
25
26         return (0);
27 }
28
29                         void
30 rhead_ev_fini(
31         __in            efx_nic_t *enp)
32 {
33         _NOTE(ARGUNUSED(enp))
34 }
35
36         __checkReturn   efx_rc_t
37 rhead_ev_qcreate(
38         __in            efx_nic_t *enp,
39         __in            unsigned int index,
40         __in            efsys_mem_t *esmp,
41         __in            size_t ndescs,
42         __in            uint32_t id,
43         __in            uint32_t us,
44         __in            uint32_t flags,
45         __in            efx_evq_t *eep)
46 {
47         uint32_t irq;
48         efx_rc_t rc;
49
50         _NOTE(ARGUNUSED(id))    /* buftbl id managed by MC */
51
52         /* Set up the handler table */
53         eep->ee_rx      = NULL; /* FIXME */
54         eep->ee_tx      = NULL; /* FIXME */
55         eep->ee_driver  = NULL; /* FIXME */
56         eep->ee_drv_gen = NULL; /* FIXME */
57         eep->ee_mcdi    = NULL; /* FIXME */
58
59         /* Set up the event queue */
60         /* INIT_EVQ expects function-relative vector number */
61         if ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
62             EFX_EVQ_FLAGS_NOTIFY_INTERRUPT) {
63                 irq = index;
64         } else if (index == EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX) {
65                 irq = index;
66                 flags = (flags & ~EFX_EVQ_FLAGS_NOTIFY_MASK) |
67                     EFX_EVQ_FLAGS_NOTIFY_INTERRUPT;
68         } else {
69                 irq = EFX_RHEAD_ALWAYS_INTERRUPTING_EVQ_INDEX;
70         }
71
72         /*
73          * Interrupts may be raised for events immediately after the queue is
74          * created. See bug58606.
75          */
76         rc = efx_mcdi_init_evq(enp, index, esmp, ndescs, irq, us, flags,
77             B_FALSE);
78         if (rc != 0)
79                 goto fail1;
80
81         return (0);
82
83 fail1:
84         EFSYS_PROBE1(fail1, efx_rc_t, rc);
85
86         return (rc);
87 }
88
89                         void
90 rhead_ev_qdestroy(
91         __in            efx_evq_t *eep)
92 {
93         efx_nic_t *enp = eep->ee_enp;
94
95         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_RIVERHEAD);
96
97         (void) efx_mcdi_fini_evq(enp, eep->ee_index);
98 }
99
100         __checkReturn   efx_rc_t
101 rhead_ev_qprime(
102         __in            efx_evq_t *eep,
103         __in            unsigned int count)
104 {
105         efx_nic_t *enp = eep->ee_enp;
106         uint32_t rptr;
107         efx_dword_t dword;
108
109         rptr = count & eep->ee_mask;
110
111         EFX_POPULATE_DWORD_2(dword, ERF_GZ_EVQ_ID, eep->ee_index,
112             ERF_GZ_IDX, rptr);
113         /* EVQ_INT_PRIME lives function control window only on Riverhead */
114         EFX_BAR_WRITED(enp, ER_GZ_EVQ_INT_PRIME, &dword, B_FALSE);
115
116         return (0);
117 }
118
119                         void
120 rhead_ev_qpost(
121         __in    efx_evq_t *eep,
122         __in    uint16_t data)
123 {
124         _NOTE(ARGUNUSED(eep, data))
125
126         /* Not implemented yet */
127         EFSYS_ASSERT(B_FALSE);
128 }
129
130 /*
131  * Poll event queue in batches. Size of the batch is equal to cache line
132  * size divided by event size.
133  *
134  * Event queue is written by NIC and read by CPU. If CPU starts reading
135  * of events on the cache line, read all remaining events in a tight
136  * loop while event is present.
137  */
138 #define EF100_EV_BATCH  8
139
140 /*
141  * Check if event is present.
142  *
143  * Riverhead EvQs use a phase bit to indicate the presence of valid events,
144  * by flipping the phase bit on each wrap of the write index.
145  */
146 #define EF100_EV_PRESENT(_qword, _phase_bit)                            \
147         (EFX_QWORD_FIELD((_qword), ESF_GZ_EV_EVQ_PHASE) == _phase_bit)
148
149                         void
150 rhead_ev_qpoll(
151         __in            efx_evq_t *eep,
152         __inout         unsigned int *countp,
153         __in            const efx_ev_callbacks_t *eecp,
154         __in_opt        void *arg)
155 {
156         efx_qword_t ev[EF100_EV_BATCH];
157         unsigned int batch;
158         unsigned int phase_bit;
159         unsigned int total;
160         unsigned int count;
161         unsigned int index;
162         size_t offset;
163
164         EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
165         EFSYS_ASSERT(countp != NULL);
166         EFSYS_ASSERT(eecp != NULL);
167
168         count = *countp;
169         do {
170                 /* Read up until the end of the batch period */
171                 batch = EF100_EV_BATCH - (count & (EF100_EV_BATCH - 1));
172                 phase_bit = (count & (eep->ee_mask + 1)) != 0;
173                 offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
174                 for (total = 0; total < batch; ++total) {
175                         EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total]));
176
177                         if (!EF100_EV_PRESENT(ev[total], phase_bit))
178                                 break;
179
180                         EFSYS_PROBE3(event, unsigned int, eep->ee_index,
181                             uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1),
182                             uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0));
183
184                         offset += sizeof (efx_qword_t);
185                 }
186
187                 /* Process the batch of events */
188                 for (index = 0; index < total; ++index) {
189                         boolean_t should_abort;
190                         uint32_t code;
191
192                         EFX_EV_QSTAT_INCR(eep, EV_ALL);
193
194                         code = EFX_QWORD_FIELD(ev[index], ESF_GZ_E_TYPE);
195                         switch (code) {
196                         default:
197                                 EFSYS_PROBE3(bad_event,
198                                     unsigned int, eep->ee_index,
199                                     uint32_t,
200                                     EFX_QWORD_FIELD(ev[index], EFX_DWORD_1),
201                                     uint32_t,
202                                     EFX_QWORD_FIELD(ev[index], EFX_DWORD_0));
203
204                                 EFSYS_ASSERT(eecp->eec_exception != NULL);
205                                 (void) eecp->eec_exception(arg,
206                                         EFX_EXCEPTION_EV_ERROR, code);
207                                 should_abort = B_TRUE;
208                         }
209                         if (should_abort) {
210                                 /* Ignore subsequent events */
211                                 total = index + 1;
212
213                                 /*
214                                  * Poison batch to ensure the outer
215                                  * loop is broken out of.
216                                  */
217                                 EFSYS_ASSERT(batch <= EF100_EV_BATCH);
218                                 batch += (EF100_EV_BATCH << 1);
219                                 EFSYS_ASSERT(total != batch);
220                                 break;
221                         }
222                 }
223
224                 /*
225                  * There is no necessity to clear processed events since
226                  * phase bit which is flipping on each write index wrap
227                  * is used for event presence indication.
228                  */
229
230                 count += total;
231
232         } while (total == batch);
233
234         *countp = count;
235 }
236
237         __checkReturn   efx_rc_t
238 rhead_ev_qmoderate(
239         __in            efx_evq_t *eep,
240         __in            unsigned int us)
241 {
242         _NOTE(ARGUNUSED(eep, us))
243
244         return (ENOTSUP);
245 }
246
247
248 #if EFSYS_OPT_QSTATS
249                         void
250 rhead_ev_qstats_update(
251         __in                            efx_evq_t *eep,
252         __inout_ecount(EV_NQSTATS)      efsys_stat_t *stat)
253 {
254         unsigned int id;
255
256         for (id = 0; id < EV_NQSTATS; id++) {
257                 efsys_stat_t *essp = &stat[id];
258
259                 EFSYS_STAT_INCR(essp, eep->ee_stat[id]);
260                 eep->ee_stat[id] = 0;
261         }
262 }
263 #endif /* EFSYS_OPT_QSTATS */
264
265 #endif  /* EFSYS_OPT_RIVERHEAD */