2 * Copyright (c) 2012-2015 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
39 #if EFSYS_OPT_HUNTINGTON
42 static __checkReturn int
46 __in uint32_t target_evq,
48 __in uint32_t instance,
49 __in efsys_mem_t *esmp)
53 MAX(MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)),
54 MC_CMD_INIT_RXQ_OUT_LEN)];
55 int npages = EFX_RXQ_NBUFS(size);
57 efx_qword_t *dma_addr;
61 EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS);
63 (void) memset(payload, 0, sizeof (payload));
64 req.emr_cmd = MC_CMD_INIT_RXQ;
65 req.emr_in_buf = payload;
66 req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages);
67 req.emr_out_buf = payload;
68 req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN;
70 MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size);
71 MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq);
72 MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label);
73 MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance);
74 MCDI_IN_POPULATE_DWORD_5(req, INIT_RXQ_IN_FLAGS,
75 INIT_RXQ_IN_FLAG_BUFF_MODE, 0,
76 INIT_RXQ_IN_FLAG_HDR_SPLIT, 0,
77 INIT_RXQ_IN_FLAG_TIMESTAMP, 0,
78 INIT_RXQ_IN_CRC_MODE, 0,
79 INIT_RXQ_IN_FLAG_PREFIX, 1);
80 MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0);
81 MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED);
83 dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR);
84 addr = EFSYS_MEM_ADDR(esmp);
86 for (i = 0; i < npages; i++) {
87 EFX_POPULATE_QWORD_2(*dma_addr,
88 EFX_DWORD_1, (uint32_t)(addr >> 32),
89 EFX_DWORD_0, (uint32_t)(addr & 0xffffffff));
95 efx_mcdi_execute(enp, &req);
97 if (req.emr_rc != 0) {
105 EFSYS_PROBE1(fail1, int, rc);
110 static __checkReturn int
113 __in uint32_t instance)
116 uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN,
117 MC_CMD_FINI_RXQ_OUT_LEN)];
120 (void) memset(payload, 0, sizeof (payload));
121 req.emr_cmd = MC_CMD_FINI_RXQ;
122 req.emr_in_buf = payload;
123 req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN;
124 req.emr_out_buf = payload;
125 req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN;
127 MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance);
129 efx_mcdi_execute(enp, &req);
131 if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) {
139 EFSYS_PROBE1(fail1, int, rc);
144 #if EFSYS_OPT_RX_SCALE
145 static __checkReturn int
146 efx_mcdi_rss_context_alloc(
148 __out uint32_t *rss_contextp)
151 uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN,
152 MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)];
153 uint32_t rss_context;
156 (void) memset(payload, 0, sizeof (payload));
157 req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC;
158 req.emr_in_buf = payload;
159 req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN;
160 req.emr_out_buf = payload;
161 req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN;
163 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID,
164 EVB_PORT_ID_ASSIGNED);
165 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE,
166 MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE);
167 /* NUM_QUEUES is only used to validate indirection table offsets */
168 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, 64);
170 efx_mcdi_execute(enp, &req);
172 if (req.emr_rc != 0) {
177 if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) {
182 rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID);
183 if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
188 *rss_contextp = rss_context;
197 EFSYS_PROBE1(fail1, int, rc);
201 #endif /* EFSYS_OPT_RX_SCALE */
203 #if EFSYS_OPT_RX_SCALE
205 efx_mcdi_rss_context_free(
207 __in uint32_t rss_context)
210 uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN,
211 MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)];
214 if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
219 (void) memset(payload, 0, sizeof (payload));
220 req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE;
221 req.emr_in_buf = payload;
222 req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN;
223 req.emr_out_buf = payload;
224 req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN;
226 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context);
228 efx_mcdi_execute(enp, &req);
230 if (req.emr_rc != 0) {
240 EFSYS_PROBE1(fail1, int, rc);
244 #endif /* EFSYS_OPT_RX_SCALE */
246 #if EFSYS_OPT_RX_SCALE
248 efx_mcdi_rss_context_set_flags(
250 __in uint32_t rss_context,
251 __in efx_rx_hash_type_t type)
254 uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN,
255 MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)];
258 if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
263 (void) memset(payload, 0, sizeof (payload));
264 req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS;
265 req.emr_in_buf = payload;
266 req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN;
267 req.emr_out_buf = payload;
268 req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN;
270 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID,
273 MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS,
274 RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN,
275 (type & (1U << EFX_RX_HASH_IPV4)) ? 1 : 0,
276 RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN,
277 (type & (1U << EFX_RX_HASH_TCPIPV4)) ? 1 : 0,
278 RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN,
279 (type & (1U << EFX_RX_HASH_IPV6)) ? 1 : 0,
280 RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN,
281 (type & (1U << EFX_RX_HASH_TCPIPV6)) ? 1 : 0);
283 efx_mcdi_execute(enp, &req);
285 if (req.emr_rc != 0) {
295 EFSYS_PROBE1(fail1, int, rc);
299 #endif /* EFSYS_OPT_RX_SCALE */
301 #if EFSYS_OPT_RX_SCALE
303 efx_mcdi_rss_context_set_key(
305 __in uint32_t rss_context,
306 __in_ecount(n) uint8_t *key,
310 uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN,
311 MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)];
314 if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
319 (void) memset(payload, 0, sizeof (payload));
320 req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY;
321 req.emr_in_buf = payload;
322 req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN;
323 req.emr_out_buf = payload;
324 req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN;
326 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID,
329 EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
330 if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) {
335 memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY),
338 efx_mcdi_execute(enp, &req);
340 if (req.emr_rc != 0) {
352 EFSYS_PROBE1(fail1, int, rc);
356 #endif /* EFSYS_OPT_RX_SCALE */
358 #if EFSYS_OPT_RX_SCALE
360 efx_mcdi_rss_context_set_table(
362 __in uint32_t rss_context,
363 __in_ecount(n) unsigned int *table,
367 uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN,
368 MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)];
372 if (rss_context == HUNTINGTON_RSS_CONTEXT_INVALID) {
377 (void) memset(payload, 0, sizeof (payload));
378 req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE;
379 req.emr_in_buf = payload;
380 req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN;
381 req.emr_out_buf = payload;
382 req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN;
384 MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID,
388 MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE);
391 i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN;
393 req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0;
396 efx_mcdi_execute(enp, &req);
398 if (req.emr_rc != 0) {
408 EFSYS_PROBE1(fail1, int, rc);
412 #endif /* EFSYS_OPT_RX_SCALE */
419 #if EFSYS_OPT_RX_SCALE
421 if (efx_mcdi_rss_context_alloc(enp, &enp->en_rss_context) == 0) {
423 * Allocated an exclusive RSS context, which allows both the
424 * indirection table and key to be modified.
426 enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE;
427 enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
430 * Failed to allocate an exclusive RSS context. Continue
431 * operation without support for RSS. The pseudo-header in
432 * received packets will not contain a Toeplitz hash value.
434 enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
435 enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE;
438 #endif /* EFSYS_OPT_RX_SCALE */
443 #if EFSYS_OPT_RX_HDR_SPLIT
445 hunt_rx_hdr_split_enable(
447 __in unsigned int hdr_buf_size,
448 __in unsigned int pld_buf_size)
453 _NOTE(ARGUNUSED(enp, hdr_buf_size, pld_buf_size))
463 EFSYS_PROBE1(fail1, int, rc);
467 #endif /* EFSYS_OPT_RX_HDR_SPLIT */
469 #if EFSYS_OPT_RX_SCATTER
471 hunt_rx_scatter_enable(
473 __in unsigned int buf_size)
475 _NOTE(ARGUNUSED(enp, buf_size))
478 #endif /* EFSYS_OPT_RX_SCATTER */
480 #if EFSYS_OPT_RX_SCALE
482 hunt_rx_scale_mode_set(
484 __in efx_rx_hash_alg_t alg,
485 __in efx_rx_hash_type_t type,
486 __in boolean_t insert)
490 EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ);
491 EFSYS_ASSERT3U(insert, ==, B_TRUE);
493 if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) {
498 if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
503 if ((rc = efx_mcdi_rss_context_set_flags(enp,
504 enp->en_rss_context, type)) != 0)
514 EFSYS_PROBE1(fail1, int, rc);
518 #endif /* EFSYS_OPT_RX_SCALE */
520 #if EFSYS_OPT_RX_SCALE
522 hunt_rx_scale_key_set(
524 __in_ecount(n) uint8_t *key,
529 if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
534 if ((rc = efx_mcdi_rss_context_set_key(enp,
535 enp->en_rss_context, key, n)) != 0)
543 EFSYS_PROBE1(fail1, int, rc);
547 #endif /* EFSYS_OPT_RX_SCALE */
549 #if EFSYS_OPT_RX_SCALE
551 hunt_rx_scale_tbl_set(
553 __in_ecount(n) unsigned int *table,
558 if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) {
563 if ((rc = efx_mcdi_rss_context_set_table(enp,
564 enp->en_rss_context, table, n)) != 0)
572 EFSYS_PROBE1(fail1, int, rc);
576 #endif /* EFSYS_OPT_RX_SCALE */
581 __in_ecount(n) efsys_dma_addr_t *addrp,
584 __in unsigned int completed,
585 __in unsigned int added)
592 /* The client driver must not overfill the queue */
593 EFSYS_ASSERT3U(added - completed + n, <=,
594 EFX_RXQ_LIMIT(erp->er_mask + 1));
596 id = added & (erp->er_mask);
597 for (i = 0; i < n; i++) {
598 EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
599 unsigned int, id, efsys_dma_addr_t, addrp[i],
602 EFX_POPULATE_QWORD_3(qword,
603 ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size),
604 ESF_DZ_RX_KER_BUF_ADDR_DW0,
605 (uint32_t)(addrp[i] & 0xffffffff),
606 ESF_DZ_RX_KER_BUF_ADDR_DW1,
607 (uint32_t)(addrp[i] >> 32));
609 offset = id * sizeof (efx_qword_t);
610 EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
612 id = (id + 1) & (erp->er_mask);
619 __in unsigned int added,
620 __inout unsigned int *pushedp)
622 efx_nic_t *enp = erp->er_enp;
623 unsigned int pushed = *pushedp;
627 /* Hardware has alignment restriction for WPTR */
628 wptr = P2ALIGN(added, HUNTINGTON_RX_WPTR_ALIGN);
634 /* Push the populated descriptors out */
635 wptr &= erp->er_mask;
637 EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr);
639 /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
640 EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
641 wptr, pushed & erp->er_mask);
642 EFSYS_PIO_WRITE_BARRIER();
643 EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG,
644 erp->er_index, &dword, B_FALSE);
651 efx_nic_t *enp = erp->er_enp;
654 if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0)
660 EFSYS_PROBE1(fail1, int, rc);
670 _NOTE(ARGUNUSED(erp))
677 __in unsigned int index,
678 __in unsigned int label,
679 __in efx_rxq_type_t type,
680 __in efsys_mem_t *esmp,
686 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
689 _NOTE(ARGUNUSED(erp))
691 EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH));
692 EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
693 EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
695 EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS));
696 EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS));
698 if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) {
702 if (index >= encp->enc_rxq_limit) {
708 * FIXME: Siena code handles different queue types (default, header
709 * split, scatter); we'll need to do something more here later, but
710 * all that stuff is TBD for now.
713 if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index,
718 erp->er_label = label;
720 hunt_ev_rxlabel_init(eep, erp, label);
729 EFSYS_PROBE1(fail1, int, rc);
738 efx_nic_t *enp = erp->er_enp;
739 efx_evq_t *eep = erp->er_eep;
740 unsigned int label = erp->er_label;
742 hunt_ev_rxlabel_fini(eep, label);
744 EFSYS_ASSERT(enp->en_rx_qcount != 0);
747 EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
754 #if EFSYS_OPT_RX_SCALE
755 if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) {
756 (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context);
758 enp->en_rss_context = 0;
759 enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE;
761 _NOTE(ARGUNUSED(enp))
762 #endif /* EFSYS_OPT_RX_SCALE */
765 #endif /* EFSYS_OPT_HUNTINGTON */