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