]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/efx_tx.c
MFV ntp 4.2.8p2 (r281348)
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / efx_tx.c
1 /*-
2  * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "efsys.h"
30 #include "efx.h"
31 #include "efx_types.h"
32 #include "efx_regs.h"
33 #include "efx_impl.h"
34
35 #if EFSYS_OPT_QSTATS
36 #define EFX_TX_QSTAT_INCR(_etp, _stat)                                  \
37         do {                                                            \
38                 (_etp)->et_stat[_stat]++;                               \
39         _NOTE(CONSTANTCONDITION)                                        \
40         } while (B_FALSE)
41 #else
42 #define EFX_TX_QSTAT_INCR(_etp, _stat)
43 #endif
44
45         __checkReturn   int
46 efx_tx_init(
47         __in            efx_nic_t *enp)
48 {
49         efx_oword_t oword;
50         int rc;
51
52         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
53         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
54
55         if (!(enp->en_mod_flags & EFX_MOD_EV)) {
56                 rc = EINVAL;
57                 goto fail1;
58         }
59
60         if (enp->en_mod_flags & EFX_MOD_TX) {
61                 rc = EINVAL;
62                 goto fail2;
63         }
64
65         EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
66
67         /*
68          * Disable the timer-based TX DMA backoff and allow TX DMA to be
69          * controlled by the RX FIFO fill level (although always allow a
70          * minimal trickle).
71          */
72         EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword);
73         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe);
74         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1);
75         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
76         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0);
77         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1);
78         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2);
79         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
80
81         /*
82          * Filter all packets less than 14 bytes to avoid parsing
83          * errors.
84          */
85         EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
86         EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword);
87
88         /*
89          * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16
90          * descriptors (which is bad).
91          */
92         EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
93         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
94         EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
95
96         enp->en_mod_flags |= EFX_MOD_TX;
97         return (0);
98
99 fail2:
100         EFSYS_PROBE(fail2);
101 fail1:
102         EFSYS_PROBE1(fail1, int, rc);
103
104         return (rc);
105 }
106
107 #if EFSYS_OPT_FILTER
108 extern  __checkReturn   int
109 efx_tx_filter_insert(
110         __in            efx_txq_t *etp,
111         __inout         efx_filter_spec_t *spec)
112 {
113         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
114         EFSYS_ASSERT3P(spec, !=, NULL);
115
116         spec->efs_dmaq_id = (uint16_t)etp->et_index;
117         return (efx_filter_insert_filter(etp->et_enp, spec, B_FALSE));
118 }
119 #endif
120
121 #if EFSYS_OPT_FILTER
122 extern  __checkReturn   int
123 efx_tx_filter_remove(
124         __in            efx_txq_t *etp,
125         __inout         efx_filter_spec_t *spec)
126 {
127         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
128         EFSYS_ASSERT3P(spec, !=, NULL);
129
130         spec->efs_dmaq_id = (uint16_t)etp->et_index;
131         return (efx_filter_remove_filter(etp->et_enp, spec));
132 }
133 #endif
134
135 #define EFX_TX_DESC(_etp, _addr, _size, _eop, _added)                   \
136         do {                                                            \
137                 unsigned int id;                                        \
138                 size_t offset;                                          \
139                 efx_qword_t qword;                                      \
140                                                                         \
141                 id = (_added)++ & (_etp)->et_mask;                      \
142                 offset = id * sizeof (efx_qword_t);                     \
143                                                                         \
144                 EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index,   \
145                     unsigned int, id, efsys_dma_addr_t, (_addr),        \
146                     size_t, (_size), boolean_t, (_eop));                \
147                                                                         \
148                 EFX_POPULATE_QWORD_4(qword,                             \
149                     FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1,                 \
150                     FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size),        \
151                     FSF_AZ_TX_KER_BUF_ADDR_DW0,                         \
152                     (uint32_t)((_addr) & 0xffffffff),                   \
153                     FSF_AZ_TX_KER_BUF_ADDR_DW1,                         \
154                     (uint32_t)((_addr) >> 32));                         \
155                 EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword);      \
156                                                                         \
157                 _NOTE(CONSTANTCONDITION)                                \
158         } while (B_FALSE)
159
160         __checkReturn   int
161 efx_tx_qpost(
162         __in            efx_txq_t *etp,
163         __in_ecount(n)  efx_buffer_t *eb,
164         __in            unsigned int n,
165         __in            unsigned int completed,
166         __inout         unsigned int *addedp)
167 {
168         unsigned int added = *addedp;
169         unsigned int i;
170         int rc = ENOSPC;
171
172         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
173
174         if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1))
175                 goto fail1;
176
177         for (i = 0; i < n; i++) {
178                 efx_buffer_t *ebp = &eb[i];
179                 efsys_dma_addr_t start = ebp->eb_addr;
180                 size_t size = ebp->eb_size;
181                 efsys_dma_addr_t end = start + size;
182
183                 /* Fragments must not span 4k boundaries. */
184                 EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end);
185
186                 EFX_TX_DESC(etp, start, size, ebp->eb_eop, added);
187         }
188
189         EFX_TX_QSTAT_INCR(etp, TX_POST);
190
191         *addedp = added;
192         return (0);
193
194 fail1:
195         EFSYS_PROBE1(fail1, int, rc);
196
197         return (rc);
198 }
199
200                 void
201 efx_tx_qpush(
202         __in    efx_txq_t *etp,
203         __in    unsigned int added)
204 {
205         efx_nic_t *enp = etp->et_enp;
206         uint32_t wptr;
207         efx_dword_t dword;
208         efx_oword_t oword;
209
210         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
211
212         /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
213         EFSYS_PIO_WRITE_BARRIER();
214
215         /* Push the populated descriptors out */
216         wptr = added & etp->et_mask;
217
218         EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr);
219
220         /* Only write the third DWORD */
221         EFX_POPULATE_DWORD_1(dword,
222             EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
223         EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0,
224                             etp->et_index, &dword, B_FALSE);
225 }
226
227 #define EFX_MAX_PACE_VALUE 20
228 #define EFX_TX_PACE_CLOCK_BASE  104
229
230         __checkReturn   int
231 efx_tx_qpace(
232         __in            efx_txq_t *etp,
233         __in            unsigned int ns)
234 {
235         efx_nic_t *enp = etp->et_enp;
236         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
237         efx_oword_t oword;
238         unsigned int pace_val;
239         unsigned int timer_period;
240         int rc;
241
242         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
243
244         if (ns == 0) {
245                 pace_val = 0;
246         } else {
247                 /*
248                  * The pace_val to write into the table is s.t
249                  * ns <= timer_period * (2 ^ pace_val)
250                  */
251                 timer_period = EFX_TX_PACE_CLOCK_BASE / encp->enc_clk_mult;
252                 for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) {
253                         if ((timer_period << pace_val) >= ns)
254                                 break;
255                 }
256         }
257         if (pace_val > EFX_MAX_PACE_VALUE) {
258                 rc = EINVAL;
259                 goto fail1;
260         }
261
262         /* Update the pacing table */
263         EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val);
264         EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index, &oword);
265
266         return (0);
267
268 fail1:
269         EFSYS_PROBE1(fail1, int, rc);
270
271         return (rc);
272 }
273
274                 void
275 efx_tx_qflush(
276         __in    efx_txq_t *etp)
277 {
278         efx_nic_t *enp = etp->et_enp;
279         efx_oword_t oword;
280         uint32_t label;
281
282         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
283
284         efx_tx_qpace(etp, 0);
285
286         label = etp->et_index;
287
288         /* Flush the queue */
289         EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
290             FRF_AZ_TX_FLUSH_DESCQ, label);
291         EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword);
292 }
293
294                 void
295 efx_tx_qenable(
296         __in    efx_txq_t *etp)
297 {
298         efx_nic_t *enp = etp->et_enp;
299         efx_oword_t oword;
300
301         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
302
303         EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL,
304                             etp->et_index, &oword);
305
306         EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index,
307             uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3),
308             uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2),
309             uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1),
310             uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0));
311
312         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0);
313         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0);
314         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1);
315
316         EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
317                             etp->et_index, &oword);
318 }
319
320         __checkReturn   int
321 efx_tx_qcreate(
322         __in            efx_nic_t *enp,
323         __in            unsigned int index,
324         __in            unsigned int label,
325         __in            efsys_mem_t *esmp,
326         __in            size_t n,
327         __in            uint32_t id,
328         __in            uint16_t flags,
329         __in            efx_evq_t *eep,
330         __deref_out     efx_txq_t **etpp)
331 {
332         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
333         efx_txq_t *etp;
334         efx_oword_t oword;
335         uint32_t size;
336         int rc;
337
338         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
339         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
340
341         EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS ==
342             (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH));
343         EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS);
344         EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <, encp->enc_txq_limit);
345
346         if (!ISP2(n) || !(n & EFX_TXQ_NDESCS_MASK)) {
347                 rc = EINVAL;
348                 goto fail1;
349         }
350         if (index >= encp->enc_txq_limit) {
351                 rc = EINVAL;
352                 goto fail2;
353         }
354         for (size = 0; (1 << size) <= (EFX_TXQ_MAXNDESCS / EFX_TXQ_MINNDESCS);
355             size++)
356                 if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS))
357                         break;
358         if (id + (1 << size) >= encp->enc_buftbl_limit) {
359                 rc = EINVAL;
360                 goto fail3;
361         }
362
363         /* Allocate an TXQ object */
364         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp);
365
366         if (etp == NULL) {
367                 rc = ENOMEM;
368                 goto fail4;
369         }
370
371         etp->et_magic = EFX_TXQ_MAGIC;
372         etp->et_enp = enp;
373         etp->et_index = index;
374         etp->et_mask = n - 1;
375         etp->et_esmp = esmp;
376
377         /* Set up the new descriptor queue */
378         EFX_POPULATE_OWORD_6(oword,
379             FRF_AZ_TX_DESCQ_BUF_BASE_ID, id,
380             FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index,
381             FRF_AZ_TX_DESCQ_OWNER_ID, 0,
382             FRF_AZ_TX_DESCQ_LABEL, label,
383             FRF_AZ_TX_DESCQ_SIZE, size,
384             FRF_AZ_TX_DESCQ_TYPE, 0);
385
386         EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1);
387         EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS,
388             (flags & EFX_CKSUM_IPV4) ? 0 : 1);
389         EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS,
390             (flags & EFX_CKSUM_TCPUDP) ? 0 : 1);
391
392         EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
393             etp->et_index, &oword);
394
395         enp->en_tx_qcount++;
396         *etpp = etp;
397         return (0);
398
399 fail4:
400         EFSYS_PROBE(fail4);
401 fail3:
402         EFSYS_PROBE(fail3);
403 fail2:
404         EFSYS_PROBE(fail2);
405 fail1:
406         EFSYS_PROBE1(fail1, int, rc);
407
408         return (rc);
409 }
410
411 #if EFSYS_OPT_QSTATS
412 #if EFSYS_OPT_NAMES
413 /* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 78ca9ab00287fffb */
414 static const char       __cs * __cs __efx_tx_qstat_name[] = {
415         "post",
416         "unaligned_split",
417 };
418 /* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */
419
420                 const char __cs *
421 efx_tx_qstat_name(
422         __in    efx_nic_t *enp,
423         __in    unsigned int id)
424 {
425         _NOTE(ARGUNUSED(enp))
426         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
427         EFSYS_ASSERT3U(id, <, TX_NQSTATS);
428
429         return (__efx_tx_qstat_name[id]);
430 }
431 #endif  /* EFSYS_OPT_NAMES */
432 #endif  /* EFSYS_OPT_QSTATS */
433
434 #if EFSYS_OPT_QSTATS
435                                         void
436 efx_tx_qstats_update(
437         __in                            efx_txq_t *etp,
438         __inout_ecount(TX_NQSTATS)      efsys_stat_t *stat)
439 {
440         unsigned int id;
441
442         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
443
444         for (id = 0; id < TX_NQSTATS; id++) {
445                 efsys_stat_t *essp = &stat[id];
446
447                 EFSYS_STAT_INCR(essp, etp->et_stat[id]);
448                 etp->et_stat[id] = 0;
449         }
450 }
451 #endif  /* EFSYS_OPT_QSTATS */
452
453                 void
454 efx_tx_qdestroy(
455         __in    efx_txq_t *etp)
456 {
457         efx_nic_t *enp = etp->et_enp;
458         efx_oword_t oword;
459
460         EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC);
461
462         EFSYS_ASSERT(enp->en_tx_qcount != 0);
463         --enp->en_tx_qcount;
464
465         /* Purge descriptor queue */
466         EFX_ZERO_OWORD(oword);
467
468         EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL,
469                             etp->et_index, &oword);
470
471         /* Free the TXQ object */
472         EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp);
473 }
474
475                 void
476 efx_tx_fini(
477         __in    efx_nic_t *enp)
478 {
479         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
480         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
481         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX);
482         EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0);
483
484         enp->en_mod_flags &= ~EFX_MOD_TX;
485 }