net/sfc/base: support more RSS hash configurations
[dpdk.git] / drivers / net / sfc / base / ef10_rx.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright (c) 2012-2018 Solarflare Communications Inc.
4  * All rights reserved.
5  */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10
11 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
12
13
14 static  __checkReturn   efx_rc_t
15 efx_mcdi_init_rxq(
16         __in            efx_nic_t *enp,
17         __in            uint32_t ndescs,
18         __in            uint32_t target_evq,
19         __in            uint32_t label,
20         __in            uint32_t instance,
21         __in            efsys_mem_t *esmp,
22         __in            boolean_t disable_scatter,
23         __in            boolean_t want_inner_classes,
24         __in            uint32_t ps_bufsize)
25 {
26         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
27         efx_mcdi_req_t req;
28         uint8_t payload[MAX(MC_CMD_INIT_RXQ_EXT_IN_LEN,
29                             MC_CMD_INIT_RXQ_EXT_OUT_LEN)];
30         int npages = EFX_RXQ_NBUFS(ndescs);
31         int i;
32         efx_qword_t *dma_addr;
33         uint64_t addr;
34         efx_rc_t rc;
35         uint32_t dma_mode;
36         boolean_t want_outer_classes;
37
38         EFSYS_ASSERT3U(ndescs, <=, EFX_RXQ_MAXNDESCS);
39
40         if ((esmp == NULL) || (EFSYS_MEM_SIZE(esmp) < EFX_RXQ_SIZE(ndescs))) {
41                 rc = EINVAL;
42                 goto fail1;
43         }
44
45         if (ps_bufsize > 0)
46                 dma_mode = MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM;
47         else
48                 dma_mode = MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET;
49
50         if (encp->enc_tunnel_encapsulations_supported != 0 &&
51             !want_inner_classes) {
52                 /*
53                  * WANT_OUTER_CLASSES can only be specified on hardware which
54                  * supports tunnel encapsulation offloads, even though it is
55                  * effectively the behaviour the hardware gives.
56                  *
57                  * Also, on hardware which does support such offloads, older
58                  * firmware rejects the flag if the offloads are not supported
59                  * by the current firmware variant, which means this may fail if
60                  * the capabilities are not updated when the firmware variant
61                  * changes. This is not an issue on newer firmware, as it was
62                  * changed in bug 69842 (v6.4.2.1007) to permit this flag to be
63                  * specified on all firmware variants.
64                  */
65                 want_outer_classes = B_TRUE;
66         } else {
67                 want_outer_classes = B_FALSE;
68         }
69
70         (void) memset(payload, 0, sizeof (payload));
71         req.emr_cmd = MC_CMD_INIT_RXQ;
72         req.emr_in_buf = payload;
73         req.emr_in_length = MC_CMD_INIT_RXQ_EXT_IN_LEN;
74         req.emr_out_buf = payload;
75         req.emr_out_length = MC_CMD_INIT_RXQ_EXT_OUT_LEN;
76
77         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs);
78         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, target_evq);
79         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_LABEL, label);
80         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_INSTANCE, instance);
81         MCDI_IN_POPULATE_DWORD_9(req, INIT_RXQ_EXT_IN_FLAGS,
82             INIT_RXQ_EXT_IN_FLAG_BUFF_MODE, 0,
83             INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT, 0,
84             INIT_RXQ_EXT_IN_FLAG_TIMESTAMP, 0,
85             INIT_RXQ_EXT_IN_CRC_MODE, 0,
86             INIT_RXQ_EXT_IN_FLAG_PREFIX, 1,
87             INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER, disable_scatter,
88             INIT_RXQ_EXT_IN_DMA_MODE,
89             dma_mode,
90             INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE, ps_bufsize,
91             INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES, want_outer_classes);
92         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_OWNER_ID, 0);
93         MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
94
95         dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
96         addr = EFSYS_MEM_ADDR(esmp);
97
98         for (i = 0; i < npages; i++) {
99                 EFX_POPULATE_QWORD_2(*dma_addr,
100                     EFX_DWORD_1, (uint32_t)(addr >> 32),
101                     EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
102
103                 dma_addr++;
104                 addr += EFX_BUF_SIZE;
105         }
106
107         efx_mcdi_execute(enp, &req);
108
109         if (req.emr_rc != 0) {
110                 rc = req.emr_rc;
111                 goto fail2;
112         }
113
114         return (0);
115
116 fail2:
117         EFSYS_PROBE(fail2);
118 fail1:
119         EFSYS_PROBE1(fail1, efx_rc_t, rc);
120
121         return (rc);
122 }
123
124 static  __checkReturn   efx_rc_t
125 efx_mcdi_fini_rxq(
126         __in            efx_nic_t *enp,
127         __in            uint32_t instance)
128 {
129         efx_mcdi_req_t req;
130         uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
131                             MC_CMD_FINI_RXQ_OUT_LEN)];
132         efx_rc_t rc;
133
134         (void) memset(payload, 0, sizeof (payload));
135         req.emr_cmd = MC_CMD_FINI_RXQ;
136         req.emr_in_buf = payload;
137         req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
138         req.emr_out_buf = payload;
139         req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
140
141         MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
142
143         efx_mcdi_execute_quiet(enp, &req);
144
145         if (req.emr_rc != 0) {
146                 rc = req.emr_rc;
147                 goto fail1;
148         }
149
150         return (0);
151
152 fail1:
153         /*
154          * EALREADY is not an error, but indicates that the MC has rebooted and
155          * that the RXQ has already been destroyed.
156          */
157         if (rc != EALREADY)
158                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
159
160         return (rc);
161 }
162
163 #if EFSYS_OPT_RX_SCALE
164 static  __checkReturn   efx_rc_t
165 efx_mcdi_rss_context_alloc(
166         __in            efx_nic_t *enp,
167         __in            efx_rx_scale_context_type_t type,
168         __in            uint32_t num_queues,
169         __out           uint32_t *rss_contextp)
170 {
171         efx_mcdi_req_t req;
172         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
173                             MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
174         uint32_t rss_context;
175         uint32_t context_type;
176         efx_rc_t rc;
177
178         if (num_queues > EFX_MAXRSS) {
179                 rc = EINVAL;
180                 goto fail1;
181         }
182
183         switch (type) {
184         case EFX_RX_SCALE_EXCLUSIVE:
185                 context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE;
186                 break;
187         case EFX_RX_SCALE_SHARED:
188                 context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED;
189                 break;
190         default:
191                 rc = EINVAL;
192                 goto fail2;
193         }
194
195         (void) memset(payload, 0, sizeof (payload));
196         req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
197         req.emr_in_buf = payload;
198         req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
199         req.emr_out_buf = payload;
200         req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
201
202         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
203             EVB_PORT_ID_ASSIGNED);
204         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type);
205
206         /*
207          * For exclusive contexts, NUM_QUEUES is only used to validate
208          * indirection table offsets.
209          * For shared contexts, the provided context will spread traffic over
210          * NUM_QUEUES many queues.
211          */
212         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues);
213
214         efx_mcdi_execute(enp, &req);
215
216         if (req.emr_rc != 0) {
217                 rc = req.emr_rc;
218                 goto fail3;
219         }
220
221         if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
222                 rc = EMSGSIZE;
223                 goto fail4;
224         }
225
226         rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
227         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
228                 rc = ENOENT;
229                 goto fail5;
230         }
231
232         *rss_contextp = rss_context;
233
234         return (0);
235
236 fail5:
237         EFSYS_PROBE(fail5);
238 fail4:
239         EFSYS_PROBE(fail4);
240 fail3:
241         EFSYS_PROBE(fail3);
242 fail2:
243         EFSYS_PROBE(fail2);
244 fail1:
245         EFSYS_PROBE1(fail1, efx_rc_t, rc);
246
247         return (rc);
248 }
249 #endif /* EFSYS_OPT_RX_SCALE */
250
251 #if EFSYS_OPT_RX_SCALE
252 static                  efx_rc_t
253 efx_mcdi_rss_context_free(
254         __in            efx_nic_t *enp,
255         __in            uint32_t rss_context)
256 {
257         efx_mcdi_req_t req;
258         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
259                             MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
260         efx_rc_t rc;
261
262         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
263                 rc = EINVAL;
264                 goto fail1;
265         }
266
267         (void) memset(payload, 0, sizeof (payload));
268         req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
269         req.emr_in_buf = payload;
270         req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
271         req.emr_out_buf = payload;
272         req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
273
274         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
275
276         efx_mcdi_execute_quiet(enp, &req);
277
278         if (req.emr_rc != 0) {
279                 rc = req.emr_rc;
280                 goto fail2;
281         }
282
283         return (0);
284
285 fail2:
286         EFSYS_PROBE(fail2);
287 fail1:
288         EFSYS_PROBE1(fail1, efx_rc_t, rc);
289
290         return (rc);
291 }
292 #endif /* EFSYS_OPT_RX_SCALE */
293
294 #if EFSYS_OPT_RX_SCALE
295 static                  efx_rc_t
296 efx_mcdi_rss_context_set_flags(
297         __in            efx_nic_t *enp,
298         __in            uint32_t rss_context,
299         __in            efx_rx_hash_type_t type)
300 {
301         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
302         efx_rx_hash_type_t type_ipv4;
303         efx_rx_hash_type_t type_ipv4_tcp;
304         efx_rx_hash_type_t type_ipv6;
305         efx_rx_hash_type_t type_ipv6_tcp;
306         efx_rx_hash_type_t modes;
307         efx_mcdi_req_t req;
308         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
309                             MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
310         efx_rc_t rc;
311
312         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_TCP_LBN ==
313                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_LBN);
314         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_TCP_WIDTH ==
315                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_WIDTH);
316         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_LBN ==
317                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_LBN);
318         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV4_WIDTH ==
319                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_WIDTH);
320         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_TCP_LBN ==
321                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_LBN);
322         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_TCP_WIDTH ==
323                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_WIDTH);
324         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_LBN ==
325                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_LBN);
326         EFX_STATIC_ASSERT(EFX_RX_CLASS_IPV6_WIDTH ==
327                     MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_WIDTH);
328
329         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
330                 rc = EINVAL;
331                 goto fail1;
332         }
333
334         (void) memset(payload, 0, sizeof (payload));
335         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
336         req.emr_in_buf = payload;
337         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
338         req.emr_out_buf = payload;
339         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
340
341         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
342             rss_context);
343
344         type_ipv4 = EFX_RX_HASH(IPV4, 2TUPLE) | EFX_RX_HASH(IPV4_TCP, 2TUPLE) |
345                     EFX_RX_HASH(IPV4_UDP, 2TUPLE);
346         type_ipv4_tcp = EFX_RX_HASH(IPV4_TCP, 4TUPLE);
347         type_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE) | EFX_RX_HASH(IPV6_TCP, 2TUPLE) |
348                     EFX_RX_HASH(IPV6_UDP, 2TUPLE);
349         type_ipv6_tcp = EFX_RX_HASH(IPV6_TCP, 4TUPLE);
350
351         /*
352          * Create a copy of the original hash type.
353          * The copy will be used to fill in RSS_MODE bits and
354          * may be cleared beforehand. The original variable
355          * and, thus, EN bits will remain unaffected.
356          */
357         modes = type;
358
359         /*
360          * If the firmware lacks support for additional modes, RSS_MODE
361          * fields must contain zeros, otherwise the operation will fail.
362          */
363         if (encp->enc_rx_scale_additional_modes_supported == B_FALSE)
364                 modes = 0;
365
366 #define EXTRACT_RSS_MODE(_type, _class)         \
367         (EFX_EXTRACT_NATIVE(_type, 0, 31,       \
368         EFX_LOW_BIT(EFX_RX_CLASS_##_class),     \
369         EFX_HIGH_BIT(EFX_RX_CLASS_##_class)) &  \
370         EFX_MASK32(EFX_RX_CLASS_##_class))
371
372         MCDI_IN_POPULATE_DWORD_10(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
373             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
374             ((type & type_ipv4) == type_ipv4) ? 1 : 0,
375             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
376             ((type & type_ipv4_tcp) == type_ipv4_tcp) ? 1 : 0,
377             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
378             ((type & type_ipv6) == type_ipv6) ? 1 : 0,
379             RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
380             ((type & type_ipv6_tcp) == type_ipv6_tcp) ? 1 : 0,
381             RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE,
382             EXTRACT_RSS_MODE(modes, IPV4_TCP),
383             RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV4_RSS_MODE,
384             EXTRACT_RSS_MODE(modes, IPV4_UDP),
385             RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE,
386             EXTRACT_RSS_MODE(modes, IPV4),
387             RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE,
388             EXTRACT_RSS_MODE(modes, IPV6_TCP),
389             RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV6_RSS_MODE,
390             EXTRACT_RSS_MODE(modes, IPV6_UDP),
391             RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE,
392             EXTRACT_RSS_MODE(modes, IPV6));
393
394 #undef EXTRACT_RSS_MODE
395
396         efx_mcdi_execute(enp, &req);
397
398         if (req.emr_rc != 0) {
399                 rc = req.emr_rc;
400                 goto fail2;
401         }
402
403         return (0);
404
405 fail2:
406         EFSYS_PROBE(fail2);
407 fail1:
408         EFSYS_PROBE1(fail1, efx_rc_t, rc);
409
410         return (rc);
411 }
412 #endif /* EFSYS_OPT_RX_SCALE */
413
414 #if EFSYS_OPT_RX_SCALE
415 static                  efx_rc_t
416 efx_mcdi_rss_context_set_key(
417         __in            efx_nic_t *enp,
418         __in            uint32_t rss_context,
419         __in_ecount(n)  uint8_t *key,
420         __in            size_t n)
421 {
422         efx_mcdi_req_t req;
423         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
424                             MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
425         efx_rc_t rc;
426
427         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
428                 rc = EINVAL;
429                 goto fail1;
430         }
431
432         (void) memset(payload, 0, sizeof (payload));
433         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
434         req.emr_in_buf = payload;
435         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
436         req.emr_out_buf = payload;
437         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
438
439         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
440             rss_context);
441
442         EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
443         if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
444                 rc = EINVAL;
445                 goto fail2;
446         }
447
448         memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
449             key, n);
450
451         efx_mcdi_execute(enp, &req);
452
453         if (req.emr_rc != 0) {
454                 rc = req.emr_rc;
455                 goto fail3;
456         }
457
458         return (0);
459
460 fail3:
461         EFSYS_PROBE(fail3);
462 fail2:
463         EFSYS_PROBE(fail2);
464 fail1:
465         EFSYS_PROBE1(fail1, efx_rc_t, rc);
466
467         return (rc);
468 }
469 #endif /* EFSYS_OPT_RX_SCALE */
470
471 #if EFSYS_OPT_RX_SCALE
472 static                  efx_rc_t
473 efx_mcdi_rss_context_set_table(
474         __in            efx_nic_t *enp,
475         __in            uint32_t rss_context,
476         __in_ecount(n)  unsigned int *table,
477         __in            size_t n)
478 {
479         efx_mcdi_req_t req;
480         uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
481                             MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
482         uint8_t *req_table;
483         int i, rc;
484
485         if (rss_context == EF10_RSS_CONTEXT_INVALID) {
486                 rc = EINVAL;
487                 goto fail1;
488         }
489
490         (void) memset(payload, 0, sizeof (payload));
491         req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
492         req.emr_in_buf = payload;
493         req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
494         req.emr_out_buf = payload;
495         req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
496
497         MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
498             rss_context);
499
500         req_table =
501             MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
502
503         for (i = 0;
504             i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
505             i++) {
506                 req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
507         }
508
509         efx_mcdi_execute(enp, &req);
510
511         if (req.emr_rc != 0) {
512                 rc = req.emr_rc;
513                 goto fail2;
514         }
515
516         return (0);
517
518 fail2:
519         EFSYS_PROBE(fail2);
520 fail1:
521         EFSYS_PROBE1(fail1, efx_rc_t, rc);
522
523         return (rc);
524 }
525 #endif /* EFSYS_OPT_RX_SCALE */
526
527
528         __checkReturn   efx_rc_t
529 ef10_rx_init(
530         __in            efx_nic_t *enp)
531 {
532 #if EFSYS_OPT_RX_SCALE
533
534         if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS,
535                 &enp->en_rss_context) == 0) {
536                 /*
537                  * Allocated an exclusive RSS context, which allows both the
538                  * indirection table and key to be modified.
539                  */
540                 enp->en_rss_context_type = EFX_RX_SCALE_EXCLUSIVE;
541                 enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
542         } else {
543                 /*
544                  * Failed to allocate an exclusive RSS context. Continue
545                  * operation without support for RSS. The pseudo-header in
546                  * received packets will not contain a Toeplitz hash value.
547                  */
548                 enp->en_rss_context_type = EFX_RX_SCALE_UNAVAILABLE;
549                 enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
550         }
551
552 #endif /* EFSYS_OPT_RX_SCALE */
553
554         return (0);
555 }
556
557 #if EFSYS_OPT_RX_SCATTER
558         __checkReturn   efx_rc_t
559 ef10_rx_scatter_enable(
560         __in            efx_nic_t *enp,
561         __in            unsigned int buf_size)
562 {
563         _NOTE(ARGUNUSED(enp, buf_size))
564         return (0);
565 }
566 #endif  /* EFSYS_OPT_RX_SCATTER */
567
568 #if EFSYS_OPT_RX_SCALE
569         __checkReturn   efx_rc_t
570 ef10_rx_scale_context_alloc(
571         __in            efx_nic_t *enp,
572         __in            efx_rx_scale_context_type_t type,
573         __in            uint32_t num_queues,
574         __out           uint32_t *rss_contextp)
575 {
576         efx_rc_t rc;
577
578         rc = efx_mcdi_rss_context_alloc(enp, type, num_queues, rss_contextp);
579         if (rc != 0)
580                 goto fail1;
581
582         return (0);
583
584 fail1:
585         EFSYS_PROBE1(fail1, efx_rc_t, rc);
586         return (rc);
587 }
588 #endif /* EFSYS_OPT_RX_SCALE */
589
590 #if EFSYS_OPT_RX_SCALE
591         __checkReturn   efx_rc_t
592 ef10_rx_scale_context_free(
593         __in            efx_nic_t *enp,
594         __in            uint32_t rss_context)
595 {
596         efx_rc_t rc;
597
598         rc = efx_mcdi_rss_context_free(enp, rss_context);
599         if (rc != 0)
600                 goto fail1;
601
602         return (0);
603
604 fail1:
605         EFSYS_PROBE1(fail1, efx_rc_t, rc);
606         return (rc);
607 }
608 #endif /* EFSYS_OPT_RX_SCALE */
609
610 #if EFSYS_OPT_RX_SCALE
611         __checkReturn   efx_rc_t
612 ef10_rx_scale_mode_set(
613         __in            efx_nic_t *enp,
614         __in            uint32_t rss_context,
615         __in            efx_rx_hash_alg_t alg,
616         __in            efx_rx_hash_type_t type,
617         __in            boolean_t insert)
618 {
619         efx_rc_t rc;
620
621         EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
622         EFSYS_ASSERT3U(insert, ==, B_TRUE);
623
624         if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
625                 rc = EINVAL;
626                 goto fail1;
627         }
628
629         if (rss_context == EFX_RSS_CONTEXT_DEFAULT) {
630                 if (enp->en_rss_context_type == EFX_RX_SCALE_UNAVAILABLE) {
631                         rc = ENOTSUP;
632                         goto fail2;
633                 }
634                 rss_context = enp->en_rss_context;
635         }
636
637         if ((rc = efx_mcdi_rss_context_set_flags(enp,
638                     rss_context, type)) != 0)
639                 goto fail3;
640
641         return (0);
642
643 fail3:
644         EFSYS_PROBE(fail3);
645 fail2:
646         EFSYS_PROBE(fail2);
647 fail1:
648         EFSYS_PROBE1(fail1, efx_rc_t, rc);
649
650         return (rc);
651 }
652 #endif /* EFSYS_OPT_RX_SCALE */
653
654 #if EFSYS_OPT_RX_SCALE
655         __checkReturn   efx_rc_t
656 ef10_rx_scale_key_set(
657         __in            efx_nic_t *enp,
658         __in            uint32_t rss_context,
659         __in_ecount(n)  uint8_t *key,
660         __in            size_t n)
661 {
662         efx_rc_t rc;
663
664         EFX_STATIC_ASSERT(EFX_RSS_KEY_SIZE ==
665             MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
666
667         if (rss_context == EFX_RSS_CONTEXT_DEFAULT) {
668                 if (enp->en_rss_context_type == EFX_RX_SCALE_UNAVAILABLE) {
669                         rc = ENOTSUP;
670                         goto fail1;
671                 }
672                 rss_context = enp->en_rss_context;
673         }
674
675         if ((rc = efx_mcdi_rss_context_set_key(enp, rss_context, key, n)) != 0)
676                 goto fail2;
677
678         return (0);
679
680 fail2:
681         EFSYS_PROBE(fail2);
682 fail1:
683         EFSYS_PROBE1(fail1, efx_rc_t, rc);
684
685         return (rc);
686 }
687 #endif /* EFSYS_OPT_RX_SCALE */
688
689 #if EFSYS_OPT_RX_SCALE
690         __checkReturn   efx_rc_t
691 ef10_rx_scale_tbl_set(
692         __in            efx_nic_t *enp,
693         __in            uint32_t rss_context,
694         __in_ecount(n)  unsigned int *table,
695         __in            size_t n)
696 {
697         efx_rc_t rc;
698
699
700         if (rss_context == EFX_RSS_CONTEXT_DEFAULT) {
701                 if (enp->en_rss_context_type == EFX_RX_SCALE_UNAVAILABLE) {
702                         rc = ENOTSUP;
703                         goto fail1;
704                 }
705                 rss_context = enp->en_rss_context;
706         }
707
708         if ((rc = efx_mcdi_rss_context_set_table(enp,
709                     rss_context, table, n)) != 0)
710                 goto fail2;
711
712         return (0);
713
714 fail2:
715         EFSYS_PROBE(fail2);
716 fail1:
717         EFSYS_PROBE1(fail1, efx_rc_t, rc);
718
719         return (rc);
720 }
721 #endif /* EFSYS_OPT_RX_SCALE */
722
723
724 /*
725  * EF10 RX pseudo-header
726  * ---------------------
727  *
728  * Receive packets are prefixed by an (optional) 14 byte pseudo-header:
729  *
730  *  +00: Toeplitz hash value.
731  *       (32bit little-endian)
732  *  +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag.
733  *       (16bit big-endian)
734  *  +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag.
735  *       (16bit big-endian)
736  *  +08: Packet Length. Zero if the RX datapath was in cut-through mode.
737  *       (16bit little-endian)
738  *  +10: MAC timestamp. Zero if timestamping is not enabled.
739  *       (32bit little-endian)
740  *
741  * See "The RX Pseudo-header" in SF-109306-TC.
742  */
743
744         __checkReturn   efx_rc_t
745 ef10_rx_prefix_pktlen(
746         __in            efx_nic_t *enp,
747         __in            uint8_t *buffer,
748         __out           uint16_t *lengthp)
749 {
750         _NOTE(ARGUNUSED(enp))
751
752         /*
753          * The RX pseudo-header contains the packet length, excluding the
754          * pseudo-header. If the hardware receive datapath was operating in
755          * cut-through mode then the length in the RX pseudo-header will be
756          * zero, and the packet length must be obtained from the DMA length
757          * reported in the RX event.
758          */
759         *lengthp = buffer[8] | (buffer[9] << 8);
760         return (0);
761 }
762
763 #if EFSYS_OPT_RX_SCALE
764         __checkReturn   uint32_t
765 ef10_rx_prefix_hash(
766         __in            efx_nic_t *enp,
767         __in            efx_rx_hash_alg_t func,
768         __in            uint8_t *buffer)
769 {
770         _NOTE(ARGUNUSED(enp))
771
772         switch (func) {
773         case EFX_RX_HASHALG_TOEPLITZ:
774                 return (buffer[0] |
775                     (buffer[1] << 8) |
776                     (buffer[2] << 16) |
777                     (buffer[3] << 24));
778
779         default:
780                 EFSYS_ASSERT(0);
781                 return (0);
782         }
783 }
784 #endif /* EFSYS_OPT_RX_SCALE */
785
786 #if EFSYS_OPT_RX_PACKED_STREAM
787 /*
788  * Fake length for RXQ descriptors in packed stream mode
789  * to make hardware happy
790  */
791 #define EFX_RXQ_PACKED_STREAM_FAKE_BUF_SIZE 32
792 #endif
793
794                                 void
795 ef10_rx_qpost(
796         __in                    efx_rxq_t *erp,
797         __in_ecount(ndescs)     efsys_dma_addr_t *addrp,
798         __in                    size_t size,
799         __in                    unsigned int ndescs,
800         __in                    unsigned int completed,
801         __in                    unsigned int added)
802 {
803         efx_qword_t qword;
804         unsigned int i;
805         unsigned int offset;
806         unsigned int id;
807
808         _NOTE(ARGUNUSED(completed))
809
810 #if EFSYS_OPT_RX_PACKED_STREAM
811         /*
812          * Real size of the buffer does not fit into ESF_DZ_RX_KER_BYTE_CNT
813          * and equal to 0 after applying mask. Hardware does not like it.
814          */
815         if (erp->er_ev_qstate->eers_rx_packed_stream)
816                 size = EFX_RXQ_PACKED_STREAM_FAKE_BUF_SIZE;
817 #endif
818
819         /* The client driver must not overfill the queue */
820         EFSYS_ASSERT3U(added - completed + ndescs, <=,
821             EFX_RXQ_LIMIT(erp->er_mask + 1));
822
823         id = added & (erp->er_mask);
824         for (i = 0; i < ndescs; i++) {
825                 EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
826                     unsigned int, id, efsys_dma_addr_t, addrp[i],
827                     size_t, size);
828
829                 EFX_POPULATE_QWORD_3(qword,
830                     ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
831                     ESF_DZ_RX_KER_BUF_ADDR_DW0,
832                     (uint32_t)(addrp[i] & 0xffffffff),
833                     ESF_DZ_RX_KER_BUF_ADDR_DW1,
834                     (uint32_t)(addrp[i] >> 32));
835
836                 offset = id * sizeof (efx_qword_t);
837                 EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
838
839                 id = (id + 1) & (erp->er_mask);
840         }
841 }
842
843                         void
844 ef10_rx_qpush(
845         __in    efx_rxq_t *erp,
846         __in    unsigned int added,
847         __inout unsigned int *pushedp)
848 {
849         efx_nic_t *enp = erp->er_enp;
850         unsigned int pushed = *pushedp;
851         uint32_t wptr;
852         efx_dword_t dword;
853
854         /* Hardware has alignment restriction for WPTR */
855         wptr = P2ALIGN(added, EF10_RX_WPTR_ALIGN);
856         if (pushed == wptr)
857                 return;
858
859         *pushedp = wptr;
860
861         /* Push the populated descriptors out */
862         wptr &= erp->er_mask;
863
864         EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
865
866         /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
867         EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
868             wptr, pushed & erp->er_mask);
869         EFSYS_PIO_WRITE_BARRIER();
870         EFX_BAR_VI_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
871             erp->er_index, &dword, B_FALSE);
872 }
873
874 #if EFSYS_OPT_RX_PACKED_STREAM
875
876                         void
877 ef10_rx_qpush_ps_credits(
878         __in            efx_rxq_t *erp)
879 {
880         efx_nic_t *enp = erp->er_enp;
881         efx_dword_t dword;
882         efx_evq_rxq_state_t *rxq_state = erp->er_ev_qstate;
883         uint32_t credits;
884
885         EFSYS_ASSERT(rxq_state->eers_rx_packed_stream);
886
887         if (rxq_state->eers_rx_packed_stream_credits == 0)
888                 return;
889
890         /*
891          * It is a bug if we think that FW has utilized more
892          * credits than it is allowed to have (maximum). However,
893          * make sure that we do not credit more than maximum anyway.
894          */
895         credits = MIN(rxq_state->eers_rx_packed_stream_credits,
896             EFX_RX_PACKED_STREAM_MAX_CREDITS);
897         EFX_POPULATE_DWORD_3(dword,
898             ERF_DZ_RX_DESC_MAGIC_DOORBELL, 1,
899             ERF_DZ_RX_DESC_MAGIC_CMD,
900             ERE_DZ_RX_DESC_MAGIC_CMD_PS_CREDITS,
901             ERF_DZ_RX_DESC_MAGIC_DATA, credits);
902         EFX_BAR_VI_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
903             erp->er_index, &dword, B_FALSE);
904
905         rxq_state->eers_rx_packed_stream_credits = 0;
906 }
907
908 /*
909  * In accordance with SF-112241-TC the received data has the following layout:
910  *  - 8 byte pseudo-header which consist of:
911  *    - 4 byte little-endian timestamp
912  *    - 2 byte little-endian captured length in bytes
913  *    - 2 byte little-endian original packet length in bytes
914  *  - captured packet bytes
915  *  - optional padding to align to 64 bytes boundary
916  *  - 64 bytes scratch space for the host software
917  */
918         __checkReturn   uint8_t *
919 ef10_rx_qps_packet_info(
920         __in            efx_rxq_t *erp,
921         __in            uint8_t *buffer,
922         __in            uint32_t buffer_length,
923         __in            uint32_t current_offset,
924         __out           uint16_t *lengthp,
925         __out           uint32_t *next_offsetp,
926         __out           uint32_t *timestamp)
927 {
928         uint16_t buf_len;
929         uint8_t *pkt_start;
930         efx_qword_t *qwordp;
931         efx_evq_rxq_state_t *rxq_state = erp->er_ev_qstate;
932
933         EFSYS_ASSERT(rxq_state->eers_rx_packed_stream);
934
935         buffer += current_offset;
936         pkt_start = buffer + EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE;
937
938         qwordp = (efx_qword_t *)buffer;
939         *timestamp = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_TSTAMP);
940         *lengthp   = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_ORIG_LEN);
941         buf_len    = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_CAP_LEN);
942
943         buf_len = P2ROUNDUP(buf_len + EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE,
944                             EFX_RX_PACKED_STREAM_ALIGNMENT);
945         *next_offsetp =
946             current_offset + buf_len + EFX_RX_PACKED_STREAM_ALIGNMENT;
947
948         EFSYS_ASSERT3U(*next_offsetp, <=, buffer_length);
949         EFSYS_ASSERT3U(current_offset + *lengthp, <, *next_offsetp);
950
951         if ((*next_offsetp ^ current_offset) &
952             EFX_RX_PACKED_STREAM_MEM_PER_CREDIT)
953                 rxq_state->eers_rx_packed_stream_credits++;
954
955         return (pkt_start);
956 }
957
958
959 #endif
960
961         __checkReturn   efx_rc_t
962 ef10_rx_qflush(
963         __in    efx_rxq_t *erp)
964 {
965         efx_nic_t *enp = erp->er_enp;
966         efx_rc_t rc;
967
968         if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
969                 goto fail1;
970
971         return (0);
972
973 fail1:
974         /*
975          * EALREADY is not an error, but indicates that the MC has rebooted and
976          * that the RXQ has already been destroyed. Callers need to know that
977          * the RXQ flush has completed to avoid waiting until timeout for a
978          * flush done event that will not be delivered.
979          */
980         if (rc != EALREADY)
981                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
982
983         return (rc);
984 }
985
986                 void
987 ef10_rx_qenable(
988         __in    efx_rxq_t *erp)
989 {
990         /* FIXME */
991         _NOTE(ARGUNUSED(erp))
992         /* FIXME */
993 }
994
995         __checkReturn   efx_rc_t
996 ef10_rx_qcreate(
997         __in            efx_nic_t *enp,
998         __in            unsigned int index,
999         __in            unsigned int label,
1000         __in            efx_rxq_type_t type,
1001         __in            uint32_t type_data,
1002         __in            efsys_mem_t *esmp,
1003         __in            size_t ndescs,
1004         __in            uint32_t id,
1005         __in            unsigned int flags,
1006         __in            efx_evq_t *eep,
1007         __in            efx_rxq_t *erp)
1008 {
1009         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1010         efx_rc_t rc;
1011         boolean_t disable_scatter;
1012         boolean_t want_inner_classes;
1013         unsigned int ps_buf_size;
1014
1015         _NOTE(ARGUNUSED(id, erp, type_data))
1016
1017         EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
1018         EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
1019         EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
1020
1021         EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
1022         EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
1023
1024         if (!ISP2(ndescs) ||
1025             (ndescs < EFX_RXQ_MINNDESCS) || (ndescs > EFX_RXQ_MAXNDESCS)) {
1026                 rc = EINVAL;
1027                 goto fail1;
1028         }
1029         if (index >= encp->enc_rxq_limit) {
1030                 rc = EINVAL;
1031                 goto fail2;
1032         }
1033
1034         switch (type) {
1035         case EFX_RXQ_TYPE_DEFAULT:
1036                 ps_buf_size = 0;
1037                 break;
1038 #if EFSYS_OPT_RX_PACKED_STREAM
1039         case EFX_RXQ_TYPE_PACKED_STREAM:
1040                 switch (type_data) {
1041                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_1M:
1042                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M;
1043                         break;
1044                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_512K:
1045                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_512K;
1046                         break;
1047                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_256K:
1048                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_256K;
1049                         break;
1050                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_128K:
1051                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_128K;
1052                         break;
1053                 case EFX_RXQ_PACKED_STREAM_BUF_SIZE_64K:
1054                         ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_64K;
1055                         break;
1056                 default:
1057                         rc = ENOTSUP;
1058                         goto fail3;
1059                 }
1060                 break;
1061 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1062         default:
1063                 rc = ENOTSUP;
1064                 goto fail4;
1065         }
1066
1067 #if EFSYS_OPT_RX_PACKED_STREAM
1068         if (ps_buf_size != 0) {
1069                 /* Check if datapath firmware supports packed stream mode */
1070                 if (encp->enc_rx_packed_stream_supported == B_FALSE) {
1071                         rc = ENOTSUP;
1072                         goto fail5;
1073                 }
1074                 /* Check if packed stream allows configurable buffer sizes */
1075                 if ((ps_buf_size != MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M) &&
1076                     (encp->enc_rx_var_packed_stream_supported == B_FALSE)) {
1077                         rc = ENOTSUP;
1078                         goto fail6;
1079                 }
1080         }
1081 #else /* EFSYS_OPT_RX_PACKED_STREAM */
1082         EFSYS_ASSERT(ps_buf_size == 0);
1083 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1084
1085         /* Scatter can only be disabled if the firmware supports doing so */
1086         if (flags & EFX_RXQ_FLAG_SCATTER)
1087                 disable_scatter = B_FALSE;
1088         else
1089                 disable_scatter = encp->enc_rx_disable_scatter_supported;
1090
1091         if (flags & EFX_RXQ_FLAG_INNER_CLASSES)
1092                 want_inner_classes = B_TRUE;
1093         else
1094                 want_inner_classes = B_FALSE;
1095
1096         if ((rc = efx_mcdi_init_rxq(enp, ndescs, eep->ee_index, label, index,
1097                     esmp, disable_scatter, want_inner_classes,
1098                     ps_buf_size)) != 0)
1099                 goto fail7;
1100
1101         erp->er_eep = eep;
1102         erp->er_label = label;
1103
1104         ef10_ev_rxlabel_init(eep, erp, label, type);
1105
1106         erp->er_ev_qstate = &erp->er_eep->ee_rxq_state[label];
1107
1108         return (0);
1109
1110 fail7:
1111         EFSYS_PROBE(fail7);
1112 #if EFSYS_OPT_RX_PACKED_STREAM
1113 fail6:
1114         EFSYS_PROBE(fail6);
1115 fail5:
1116         EFSYS_PROBE(fail5);
1117 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1118 fail4:
1119         EFSYS_PROBE(fail4);
1120 #if EFSYS_OPT_RX_PACKED_STREAM
1121 fail3:
1122         EFSYS_PROBE(fail3);
1123 #endif /* EFSYS_OPT_RX_PACKED_STREAM */
1124 fail2:
1125         EFSYS_PROBE(fail2);
1126 fail1:
1127         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1128
1129         return (rc);
1130 }
1131
1132                 void
1133 ef10_rx_qdestroy(
1134         __in    efx_rxq_t *erp)
1135 {
1136         efx_nic_t *enp = erp->er_enp;
1137         efx_evq_t *eep = erp->er_eep;
1138         unsigned int label = erp->er_label;
1139
1140         ef10_ev_rxlabel_fini(eep, label);
1141
1142         EFSYS_ASSERT(enp->en_rx_qcount != 0);
1143         --enp->en_rx_qcount;
1144
1145         EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
1146 }
1147
1148                 void
1149 ef10_rx_fini(
1150         __in    efx_nic_t *enp)
1151 {
1152 #if EFSYS_OPT_RX_SCALE
1153         if (enp->en_rss_context_type != EFX_RX_SCALE_UNAVAILABLE)
1154                 (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
1155         enp->en_rss_context = 0;
1156         enp->en_rss_context_type = EFX_RX_SCALE_UNAVAILABLE;
1157 #else
1158         _NOTE(ARGUNUSED(enp))
1159 #endif /* EFSYS_OPT_RX_SCALE */
1160 }
1161
1162 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */