xref: /dpdk/drivers/common/sfc_efx/base/efx_rx.c (revision e5e5c12756d133e44456e64eafdc3a0e728b57d5)
15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko  *
3672386c1SAndrew Rybchenko  * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko  * Copyright(c) 2007-2019 Solarflare Communications Inc.
55e111ed8SAndrew Rybchenko  */
65e111ed8SAndrew Rybchenko 
75e111ed8SAndrew Rybchenko #include "efx.h"
85e111ed8SAndrew Rybchenko #include "efx_impl.h"
95e111ed8SAndrew Rybchenko 
105e111ed8SAndrew Rybchenko 
115e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
125e111ed8SAndrew Rybchenko 
135e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
145e111ed8SAndrew Rybchenko siena_rx_init(
155e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp);
165e111ed8SAndrew Rybchenko 
175e111ed8SAndrew Rybchenko static			void
185e111ed8SAndrew Rybchenko siena_rx_fini(
195e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp);
205e111ed8SAndrew Rybchenko 
215e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
225e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
235e111ed8SAndrew Rybchenko siena_rx_scatter_enable(
245e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
255e111ed8SAndrew Rybchenko 	__in		unsigned int buf_size);
265e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCATTER */
275e111ed8SAndrew Rybchenko 
285e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
295e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
305e111ed8SAndrew Rybchenko siena_rx_scale_mode_set(
315e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
325e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context,
335e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_alg_t alg,
345e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_type_t type,
355e111ed8SAndrew Rybchenko 	__in		boolean_t insert);
365e111ed8SAndrew Rybchenko 
375e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
385e111ed8SAndrew Rybchenko siena_rx_scale_key_set(
395e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
405e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context,
415e111ed8SAndrew Rybchenko 	__in_ecount(n)	uint8_t *key,
425e111ed8SAndrew Rybchenko 	__in		size_t n);
435e111ed8SAndrew Rybchenko 
445e111ed8SAndrew Rybchenko static	__checkReturn		efx_rc_t
455e111ed8SAndrew Rybchenko siena_rx_scale_tbl_set(
465e111ed8SAndrew Rybchenko 	__in			efx_nic_t *enp,
475e111ed8SAndrew Rybchenko 	__in			uint32_t rss_context,
487a71c15dSIvan Malov 	__in_ecount(nentries)	unsigned int *table,
497a71c15dSIvan Malov 	__in			size_t nentries);
505e111ed8SAndrew Rybchenko 
515e111ed8SAndrew Rybchenko static	__checkReturn	uint32_t
525e111ed8SAndrew Rybchenko siena_rx_prefix_hash(
535e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
545e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_alg_t func,
555e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer);
565e111ed8SAndrew Rybchenko 
575e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCALE */
585e111ed8SAndrew Rybchenko 
595e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
605e111ed8SAndrew Rybchenko siena_rx_prefix_pktlen(
615e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
625e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer,
635e111ed8SAndrew Rybchenko 	__out		uint16_t *lengthp);
645e111ed8SAndrew Rybchenko 
655e111ed8SAndrew Rybchenko static				void
665e111ed8SAndrew Rybchenko siena_rx_qpost(
675e111ed8SAndrew Rybchenko 	__in			efx_rxq_t *erp,
685e111ed8SAndrew Rybchenko 	__in_ecount(ndescs)	efsys_dma_addr_t *addrp,
695e111ed8SAndrew Rybchenko 	__in			size_t size,
705e111ed8SAndrew Rybchenko 	__in			unsigned int ndescs,
715e111ed8SAndrew Rybchenko 	__in			unsigned int completed,
725e111ed8SAndrew Rybchenko 	__in			unsigned int added);
735e111ed8SAndrew Rybchenko 
745e111ed8SAndrew Rybchenko static			void
755e111ed8SAndrew Rybchenko siena_rx_qpush(
765e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
775e111ed8SAndrew Rybchenko 	__in		unsigned int added,
785e111ed8SAndrew Rybchenko 	__inout		unsigned int *pushedp);
795e111ed8SAndrew Rybchenko 
805e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
815e111ed8SAndrew Rybchenko static		void
825e111ed8SAndrew Rybchenko siena_rx_qpush_ps_credits(
835e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp);
845e111ed8SAndrew Rybchenko 
855e111ed8SAndrew Rybchenko static	__checkReturn	uint8_t *
865e111ed8SAndrew Rybchenko siena_rx_qps_packet_info(
875e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
885e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer,
895e111ed8SAndrew Rybchenko 	__in		uint32_t buffer_length,
905e111ed8SAndrew Rybchenko 	__in		uint32_t current_offset,
915e111ed8SAndrew Rybchenko 	__out		uint16_t *lengthp,
925e111ed8SAndrew Rybchenko 	__out		uint32_t *next_offsetp,
935e111ed8SAndrew Rybchenko 	__out		uint32_t *timestamp);
945e111ed8SAndrew Rybchenko #endif
955e111ed8SAndrew Rybchenko 
965e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
975e111ed8SAndrew Rybchenko siena_rx_qflush(
985e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp);
995e111ed8SAndrew Rybchenko 
1005e111ed8SAndrew Rybchenko static			void
1015e111ed8SAndrew Rybchenko siena_rx_qenable(
1025e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp);
1035e111ed8SAndrew Rybchenko 
1045e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
1055e111ed8SAndrew Rybchenko siena_rx_qcreate(
1065e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
1075e111ed8SAndrew Rybchenko 	__in		unsigned int index,
1085e111ed8SAndrew Rybchenko 	__in		unsigned int label,
1095e111ed8SAndrew Rybchenko 	__in		efx_rxq_type_t type,
1105e111ed8SAndrew Rybchenko 	__in_opt	const efx_rxq_type_data_t *type_data,
1115e111ed8SAndrew Rybchenko 	__in		efsys_mem_t *esmp,
1125e111ed8SAndrew Rybchenko 	__in		size_t ndescs,
1135e111ed8SAndrew Rybchenko 	__in		uint32_t id,
1145e111ed8SAndrew Rybchenko 	__in		unsigned int flags,
1155e111ed8SAndrew Rybchenko 	__in		efx_evq_t *eep,
1165e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp);
1175e111ed8SAndrew Rybchenko 
1185e111ed8SAndrew Rybchenko static			void
1195e111ed8SAndrew Rybchenko siena_rx_qdestroy(
1205e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp);
1215e111ed8SAndrew Rybchenko 
1225e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
1235e111ed8SAndrew Rybchenko 
1245e111ed8SAndrew Rybchenko 
1255e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
1265e111ed8SAndrew Rybchenko static const efx_rx_ops_t __efx_rx_siena_ops = {
1275e111ed8SAndrew Rybchenko 	siena_rx_init,				/* erxo_init */
1285e111ed8SAndrew Rybchenko 	siena_rx_fini,				/* erxo_fini */
1295e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
1305e111ed8SAndrew Rybchenko 	siena_rx_scatter_enable,		/* erxo_scatter_enable */
1315e111ed8SAndrew Rybchenko #endif
1325e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
1335e111ed8SAndrew Rybchenko 	NULL,					/* erxo_scale_context_alloc */
1345e111ed8SAndrew Rybchenko 	NULL,					/* erxo_scale_context_free */
1355e111ed8SAndrew Rybchenko 	siena_rx_scale_mode_set,		/* erxo_scale_mode_set */
1365e111ed8SAndrew Rybchenko 	siena_rx_scale_key_set,			/* erxo_scale_key_set */
1375e111ed8SAndrew Rybchenko 	siena_rx_scale_tbl_set,			/* erxo_scale_tbl_set */
1385e111ed8SAndrew Rybchenko 	siena_rx_prefix_hash,			/* erxo_prefix_hash */
1395e111ed8SAndrew Rybchenko #endif
1405e111ed8SAndrew Rybchenko 	siena_rx_prefix_pktlen,			/* erxo_prefix_pktlen */
1415e111ed8SAndrew Rybchenko 	siena_rx_qpost,				/* erxo_qpost */
1425e111ed8SAndrew Rybchenko 	siena_rx_qpush,				/* erxo_qpush */
1435e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
1445e111ed8SAndrew Rybchenko 	siena_rx_qpush_ps_credits,		/* erxo_qpush_ps_credits */
1455e111ed8SAndrew Rybchenko 	siena_rx_qps_packet_info,		/* erxo_qps_packet_info */
1465e111ed8SAndrew Rybchenko #endif
1475e111ed8SAndrew Rybchenko 	siena_rx_qflush,			/* erxo_qflush */
1485e111ed8SAndrew Rybchenko 	siena_rx_qenable,			/* erxo_qenable */
1495e111ed8SAndrew Rybchenko 	siena_rx_qcreate,			/* erxo_qcreate */
1505e111ed8SAndrew Rybchenko 	siena_rx_qdestroy,			/* erxo_qdestroy */
1515e111ed8SAndrew Rybchenko };
1525e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_SIENA */
1535e111ed8SAndrew Rybchenko 
1545e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
1555e111ed8SAndrew Rybchenko static const efx_rx_ops_t __efx_rx_ef10_ops = {
1565e111ed8SAndrew Rybchenko 	ef10_rx_init,				/* erxo_init */
1575e111ed8SAndrew Rybchenko 	ef10_rx_fini,				/* erxo_fini */
1585e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
1595e111ed8SAndrew Rybchenko 	ef10_rx_scatter_enable,			/* erxo_scatter_enable */
1605e111ed8SAndrew Rybchenko #endif
1615e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
1625e111ed8SAndrew Rybchenko 	ef10_rx_scale_context_alloc,		/* erxo_scale_context_alloc */
1635e111ed8SAndrew Rybchenko 	ef10_rx_scale_context_free,		/* erxo_scale_context_free */
1645e111ed8SAndrew Rybchenko 	ef10_rx_scale_mode_set,			/* erxo_scale_mode_set */
1655e111ed8SAndrew Rybchenko 	ef10_rx_scale_key_set,			/* erxo_scale_key_set */
1665e111ed8SAndrew Rybchenko 	ef10_rx_scale_tbl_set,			/* erxo_scale_tbl_set */
1675e111ed8SAndrew Rybchenko 	ef10_rx_prefix_hash,			/* erxo_prefix_hash */
1685e111ed8SAndrew Rybchenko #endif
1695e111ed8SAndrew Rybchenko 	ef10_rx_prefix_pktlen,			/* erxo_prefix_pktlen */
1705e111ed8SAndrew Rybchenko 	ef10_rx_qpost,				/* erxo_qpost */
1715e111ed8SAndrew Rybchenko 	ef10_rx_qpush,				/* erxo_qpush */
1725e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
1735e111ed8SAndrew Rybchenko 	ef10_rx_qpush_ps_credits,		/* erxo_qpush_ps_credits */
1745e111ed8SAndrew Rybchenko 	ef10_rx_qps_packet_info,		/* erxo_qps_packet_info */
1755e111ed8SAndrew Rybchenko #endif
1765e111ed8SAndrew Rybchenko 	ef10_rx_qflush,				/* erxo_qflush */
1775e111ed8SAndrew Rybchenko 	ef10_rx_qenable,			/* erxo_qenable */
1785e111ed8SAndrew Rybchenko 	ef10_rx_qcreate,			/* erxo_qcreate */
1795e111ed8SAndrew Rybchenko 	ef10_rx_qdestroy,			/* erxo_qdestroy */
1805e111ed8SAndrew Rybchenko };
1815e111ed8SAndrew Rybchenko #endif	/* EFX_OPTS_EF10() */
1825e111ed8SAndrew Rybchenko 
183b6b29352SAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
184b6b29352SAndrew Rybchenko static const efx_rx_ops_t __efx_rx_rhead_ops = {
185b6b29352SAndrew Rybchenko 	rhead_rx_init,				/* erxo_init */
186b6b29352SAndrew Rybchenko 	rhead_rx_fini,				/* erxo_fini */
187b6b29352SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
188b6b29352SAndrew Rybchenko 	rhead_rx_scatter_enable,		/* erxo_scatter_enable */
189b6b29352SAndrew Rybchenko #endif
190b6b29352SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
191b6b29352SAndrew Rybchenko 	rhead_rx_scale_context_alloc,		/* erxo_scale_context_alloc */
192b6b29352SAndrew Rybchenko 	rhead_rx_scale_context_free,		/* erxo_scale_context_free */
193b6b29352SAndrew Rybchenko 	rhead_rx_scale_mode_set,		/* erxo_scale_mode_set */
194b6b29352SAndrew Rybchenko 	rhead_rx_scale_key_set,			/* erxo_scale_key_set */
195b6b29352SAndrew Rybchenko 	rhead_rx_scale_tbl_set,			/* erxo_scale_tbl_set */
196b6b29352SAndrew Rybchenko 	rhead_rx_prefix_hash,			/* erxo_prefix_hash */
197b6b29352SAndrew Rybchenko #endif
198b6b29352SAndrew Rybchenko 	rhead_rx_prefix_pktlen,			/* erxo_prefix_pktlen */
199b6b29352SAndrew Rybchenko 	rhead_rx_qpost,				/* erxo_qpost */
200b6b29352SAndrew Rybchenko 	rhead_rx_qpush,				/* erxo_qpush */
201b6b29352SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
202b6b29352SAndrew Rybchenko 	NULL,					/* erxo_qpush_ps_credits */
203b6b29352SAndrew Rybchenko 	NULL,					/* erxo_qps_packet_info */
204b6b29352SAndrew Rybchenko #endif
205b6b29352SAndrew Rybchenko 	rhead_rx_qflush,			/* erxo_qflush */
206b6b29352SAndrew Rybchenko 	rhead_rx_qenable,			/* erxo_qenable */
207b6b29352SAndrew Rybchenko 	rhead_rx_qcreate,			/* erxo_qcreate */
208b6b29352SAndrew Rybchenko 	rhead_rx_qdestroy,			/* erxo_qdestroy */
209b6b29352SAndrew Rybchenko };
210b6b29352SAndrew Rybchenko #endif	/* EFSYS_OPT_RIVERHEAD */
211b6b29352SAndrew Rybchenko 
2125e111ed8SAndrew Rybchenko 
2135e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_init(__inout efx_nic_t * enp)2145e111ed8SAndrew Rybchenko efx_rx_init(
2155e111ed8SAndrew Rybchenko 	__inout		efx_nic_t *enp)
2165e111ed8SAndrew Rybchenko {
2175e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop;
2185e111ed8SAndrew Rybchenko 	efx_rc_t rc;
2195e111ed8SAndrew Rybchenko 
2205e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2215e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
2225e111ed8SAndrew Rybchenko 
2235e111ed8SAndrew Rybchenko 	if (!(enp->en_mod_flags & EFX_MOD_EV)) {
2245e111ed8SAndrew Rybchenko 		rc = EINVAL;
2255e111ed8SAndrew Rybchenko 		goto fail1;
2265e111ed8SAndrew Rybchenko 	}
2275e111ed8SAndrew Rybchenko 
2285e111ed8SAndrew Rybchenko 	if (enp->en_mod_flags & EFX_MOD_RX) {
2295e111ed8SAndrew Rybchenko 		rc = EINVAL;
2305e111ed8SAndrew Rybchenko 		goto fail2;
2315e111ed8SAndrew Rybchenko 	}
2325e111ed8SAndrew Rybchenko 
2335e111ed8SAndrew Rybchenko 	switch (enp->en_family) {
2345e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
2355e111ed8SAndrew Rybchenko 	case EFX_FAMILY_SIENA:
2365e111ed8SAndrew Rybchenko 		erxop = &__efx_rx_siena_ops;
2375e111ed8SAndrew Rybchenko 		break;
2385e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
2395e111ed8SAndrew Rybchenko 
2405e111ed8SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
2415e111ed8SAndrew Rybchenko 	case EFX_FAMILY_HUNTINGTON:
2425e111ed8SAndrew Rybchenko 		erxop = &__efx_rx_ef10_ops;
2435e111ed8SAndrew Rybchenko 		break;
2445e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
2455e111ed8SAndrew Rybchenko 
2465e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
2475e111ed8SAndrew Rybchenko 	case EFX_FAMILY_MEDFORD:
2485e111ed8SAndrew Rybchenko 		erxop = &__efx_rx_ef10_ops;
2495e111ed8SAndrew Rybchenko 		break;
2505e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
2515e111ed8SAndrew Rybchenko 
2525e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
2535e111ed8SAndrew Rybchenko 	case EFX_FAMILY_MEDFORD2:
2545e111ed8SAndrew Rybchenko 		erxop = &__efx_rx_ef10_ops;
2555e111ed8SAndrew Rybchenko 		break;
2565e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
2575e111ed8SAndrew Rybchenko 
258b6b29352SAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
259b6b29352SAndrew Rybchenko 	case EFX_FAMILY_RIVERHEAD:
260b6b29352SAndrew Rybchenko 		erxop = &__efx_rx_rhead_ops;
261b6b29352SAndrew Rybchenko 		break;
262b6b29352SAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
263b6b29352SAndrew Rybchenko 
2645e111ed8SAndrew Rybchenko 	default:
2655e111ed8SAndrew Rybchenko 		EFSYS_ASSERT(0);
2665e111ed8SAndrew Rybchenko 		rc = ENOTSUP;
2675e111ed8SAndrew Rybchenko 		goto fail3;
2685e111ed8SAndrew Rybchenko 	}
2695e111ed8SAndrew Rybchenko 
2705e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_init(enp)) != 0)
2715e111ed8SAndrew Rybchenko 		goto fail4;
2725e111ed8SAndrew Rybchenko 
2735e111ed8SAndrew Rybchenko 	enp->en_erxop = erxop;
2745e111ed8SAndrew Rybchenko 	enp->en_mod_flags |= EFX_MOD_RX;
2755e111ed8SAndrew Rybchenko 	return (0);
2765e111ed8SAndrew Rybchenko 
2775e111ed8SAndrew Rybchenko fail4:
2785e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail4);
2795e111ed8SAndrew Rybchenko fail3:
2805e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail3);
2815e111ed8SAndrew Rybchenko fail2:
2825e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
2835e111ed8SAndrew Rybchenko fail1:
2845e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2855e111ed8SAndrew Rybchenko 
2865e111ed8SAndrew Rybchenko 	enp->en_erxop = NULL;
2875e111ed8SAndrew Rybchenko 	enp->en_mod_flags &= ~EFX_MOD_RX;
2885e111ed8SAndrew Rybchenko 	return (rc);
2895e111ed8SAndrew Rybchenko }
2905e111ed8SAndrew Rybchenko 
2915e111ed8SAndrew Rybchenko 			void
efx_rx_fini(__in efx_nic_t * enp)2925e111ed8SAndrew Rybchenko efx_rx_fini(
2935e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp)
2945e111ed8SAndrew Rybchenko {
2955e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
2965e111ed8SAndrew Rybchenko 
2975e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2985e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
2995e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
3005e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_rx_qcount, ==, 0);
3015e111ed8SAndrew Rybchenko 
3025e111ed8SAndrew Rybchenko 	erxop->erxo_fini(enp);
3035e111ed8SAndrew Rybchenko 
3045e111ed8SAndrew Rybchenko 	enp->en_erxop = NULL;
3055e111ed8SAndrew Rybchenko 	enp->en_mod_flags &= ~EFX_MOD_RX;
3065e111ed8SAndrew Rybchenko }
3075e111ed8SAndrew Rybchenko 
3085e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
3095e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_scatter_enable(__in efx_nic_t * enp,__in unsigned int buf_size)3105e111ed8SAndrew Rybchenko efx_rx_scatter_enable(
3115e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
3125e111ed8SAndrew Rybchenko 	__in		unsigned int buf_size)
3135e111ed8SAndrew Rybchenko {
3145e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
3155e111ed8SAndrew Rybchenko 	efx_rc_t rc;
3165e111ed8SAndrew Rybchenko 
3175e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3185e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
3195e111ed8SAndrew Rybchenko 
3205e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_scatter_enable(enp, buf_size)) != 0)
3215e111ed8SAndrew Rybchenko 		goto fail1;
3225e111ed8SAndrew Rybchenko 
3235e111ed8SAndrew Rybchenko 	return (0);
3245e111ed8SAndrew Rybchenko 
3255e111ed8SAndrew Rybchenko fail1:
3265e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3275e111ed8SAndrew Rybchenko 	return (rc);
3285e111ed8SAndrew Rybchenko }
3295e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCATTER */
3305e111ed8SAndrew Rybchenko 
3315e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
3325e111ed8SAndrew Rybchenko 	__checkReturn				efx_rc_t
efx_rx_scale_hash_flags_get(__in efx_nic_t * enp,__in efx_rx_hash_alg_t hash_alg,__out_ecount_part (max_nflags,* nflagsp)unsigned int * flagsp,__in unsigned int max_nflags,__out unsigned int * nflagsp)3335e111ed8SAndrew Rybchenko efx_rx_scale_hash_flags_get(
3345e111ed8SAndrew Rybchenko 	__in					efx_nic_t *enp,
3355e111ed8SAndrew Rybchenko 	__in					efx_rx_hash_alg_t hash_alg,
3365e111ed8SAndrew Rybchenko 	__out_ecount_part(max_nflags, *nflagsp)	unsigned int *flagsp,
3375e111ed8SAndrew Rybchenko 	__in					unsigned int max_nflags,
3385e111ed8SAndrew Rybchenko 	__out					unsigned int *nflagsp)
3395e111ed8SAndrew Rybchenko {
3405e111ed8SAndrew Rybchenko 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
3415e111ed8SAndrew Rybchenko 	unsigned int nflags = 0;
3425e111ed8SAndrew Rybchenko 	efx_rc_t rc;
3435e111ed8SAndrew Rybchenko 
3445e111ed8SAndrew Rybchenko 	if (flagsp == NULL || nflagsp == NULL) {
3455e111ed8SAndrew Rybchenko 		rc = EINVAL;
3465e111ed8SAndrew Rybchenko 		goto fail1;
3475e111ed8SAndrew Rybchenko 	}
3485e111ed8SAndrew Rybchenko 
3495e111ed8SAndrew Rybchenko 	if ((encp->enc_rx_scale_hash_alg_mask & (1U << hash_alg)) == 0) {
3505e111ed8SAndrew Rybchenko 		nflags = 0;
3515e111ed8SAndrew Rybchenko 		goto done;
3525e111ed8SAndrew Rybchenko 	}
3535e111ed8SAndrew Rybchenko 
3545e111ed8SAndrew Rybchenko 	/* Helper to add flags word to flags array without buffer overflow */
3555e111ed8SAndrew Rybchenko #define	INSERT_FLAGS(_flags)			\
3565e111ed8SAndrew Rybchenko 	do {					\
3575e111ed8SAndrew Rybchenko 		if (nflags >= max_nflags) {	\
3585e111ed8SAndrew Rybchenko 			rc = E2BIG;		\
3595e111ed8SAndrew Rybchenko 			goto fail2;		\
3605e111ed8SAndrew Rybchenko 		}				\
3615e111ed8SAndrew Rybchenko 		*(flagsp + nflags) = (_flags);	\
3625e111ed8SAndrew Rybchenko 		nflags++;			\
3635e111ed8SAndrew Rybchenko 						\
3645e111ed8SAndrew Rybchenko 		_NOTE(CONSTANTCONDITION)	\
3655e111ed8SAndrew Rybchenko 	} while (B_FALSE)
3665e111ed8SAndrew Rybchenko 
3675e111ed8SAndrew Rybchenko 	if (encp->enc_rx_scale_l4_hash_supported != B_FALSE) {
3685e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 4TUPLE));
3695e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 4TUPLE));
3705e111ed8SAndrew Rybchenko 	}
3715e111ed8SAndrew Rybchenko 
3725e111ed8SAndrew Rybchenko 	if ((encp->enc_rx_scale_l4_hash_supported != B_FALSE) &&
3735e111ed8SAndrew Rybchenko 	    (encp->enc_rx_scale_additional_modes_supported != B_FALSE)) {
3745e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 2TUPLE_DST));
3755e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 2TUPLE_SRC));
3765e111ed8SAndrew Rybchenko 
3775e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 2TUPLE_DST));
3785e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 2TUPLE_SRC));
3795e111ed8SAndrew Rybchenko 
3805e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 4TUPLE));
3815e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 2TUPLE_DST));
3825e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 2TUPLE_SRC));
3835e111ed8SAndrew Rybchenko 
3845e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 4TUPLE));
3855e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 2TUPLE_DST));
3865e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 2TUPLE_SRC));
3875e111ed8SAndrew Rybchenko 	}
3885e111ed8SAndrew Rybchenko 
3895e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 2TUPLE));
3905e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 2TUPLE));
3915e111ed8SAndrew Rybchenko 
3925e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV4, 2TUPLE));
3935e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV6, 2TUPLE));
3945e111ed8SAndrew Rybchenko 
3955e111ed8SAndrew Rybchenko 	if (encp->enc_rx_scale_additional_modes_supported != B_FALSE) {
3965e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 1TUPLE_DST));
3975e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, 1TUPLE_SRC));
3985e111ed8SAndrew Rybchenko 
3995e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 1TUPLE_DST));
4005e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, 1TUPLE_SRC));
4015e111ed8SAndrew Rybchenko 
4025e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 2TUPLE));
4035e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 1TUPLE_DST));
4045e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, 1TUPLE_SRC));
4055e111ed8SAndrew Rybchenko 
4065e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 2TUPLE));
4075e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 1TUPLE_DST));
4085e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, 1TUPLE_SRC));
4095e111ed8SAndrew Rybchenko 
4105e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4, 1TUPLE_DST));
4115e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV4, 1TUPLE_SRC));
4125e111ed8SAndrew Rybchenko 
4135e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6, 1TUPLE_DST));
4145e111ed8SAndrew Rybchenko 		INSERT_FLAGS(EFX_RX_HASH(IPV6, 1TUPLE_SRC));
4155e111ed8SAndrew Rybchenko 	}
4165e111ed8SAndrew Rybchenko 
4175e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV4_TCP, DISABLE));
4185e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV6_TCP, DISABLE));
4195e111ed8SAndrew Rybchenko 
4205e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV4_UDP, DISABLE));
4215e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV6_UDP, DISABLE));
4225e111ed8SAndrew Rybchenko 
4235e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV4, DISABLE));
4245e111ed8SAndrew Rybchenko 	INSERT_FLAGS(EFX_RX_HASH(IPV6, DISABLE));
4255e111ed8SAndrew Rybchenko 
4265e111ed8SAndrew Rybchenko #undef INSERT_FLAGS
4275e111ed8SAndrew Rybchenko 
4285e111ed8SAndrew Rybchenko done:
4295e111ed8SAndrew Rybchenko 	*nflagsp = nflags;
4305e111ed8SAndrew Rybchenko 	return (0);
4315e111ed8SAndrew Rybchenko 
4325e111ed8SAndrew Rybchenko fail2:
4335e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
4345e111ed8SAndrew Rybchenko fail1:
4355e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4365e111ed8SAndrew Rybchenko 
4375e111ed8SAndrew Rybchenko 	return (rc);
4385e111ed8SAndrew Rybchenko }
4395e111ed8SAndrew Rybchenko 
4405e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_hash_default_support_get(__in efx_nic_t * enp,__out efx_rx_hash_support_t * supportp)4415e111ed8SAndrew Rybchenko efx_rx_hash_default_support_get(
4425e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
4435e111ed8SAndrew Rybchenko 	__out		efx_rx_hash_support_t *supportp)
4445e111ed8SAndrew Rybchenko {
4455e111ed8SAndrew Rybchenko 	efx_rc_t rc;
4465e111ed8SAndrew Rybchenko 
4475e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4485e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
4495e111ed8SAndrew Rybchenko 
4505e111ed8SAndrew Rybchenko 	if (supportp == NULL) {
4515e111ed8SAndrew Rybchenko 		rc = EINVAL;
4525e111ed8SAndrew Rybchenko 		goto fail1;
4535e111ed8SAndrew Rybchenko 	}
4545e111ed8SAndrew Rybchenko 
4555e111ed8SAndrew Rybchenko 	/*
4565e111ed8SAndrew Rybchenko 	 * Report the hashing support the client gets by default if it
4575e111ed8SAndrew Rybchenko 	 * does not allocate an RSS context itself.
4585e111ed8SAndrew Rybchenko 	 */
4595e111ed8SAndrew Rybchenko 	*supportp = enp->en_hash_support;
4605e111ed8SAndrew Rybchenko 
4615e111ed8SAndrew Rybchenko 	return (0);
4625e111ed8SAndrew Rybchenko 
4635e111ed8SAndrew Rybchenko fail1:
4645e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4655e111ed8SAndrew Rybchenko 
4665e111ed8SAndrew Rybchenko 	return (rc);
4675e111ed8SAndrew Rybchenko }
4685e111ed8SAndrew Rybchenko 
4695e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_scale_default_support_get(__in efx_nic_t * enp,__out efx_rx_scale_context_type_t * typep)4705e111ed8SAndrew Rybchenko efx_rx_scale_default_support_get(
4715e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
4725e111ed8SAndrew Rybchenko 	__out		efx_rx_scale_context_type_t *typep)
4735e111ed8SAndrew Rybchenko {
4745e111ed8SAndrew Rybchenko 	efx_rc_t rc;
4755e111ed8SAndrew Rybchenko 
4765e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
4775e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
4785e111ed8SAndrew Rybchenko 
4795e111ed8SAndrew Rybchenko 	if (typep == NULL) {
4805e111ed8SAndrew Rybchenko 		rc = EINVAL;
4815e111ed8SAndrew Rybchenko 		goto fail1;
4825e111ed8SAndrew Rybchenko 	}
4835e111ed8SAndrew Rybchenko 
4845e111ed8SAndrew Rybchenko 	/*
4855e111ed8SAndrew Rybchenko 	 * Report the RSS support the client gets by default if it
4865e111ed8SAndrew Rybchenko 	 * does not allocate an RSS context itself.
4875e111ed8SAndrew Rybchenko 	 */
4885e111ed8SAndrew Rybchenko 	*typep = enp->en_rss_context_type;
4895e111ed8SAndrew Rybchenko 
4905e111ed8SAndrew Rybchenko 	return (0);
4915e111ed8SAndrew Rybchenko 
4925e111ed8SAndrew Rybchenko fail1:
4935e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
4945e111ed8SAndrew Rybchenko 
4955e111ed8SAndrew Rybchenko 	return (rc);
4965e111ed8SAndrew Rybchenko }
4975e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
4985e111ed8SAndrew Rybchenko 
4995e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
5005e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_scale_context_alloc(__in efx_nic_t * enp,__in efx_rx_scale_context_type_t type,__in uint32_t num_queues,__out uint32_t * rss_contextp)5015e111ed8SAndrew Rybchenko efx_rx_scale_context_alloc(
5025e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
5035e111ed8SAndrew Rybchenko 	__in		efx_rx_scale_context_type_t type,
5045e111ed8SAndrew Rybchenko 	__in		uint32_t num_queues,
5055e111ed8SAndrew Rybchenko 	__out		uint32_t *rss_contextp)
5065e111ed8SAndrew Rybchenko {
507bcdcec8cSIvan Malov 	uint32_t table_nentries = EFX_RSS_TBL_SIZE;
5085e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
5095e111ed8SAndrew Rybchenko 	efx_rc_t rc;
5105e111ed8SAndrew Rybchenko 
5115e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
5125e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
5135e111ed8SAndrew Rybchenko 
5145e111ed8SAndrew Rybchenko 	if (erxop->erxo_scale_context_alloc == NULL) {
5155e111ed8SAndrew Rybchenko 		rc = ENOTSUP;
5165e111ed8SAndrew Rybchenko 		goto fail1;
5175e111ed8SAndrew Rybchenko 	}
518e7ea5f30SIvan Malov 
519bcdcec8cSIvan Malov 	if (type == EFX_RX_SCALE_EVEN_SPREAD)
520bcdcec8cSIvan Malov 		table_nentries = 0;
521bcdcec8cSIvan Malov 
522e7ea5f30SIvan Malov 	if ((rc = erxop->erxo_scale_context_alloc(enp, type, num_queues,
523bcdcec8cSIvan Malov 			    table_nentries, rss_contextp)) != 0) {
524e7ea5f30SIvan Malov 		goto fail2;
525e7ea5f30SIvan Malov 	}
526e7ea5f30SIvan Malov 
527e7ea5f30SIvan Malov 	return (0);
528e7ea5f30SIvan Malov 
529e7ea5f30SIvan Malov fail2:
530e7ea5f30SIvan Malov 	EFSYS_PROBE(fail2);
531e7ea5f30SIvan Malov fail1:
532e7ea5f30SIvan Malov 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
533e7ea5f30SIvan Malov 	return (rc);
534e7ea5f30SIvan Malov }
535e7ea5f30SIvan Malov #endif	/* EFSYS_OPT_RX_SCALE */
536e7ea5f30SIvan Malov 
537e7ea5f30SIvan Malov #if EFSYS_OPT_RX_SCALE
538e7ea5f30SIvan Malov 	__checkReturn	efx_rc_t
efx_rx_scale_context_alloc_v2(__in efx_nic_t * enp,__in efx_rx_scale_context_type_t type,__in uint32_t num_queues,__in uint32_t table_nentries,__out uint32_t * rss_contextp)539e7ea5f30SIvan Malov efx_rx_scale_context_alloc_v2(
540e7ea5f30SIvan Malov 	__in		efx_nic_t *enp,
541e7ea5f30SIvan Malov 	__in		efx_rx_scale_context_type_t type,
542e7ea5f30SIvan Malov 	__in		uint32_t num_queues,
543e7ea5f30SIvan Malov 	__in		uint32_t table_nentries,
544e7ea5f30SIvan Malov 	__out		uint32_t *rss_contextp)
545e7ea5f30SIvan Malov {
546e7ea5f30SIvan Malov 	const efx_rx_ops_t *erxop = enp->en_erxop;
547e7ea5f30SIvan Malov 	efx_rc_t rc;
548e7ea5f30SIvan Malov 
549e7ea5f30SIvan Malov 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
550e7ea5f30SIvan Malov 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
551e7ea5f30SIvan Malov 
552e7ea5f30SIvan Malov 	if (erxop->erxo_scale_context_alloc == NULL) {
553e7ea5f30SIvan Malov 		rc = ENOTSUP;
554e7ea5f30SIvan Malov 		goto fail1;
555e7ea5f30SIvan Malov 	}
556e7ea5f30SIvan Malov 
5575e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_scale_context_alloc(enp, type,
558e7ea5f30SIvan Malov 			    num_queues, table_nentries, rss_contextp)) != 0) {
5595e111ed8SAndrew Rybchenko 		goto fail2;
5605e111ed8SAndrew Rybchenko 	}
5615e111ed8SAndrew Rybchenko 
5625e111ed8SAndrew Rybchenko 	return (0);
5635e111ed8SAndrew Rybchenko 
5645e111ed8SAndrew Rybchenko fail2:
5655e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
5665e111ed8SAndrew Rybchenko fail1:
5675e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5685e111ed8SAndrew Rybchenko 	return (rc);
5695e111ed8SAndrew Rybchenko }
5705e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
5715e111ed8SAndrew Rybchenko 
5725e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
5735e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_scale_context_free(__in efx_nic_t * enp,__in uint32_t rss_context)5745e111ed8SAndrew Rybchenko efx_rx_scale_context_free(
5755e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
5765e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context)
5775e111ed8SAndrew Rybchenko {
5785e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
5795e111ed8SAndrew Rybchenko 	efx_rc_t rc;
5805e111ed8SAndrew Rybchenko 
5815e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
5825e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
5835e111ed8SAndrew Rybchenko 
5845e111ed8SAndrew Rybchenko 	if (erxop->erxo_scale_context_free == NULL) {
5855e111ed8SAndrew Rybchenko 		rc = ENOTSUP;
5865e111ed8SAndrew Rybchenko 		goto fail1;
5875e111ed8SAndrew Rybchenko 	}
5885e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_scale_context_free(enp, rss_context)) != 0)
5895e111ed8SAndrew Rybchenko 		goto fail2;
5905e111ed8SAndrew Rybchenko 
5915e111ed8SAndrew Rybchenko 	return (0);
5925e111ed8SAndrew Rybchenko 
5935e111ed8SAndrew Rybchenko fail2:
5945e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
5955e111ed8SAndrew Rybchenko fail1:
5965e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
5975e111ed8SAndrew Rybchenko 	return (rc);
5985e111ed8SAndrew Rybchenko }
5995e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
6005e111ed8SAndrew Rybchenko 
6015e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
6025e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_scale_mode_set(__in efx_nic_t * enp,__in uint32_t rss_context,__in efx_rx_hash_alg_t alg,__in efx_rx_hash_type_t type,__in boolean_t insert)6035e111ed8SAndrew Rybchenko efx_rx_scale_mode_set(
6045e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
6055e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context,
6065e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_alg_t alg,
6075e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_type_t type,
6085e111ed8SAndrew Rybchenko 	__in		boolean_t insert)
6095e111ed8SAndrew Rybchenko {
6105e111ed8SAndrew Rybchenko 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
6115e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
6125e111ed8SAndrew Rybchenko 	efx_rx_hash_type_t type_check;
6135e111ed8SAndrew Rybchenko 	unsigned int i;
6145e111ed8SAndrew Rybchenko 	efx_rc_t rc;
6155e111ed8SAndrew Rybchenko 
6165e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
6175e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
6185e111ed8SAndrew Rybchenko 
6195e111ed8SAndrew Rybchenko 	/*
6205e111ed8SAndrew Rybchenko 	 * Legacy flags and modern bits cannot be
6215e111ed8SAndrew Rybchenko 	 * used at the same time in the hash type.
6225e111ed8SAndrew Rybchenko 	 */
6235e111ed8SAndrew Rybchenko 	if ((type & EFX_RX_HASH_LEGACY_MASK) &&
6245e111ed8SAndrew Rybchenko 	    (type & ~EFX_RX_HASH_LEGACY_MASK)) {
6255e111ed8SAndrew Rybchenko 		rc = EINVAL;
6265e111ed8SAndrew Rybchenko 		goto fail1;
6275e111ed8SAndrew Rybchenko 	}
6285e111ed8SAndrew Rybchenko 
6295e111ed8SAndrew Rybchenko 	/*
6305e111ed8SAndrew Rybchenko 	 * If RSS hash type is represented by additional bits
6315e111ed8SAndrew Rybchenko 	 * in the value, the latter need to be verified since
6325e111ed8SAndrew Rybchenko 	 * not all bit combinations are valid RSS modes. Also,
6335e111ed8SAndrew Rybchenko 	 * depending on the firmware, some valid combinations
6345e111ed8SAndrew Rybchenko 	 * may be unsupported. Discern additional bits in the
6355e111ed8SAndrew Rybchenko 	 * type value and try to recognise valid combinations.
6365e111ed8SAndrew Rybchenko 	 * If some bits remain unrecognised, report the error.
6375e111ed8SAndrew Rybchenko 	 */
6385e111ed8SAndrew Rybchenko 	type_check = type & ~EFX_RX_HASH_LEGACY_MASK;
6395e111ed8SAndrew Rybchenko 	if (type_check != 0) {
6405e111ed8SAndrew Rybchenko 		unsigned int type_flags[EFX_RX_HASH_NFLAGS];
6415e111ed8SAndrew Rybchenko 		unsigned int type_nflags;
6425e111ed8SAndrew Rybchenko 
6435e111ed8SAndrew Rybchenko 		rc = efx_rx_scale_hash_flags_get(enp, alg, type_flags,
6445e111ed8SAndrew Rybchenko 				    EFX_ARRAY_SIZE(type_flags), &type_nflags);
6455e111ed8SAndrew Rybchenko 		if (rc != 0)
6465e111ed8SAndrew Rybchenko 			goto fail2;
6475e111ed8SAndrew Rybchenko 
6485e111ed8SAndrew Rybchenko 		for (i = 0; i < type_nflags; ++i) {
6495e111ed8SAndrew Rybchenko 			if ((type_check & type_flags[i]) == type_flags[i])
6505e111ed8SAndrew Rybchenko 				type_check &= ~(type_flags[i]);
6515e111ed8SAndrew Rybchenko 		}
6525e111ed8SAndrew Rybchenko 
6535e111ed8SAndrew Rybchenko 		if (type_check != 0) {
6545e111ed8SAndrew Rybchenko 			rc = EINVAL;
6555e111ed8SAndrew Rybchenko 			goto fail3;
6565e111ed8SAndrew Rybchenko 		}
6575e111ed8SAndrew Rybchenko 	}
6585e111ed8SAndrew Rybchenko 
6595e111ed8SAndrew Rybchenko 	/*
6605e111ed8SAndrew Rybchenko 	 * Translate EFX_RX_HASH() flags to their legacy counterparts
6615e111ed8SAndrew Rybchenko 	 * provided that the FW claims no support for additional modes.
6625e111ed8SAndrew Rybchenko 	 */
6635e111ed8SAndrew Rybchenko 	if (encp->enc_rx_scale_additional_modes_supported == B_FALSE) {
6645e111ed8SAndrew Rybchenko 		efx_rx_hash_type_t t_ipv4 = EFX_RX_HASH(IPV4, 2TUPLE) |
6655e111ed8SAndrew Rybchenko 					    EFX_RX_HASH(IPV4_TCP, 2TUPLE);
6665e111ed8SAndrew Rybchenko 		efx_rx_hash_type_t t_ipv6 = EFX_RX_HASH(IPV6, 2TUPLE) |
6675e111ed8SAndrew Rybchenko 					    EFX_RX_HASH(IPV6_TCP, 2TUPLE);
6685e111ed8SAndrew Rybchenko 		efx_rx_hash_type_t t_ipv4_tcp = EFX_RX_HASH(IPV4_TCP, 4TUPLE);
6695e111ed8SAndrew Rybchenko 		efx_rx_hash_type_t t_ipv6_tcp = EFX_RX_HASH(IPV6_TCP, 4TUPLE);
6705e111ed8SAndrew Rybchenko 
6715e111ed8SAndrew Rybchenko 		if ((type & t_ipv4) == t_ipv4)
6725e111ed8SAndrew Rybchenko 			type |= EFX_RX_HASH_IPV4;
6735e111ed8SAndrew Rybchenko 		if ((type & t_ipv6) == t_ipv6)
6745e111ed8SAndrew Rybchenko 			type |= EFX_RX_HASH_IPV6;
6755e111ed8SAndrew Rybchenko 
6765e111ed8SAndrew Rybchenko 		if (encp->enc_rx_scale_l4_hash_supported == B_TRUE) {
6775e111ed8SAndrew Rybchenko 			if ((type & t_ipv4_tcp) == t_ipv4_tcp)
6785e111ed8SAndrew Rybchenko 				type |= EFX_RX_HASH_TCPIPV4;
6795e111ed8SAndrew Rybchenko 			if ((type & t_ipv6_tcp) == t_ipv6_tcp)
6805e111ed8SAndrew Rybchenko 				type |= EFX_RX_HASH_TCPIPV6;
6815e111ed8SAndrew Rybchenko 		}
6825e111ed8SAndrew Rybchenko 
6835e111ed8SAndrew Rybchenko 		type &= EFX_RX_HASH_LEGACY_MASK;
6845e111ed8SAndrew Rybchenko 	}
6855e111ed8SAndrew Rybchenko 
6865e111ed8SAndrew Rybchenko 	if (erxop->erxo_scale_mode_set != NULL) {
6875e111ed8SAndrew Rybchenko 		if ((rc = erxop->erxo_scale_mode_set(enp, rss_context, alg,
6885e111ed8SAndrew Rybchenko 			    type, insert)) != 0)
6895e111ed8SAndrew Rybchenko 			goto fail4;
6905e111ed8SAndrew Rybchenko 	}
6915e111ed8SAndrew Rybchenko 
6925e111ed8SAndrew Rybchenko 	return (0);
6935e111ed8SAndrew Rybchenko 
6945e111ed8SAndrew Rybchenko fail4:
6955e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail4);
6965e111ed8SAndrew Rybchenko fail3:
6975e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail3);
6985e111ed8SAndrew Rybchenko fail2:
6995e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
7005e111ed8SAndrew Rybchenko fail1:
7015e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7025e111ed8SAndrew Rybchenko 	return (rc);
7035e111ed8SAndrew Rybchenko }
7045e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
7055e111ed8SAndrew Rybchenko 
7065e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
7075e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_scale_key_set(__in efx_nic_t * enp,__in uint32_t rss_context,__in_ecount (n)uint8_t * key,__in size_t n)7085e111ed8SAndrew Rybchenko efx_rx_scale_key_set(
7095e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
7105e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context,
7115e111ed8SAndrew Rybchenko 	__in_ecount(n)	uint8_t *key,
7125e111ed8SAndrew Rybchenko 	__in		size_t n)
7135e111ed8SAndrew Rybchenko {
7145e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
7155e111ed8SAndrew Rybchenko 	efx_rc_t rc;
7165e111ed8SAndrew Rybchenko 
7175e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
7185e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
7195e111ed8SAndrew Rybchenko 
7205e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_scale_key_set(enp, rss_context, key, n)) != 0)
7215e111ed8SAndrew Rybchenko 		goto fail1;
7225e111ed8SAndrew Rybchenko 
7235e111ed8SAndrew Rybchenko 	return (0);
7245e111ed8SAndrew Rybchenko 
7255e111ed8SAndrew Rybchenko fail1:
7265e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7275e111ed8SAndrew Rybchenko 
7285e111ed8SAndrew Rybchenko 	return (rc);
7295e111ed8SAndrew Rybchenko }
7305e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
7315e111ed8SAndrew Rybchenko 
7325e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
7335e111ed8SAndrew Rybchenko 	__checkReturn		efx_rc_t
efx_rx_scale_tbl_set(__in efx_nic_t * enp,__in uint32_t rss_context,__in_ecount (nentries)unsigned int * table,__in size_t nentries)7345e111ed8SAndrew Rybchenko efx_rx_scale_tbl_set(
7355e111ed8SAndrew Rybchenko 	__in			efx_nic_t *enp,
7365e111ed8SAndrew Rybchenko 	__in			uint32_t rss_context,
7377a71c15dSIvan Malov 	__in_ecount(nentries)	unsigned int *table,
7387a71c15dSIvan Malov 	__in			size_t nentries)
7395e111ed8SAndrew Rybchenko {
7405e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
7415e111ed8SAndrew Rybchenko 	efx_rc_t rc;
7425e111ed8SAndrew Rybchenko 
7435e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
7445e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
7455e111ed8SAndrew Rybchenko 
7467a71c15dSIvan Malov 	if ((rc = erxop->erxo_scale_tbl_set(enp, rss_context, table,
7477a71c15dSIvan Malov 		    nentries)) != 0)
7485e111ed8SAndrew Rybchenko 		goto fail1;
7495e111ed8SAndrew Rybchenko 
7505e111ed8SAndrew Rybchenko 	return (0);
7515e111ed8SAndrew Rybchenko 
7525e111ed8SAndrew Rybchenko fail1:
7535e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
7545e111ed8SAndrew Rybchenko 
7555e111ed8SAndrew Rybchenko 	return (rc);
7565e111ed8SAndrew Rybchenko }
7575e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
7585e111ed8SAndrew Rybchenko 
7595e111ed8SAndrew Rybchenko 				void
efx_rx_qpost(__in efx_rxq_t * erp,__in_ecount (ndescs)efsys_dma_addr_t * addrp,__in size_t size,__in unsigned int ndescs,__in unsigned int completed,__in unsigned int added)7605e111ed8SAndrew Rybchenko efx_rx_qpost(
7615e111ed8SAndrew Rybchenko 	__in			efx_rxq_t *erp,
7625e111ed8SAndrew Rybchenko 	__in_ecount(ndescs)	efsys_dma_addr_t *addrp,
7635e111ed8SAndrew Rybchenko 	__in			size_t size,
7645e111ed8SAndrew Rybchenko 	__in			unsigned int ndescs,
7655e111ed8SAndrew Rybchenko 	__in			unsigned int completed,
7665e111ed8SAndrew Rybchenko 	__in			unsigned int added)
7675e111ed8SAndrew Rybchenko {
7685e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
7695e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
7705e111ed8SAndrew Rybchenko 
7715e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
7725e111ed8SAndrew Rybchenko 	EFSYS_ASSERT(erp->er_buf_size == 0 || size == erp->er_buf_size);
7735e111ed8SAndrew Rybchenko 
7745e111ed8SAndrew Rybchenko 	erxop->erxo_qpost(erp, addrp, size, ndescs, completed, added);
7755e111ed8SAndrew Rybchenko }
7765e111ed8SAndrew Rybchenko 
7775e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
7785e111ed8SAndrew Rybchenko 
7795e111ed8SAndrew Rybchenko 			void
efx_rx_qpush_ps_credits(__in efx_rxq_t * erp)7805e111ed8SAndrew Rybchenko efx_rx_qpush_ps_credits(
7815e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp)
7825e111ed8SAndrew Rybchenko {
7835e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
7845e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
7855e111ed8SAndrew Rybchenko 
7865e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
7875e111ed8SAndrew Rybchenko 
7885e111ed8SAndrew Rybchenko 	erxop->erxo_qpush_ps_credits(erp);
7895e111ed8SAndrew Rybchenko }
7905e111ed8SAndrew Rybchenko 
7915e111ed8SAndrew Rybchenko 	__checkReturn	uint8_t *
efx_rx_qps_packet_info(__in efx_rxq_t * erp,__in uint8_t * buffer,__in uint32_t buffer_length,__in uint32_t current_offset,__out uint16_t * lengthp,__out uint32_t * next_offsetp,__out uint32_t * timestamp)7925e111ed8SAndrew Rybchenko efx_rx_qps_packet_info(
7935e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
7945e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer,
7955e111ed8SAndrew Rybchenko 	__in		uint32_t buffer_length,
7965e111ed8SAndrew Rybchenko 	__in		uint32_t current_offset,
7975e111ed8SAndrew Rybchenko 	__out		uint16_t *lengthp,
7985e111ed8SAndrew Rybchenko 	__out		uint32_t *next_offsetp,
7995e111ed8SAndrew Rybchenko 	__out		uint32_t *timestamp)
8005e111ed8SAndrew Rybchenko {
8015e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
8025e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
8035e111ed8SAndrew Rybchenko 
8045e111ed8SAndrew Rybchenko 	return (erxop->erxo_qps_packet_info(erp, buffer,
8055e111ed8SAndrew Rybchenko 		buffer_length, current_offset, lengthp,
8065e111ed8SAndrew Rybchenko 		next_offsetp, timestamp));
8075e111ed8SAndrew Rybchenko }
8085e111ed8SAndrew Rybchenko 
8095e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_PACKED_STREAM */
8105e111ed8SAndrew Rybchenko 
8115e111ed8SAndrew Rybchenko 			void
efx_rx_qpush(__in efx_rxq_t * erp,__in unsigned int added,__inout unsigned int * pushedp)8125e111ed8SAndrew Rybchenko efx_rx_qpush(
8135e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
8145e111ed8SAndrew Rybchenko 	__in		unsigned int added,
8155e111ed8SAndrew Rybchenko 	__inout		unsigned int *pushedp)
8165e111ed8SAndrew Rybchenko {
8175e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
8185e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
8195e111ed8SAndrew Rybchenko 
8205e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
8215e111ed8SAndrew Rybchenko 
8225e111ed8SAndrew Rybchenko 	erxop->erxo_qpush(erp, added, pushedp);
8235e111ed8SAndrew Rybchenko }
8245e111ed8SAndrew Rybchenko 
8255e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_qflush(__in efx_rxq_t * erp)8265e111ed8SAndrew Rybchenko efx_rx_qflush(
8275e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp)
8285e111ed8SAndrew Rybchenko {
8295e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
8305e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
8315e111ed8SAndrew Rybchenko 	efx_rc_t rc;
8325e111ed8SAndrew Rybchenko 
8335e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
8345e111ed8SAndrew Rybchenko 
8355e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_qflush(erp)) != 0)
8365e111ed8SAndrew Rybchenko 		goto fail1;
8375e111ed8SAndrew Rybchenko 
8385e111ed8SAndrew Rybchenko 	return (0);
8395e111ed8SAndrew Rybchenko 
8405e111ed8SAndrew Rybchenko fail1:
8415e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
8425e111ed8SAndrew Rybchenko 
8435e111ed8SAndrew Rybchenko 	return (rc);
8445e111ed8SAndrew Rybchenko }
8455e111ed8SAndrew Rybchenko 
8465e111ed8SAndrew Rybchenko 	__checkReturn	size_t
efx_rxq_size(__in const efx_nic_t * enp,__in unsigned int ndescs)8475e111ed8SAndrew Rybchenko efx_rxq_size(
8485e111ed8SAndrew Rybchenko 	__in	const efx_nic_t *enp,
8495e111ed8SAndrew Rybchenko 	__in	unsigned int ndescs)
8505e111ed8SAndrew Rybchenko {
8515e111ed8SAndrew Rybchenko 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
8525e111ed8SAndrew Rybchenko 
8535e111ed8SAndrew Rybchenko 	return (ndescs * encp->enc_rx_desc_size);
8545e111ed8SAndrew Rybchenko }
8555e111ed8SAndrew Rybchenko 
8565e111ed8SAndrew Rybchenko 	__checkReturn	unsigned int
efx_rxq_nbufs(__in const efx_nic_t * enp,__in unsigned int ndescs)8575e111ed8SAndrew Rybchenko efx_rxq_nbufs(
8585e111ed8SAndrew Rybchenko 	__in	const efx_nic_t *enp,
8595e111ed8SAndrew Rybchenko 	__in	unsigned int ndescs)
8605e111ed8SAndrew Rybchenko {
8615e111ed8SAndrew Rybchenko 	return (EFX_DIV_ROUND_UP(efx_rxq_size(enp, ndescs), EFX_BUF_SIZE));
8625e111ed8SAndrew Rybchenko }
8635e111ed8SAndrew Rybchenko 
8645e111ed8SAndrew Rybchenko 			void
efx_rx_qenable(__in efx_rxq_t * erp)8655e111ed8SAndrew Rybchenko efx_rx_qenable(
8665e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp)
8675e111ed8SAndrew Rybchenko {
8685e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
8695e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
8705e111ed8SAndrew Rybchenko 
8715e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
8725e111ed8SAndrew Rybchenko 
8735e111ed8SAndrew Rybchenko 	erxop->erxo_qenable(erp);
8745e111ed8SAndrew Rybchenko }
8755e111ed8SAndrew Rybchenko 
8765e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
efx_rx_qcreate_internal(__in efx_nic_t * enp,__in unsigned int index,__in unsigned int label,__in efx_rxq_type_t type,__in_opt const efx_rxq_type_data_t * type_data,__in efsys_mem_t * esmp,__in size_t ndescs,__in uint32_t id,__in unsigned int flags,__in efx_evq_t * eep,__deref_out efx_rxq_t ** erpp)8775e111ed8SAndrew Rybchenko efx_rx_qcreate_internal(
8785e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
8795e111ed8SAndrew Rybchenko 	__in		unsigned int index,
8805e111ed8SAndrew Rybchenko 	__in		unsigned int label,
8815e111ed8SAndrew Rybchenko 	__in		efx_rxq_type_t type,
8825e111ed8SAndrew Rybchenko 	__in_opt	const efx_rxq_type_data_t *type_data,
8835e111ed8SAndrew Rybchenko 	__in		efsys_mem_t *esmp,
8845e111ed8SAndrew Rybchenko 	__in		size_t ndescs,
8855e111ed8SAndrew Rybchenko 	__in		uint32_t id,
8865e111ed8SAndrew Rybchenko 	__in		unsigned int flags,
8875e111ed8SAndrew Rybchenko 	__in		efx_evq_t *eep,
8885e111ed8SAndrew Rybchenko 	__deref_out	efx_rxq_t **erpp)
8895e111ed8SAndrew Rybchenko {
8905e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
8915e111ed8SAndrew Rybchenko 	efx_rxq_t *erp;
8925e111ed8SAndrew Rybchenko 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
8935e111ed8SAndrew Rybchenko 	efx_rc_t rc;
8945e111ed8SAndrew Rybchenko 
8955e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
8965e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX);
8975e111ed8SAndrew Rybchenko 
8987d382a05SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit);
8997d382a05SAndrew Rybchenko 
9005e111ed8SAndrew Rybchenko 	EFSYS_ASSERT(ISP2(encp->enc_rxq_max_ndescs));
9015e111ed8SAndrew Rybchenko 	EFSYS_ASSERT(ISP2(encp->enc_rxq_min_ndescs));
9025e111ed8SAndrew Rybchenko 
903e9b9b2e5SAndrew Rybchenko 	if (index >= encp->enc_rxq_limit) {
904e9b9b2e5SAndrew Rybchenko 		rc = EINVAL;
905e9b9b2e5SAndrew Rybchenko 		goto fail1;
906e9b9b2e5SAndrew Rybchenko 	}
907e9b9b2e5SAndrew Rybchenko 
9085e111ed8SAndrew Rybchenko 	if (!ISP2(ndescs) ||
9095e111ed8SAndrew Rybchenko 	    ndescs < encp->enc_rxq_min_ndescs ||
9105e111ed8SAndrew Rybchenko 	    ndescs > encp->enc_rxq_max_ndescs) {
9115e111ed8SAndrew Rybchenko 		rc = EINVAL;
912e9b9b2e5SAndrew Rybchenko 		goto fail2;
9135e111ed8SAndrew Rybchenko 	}
9145e111ed8SAndrew Rybchenko 
9155e111ed8SAndrew Rybchenko 	/* Allocate an RXQ object */
9165e111ed8SAndrew Rybchenko 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_rxq_t), erp);
9175e111ed8SAndrew Rybchenko 
9185e111ed8SAndrew Rybchenko 	if (erp == NULL) {
9195e111ed8SAndrew Rybchenko 		rc = ENOMEM;
920e9b9b2e5SAndrew Rybchenko 		goto fail3;
9215e111ed8SAndrew Rybchenko 	}
9225e111ed8SAndrew Rybchenko 
9235e111ed8SAndrew Rybchenko 	erp->er_magic = EFX_RXQ_MAGIC;
9245e111ed8SAndrew Rybchenko 	erp->er_enp = enp;
9255e111ed8SAndrew Rybchenko 	erp->er_index = index;
9265e111ed8SAndrew Rybchenko 	erp->er_mask = ndescs - 1;
9275e111ed8SAndrew Rybchenko 	erp->er_esmp = esmp;
9285e111ed8SAndrew Rybchenko 
9295e111ed8SAndrew Rybchenko 	if ((rc = erxop->erxo_qcreate(enp, index, label, type, type_data, esmp,
9305e111ed8SAndrew Rybchenko 	    ndescs, id, flags, eep, erp)) != 0)
931e9b9b2e5SAndrew Rybchenko 		goto fail4;
9325e111ed8SAndrew Rybchenko 
933f784cdc5SAndrew Rybchenko 	/* Sanity check queue creation result */
934f784cdc5SAndrew Rybchenko 	if (flags & EFX_RXQ_FLAG_RSS_HASH) {
935f784cdc5SAndrew Rybchenko 		const efx_rx_prefix_layout_t *erplp = &erp->er_prefix_layout;
936f784cdc5SAndrew Rybchenko 		const efx_rx_prefix_field_info_t *rss_hash_field;
937f784cdc5SAndrew Rybchenko 
938f784cdc5SAndrew Rybchenko 		rss_hash_field =
939f784cdc5SAndrew Rybchenko 		    &erplp->erpl_fields[EFX_RX_PREFIX_FIELD_RSS_HASH];
94080d18a95SArtemii Morozov 		if (rss_hash_field->erpfi_width_bits == 0) {
94180d18a95SArtemii Morozov 			rc = ENOTSUP;
942f784cdc5SAndrew Rybchenko 			goto fail5;
943f784cdc5SAndrew Rybchenko 		}
94480d18a95SArtemii Morozov 	}
945f784cdc5SAndrew Rybchenko 
946*e5e5c127SArtemii Morozov 	if (flags & EFX_RXQ_FLAG_VLAN_STRIPPED_TCI) {
947*e5e5c127SArtemii Morozov 		const efx_rx_prefix_layout_t *erplp = &erp->er_prefix_layout;
948*e5e5c127SArtemii Morozov 		const efx_rx_prefix_field_info_t *vlan_tci_field;
949*e5e5c127SArtemii Morozov 
950*e5e5c127SArtemii Morozov 		vlan_tci_field =
951*e5e5c127SArtemii Morozov 		    &erplp->erpl_fields[EFX_RX_PREFIX_FIELD_VLAN_STRIP_TCI];
952*e5e5c127SArtemii Morozov 		if (vlan_tci_field->erpfi_width_bits == 0) {
953*e5e5c127SArtemii Morozov 			rc = ENOTSUP;
954*e5e5c127SArtemii Morozov 			goto fail6;
955*e5e5c127SArtemii Morozov 		}
956*e5e5c127SArtemii Morozov 	}
957*e5e5c127SArtemii Morozov 
9585e111ed8SAndrew Rybchenko 	enp->en_rx_qcount++;
9595e111ed8SAndrew Rybchenko 	*erpp = erp;
9605e111ed8SAndrew Rybchenko 
9615e111ed8SAndrew Rybchenko 	return (0);
9625e111ed8SAndrew Rybchenko 
963*e5e5c127SArtemii Morozov fail6:
964*e5e5c127SArtemii Morozov 	EFSYS_PROBE(fail6);
965f784cdc5SAndrew Rybchenko fail5:
966f784cdc5SAndrew Rybchenko 	EFSYS_PROBE(fail5);
967f784cdc5SAndrew Rybchenko 
968f784cdc5SAndrew Rybchenko 	erxop->erxo_qdestroy(erp);
969e9b9b2e5SAndrew Rybchenko fail4:
970e9b9b2e5SAndrew Rybchenko 	EFSYS_PROBE(fail4);
9715e111ed8SAndrew Rybchenko 
9725e111ed8SAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
973e9b9b2e5SAndrew Rybchenko fail3:
974e9b9b2e5SAndrew Rybchenko 	EFSYS_PROBE(fail3);
9755e111ed8SAndrew Rybchenko fail2:
9765e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
9775e111ed8SAndrew Rybchenko fail1:
9785e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
9795e111ed8SAndrew Rybchenko 
9805e111ed8SAndrew Rybchenko 	return (rc);
9815e111ed8SAndrew Rybchenko }
9825e111ed8SAndrew Rybchenko 
9835e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_qcreate(__in efx_nic_t * enp,__in unsigned int index,__in unsigned int label,__in efx_rxq_type_t type,__in size_t buf_size,__in efsys_mem_t * esmp,__in size_t ndescs,__in uint32_t id,__in unsigned int flags,__in efx_evq_t * eep,__deref_out efx_rxq_t ** erpp)9845e111ed8SAndrew Rybchenko efx_rx_qcreate(
9855e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
9865e111ed8SAndrew Rybchenko 	__in		unsigned int index,
9875e111ed8SAndrew Rybchenko 	__in		unsigned int label,
9885e111ed8SAndrew Rybchenko 	__in		efx_rxq_type_t type,
9895e111ed8SAndrew Rybchenko 	__in		size_t buf_size,
9905e111ed8SAndrew Rybchenko 	__in		efsys_mem_t *esmp,
9915e111ed8SAndrew Rybchenko 	__in		size_t ndescs,
9925e111ed8SAndrew Rybchenko 	__in		uint32_t id,
9935e111ed8SAndrew Rybchenko 	__in		unsigned int flags,
9945e111ed8SAndrew Rybchenko 	__in		efx_evq_t *eep,
9955e111ed8SAndrew Rybchenko 	__deref_out	efx_rxq_t **erpp)
9965e111ed8SAndrew Rybchenko {
99761b3e9e7SIvan Malov 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
9985e111ed8SAndrew Rybchenko 	efx_rxq_type_data_t type_data;
99961b3e9e7SIvan Malov 	efx_rc_t rc;
100061b3e9e7SIvan Malov 
100161b3e9e7SIvan Malov 	if (buf_size > encp->enc_rx_dma_desc_size_max) {
100261b3e9e7SIvan Malov 		rc = EINVAL;
100361b3e9e7SIvan Malov 		goto fail1;
100461b3e9e7SIvan Malov 	}
10055e111ed8SAndrew Rybchenko 
10065e111ed8SAndrew Rybchenko 	memset(&type_data, 0, sizeof (type_data));
10075e111ed8SAndrew Rybchenko 
10085e111ed8SAndrew Rybchenko 	type_data.ertd_default.ed_buf_size = buf_size;
10095e111ed8SAndrew Rybchenko 
10105e111ed8SAndrew Rybchenko 	return efx_rx_qcreate_internal(enp, index, label, type, &type_data,
10115e111ed8SAndrew Rybchenko 	    esmp, ndescs, id, flags, eep, erpp);
101261b3e9e7SIvan Malov 
101361b3e9e7SIvan Malov fail1:
101461b3e9e7SIvan Malov 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
101561b3e9e7SIvan Malov 
101661b3e9e7SIvan Malov 	return (rc);
10175e111ed8SAndrew Rybchenko }
10185e111ed8SAndrew Rybchenko 
10195e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
10205e111ed8SAndrew Rybchenko 
10215e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_qcreate_packed_stream(__in efx_nic_t * enp,__in unsigned int index,__in unsigned int label,__in uint32_t ps_buf_size,__in efsys_mem_t * esmp,__in size_t ndescs,__in efx_evq_t * eep,__deref_out efx_rxq_t ** erpp)10225e111ed8SAndrew Rybchenko efx_rx_qcreate_packed_stream(
10235e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
10245e111ed8SAndrew Rybchenko 	__in		unsigned int index,
10255e111ed8SAndrew Rybchenko 	__in		unsigned int label,
10265e111ed8SAndrew Rybchenko 	__in		uint32_t ps_buf_size,
10275e111ed8SAndrew Rybchenko 	__in		efsys_mem_t *esmp,
10285e111ed8SAndrew Rybchenko 	__in		size_t ndescs,
10295e111ed8SAndrew Rybchenko 	__in		efx_evq_t *eep,
10305e111ed8SAndrew Rybchenko 	__deref_out	efx_rxq_t **erpp)
10315e111ed8SAndrew Rybchenko {
10325e111ed8SAndrew Rybchenko 	efx_rxq_type_data_t type_data;
10335e111ed8SAndrew Rybchenko 
10345e111ed8SAndrew Rybchenko 	memset(&type_data, 0, sizeof (type_data));
10355e111ed8SAndrew Rybchenko 
10365e111ed8SAndrew Rybchenko 	type_data.ertd_packed_stream.eps_buf_size = ps_buf_size;
10375e111ed8SAndrew Rybchenko 
10385e111ed8SAndrew Rybchenko 	return efx_rx_qcreate_internal(enp, index, label,
10395e111ed8SAndrew Rybchenko 	    EFX_RXQ_TYPE_PACKED_STREAM, &type_data, esmp, ndescs,
10405e111ed8SAndrew Rybchenko 	    0 /* id unused on EF10 */, EFX_RXQ_FLAG_NONE, eep, erpp);
10415e111ed8SAndrew Rybchenko }
10425e111ed8SAndrew Rybchenko 
10435e111ed8SAndrew Rybchenko #endif
10445e111ed8SAndrew Rybchenko 
10455e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_ES_SUPER_BUFFER
10465e111ed8SAndrew Rybchenko 
10475e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_qcreate_es_super_buffer(__in efx_nic_t * enp,__in unsigned int index,__in unsigned int label,__in uint32_t n_bufs_per_desc,__in uint32_t max_dma_len,__in uint32_t buf_stride,__in uint32_t hol_block_timeout,__in efsys_mem_t * esmp,__in size_t ndescs,__in unsigned int flags,__in efx_evq_t * eep,__deref_out efx_rxq_t ** erpp)10485e111ed8SAndrew Rybchenko efx_rx_qcreate_es_super_buffer(
10495e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
10505e111ed8SAndrew Rybchenko 	__in		unsigned int index,
10515e111ed8SAndrew Rybchenko 	__in		unsigned int label,
10525e111ed8SAndrew Rybchenko 	__in		uint32_t n_bufs_per_desc,
10535e111ed8SAndrew Rybchenko 	__in		uint32_t max_dma_len,
10545e111ed8SAndrew Rybchenko 	__in		uint32_t buf_stride,
10555e111ed8SAndrew Rybchenko 	__in		uint32_t hol_block_timeout,
10565e111ed8SAndrew Rybchenko 	__in		efsys_mem_t *esmp,
10575e111ed8SAndrew Rybchenko 	__in		size_t ndescs,
10585e111ed8SAndrew Rybchenko 	__in		unsigned int flags,
10595e111ed8SAndrew Rybchenko 	__in		efx_evq_t *eep,
10605e111ed8SAndrew Rybchenko 	__deref_out	efx_rxq_t **erpp)
10615e111ed8SAndrew Rybchenko {
10625e111ed8SAndrew Rybchenko 	efx_rc_t rc;
10635e111ed8SAndrew Rybchenko 	efx_rxq_type_data_t type_data;
10645e111ed8SAndrew Rybchenko 
10655e111ed8SAndrew Rybchenko 	if (hol_block_timeout > EFX_RXQ_ES_SUPER_BUFFER_HOL_BLOCK_MAX) {
10665e111ed8SAndrew Rybchenko 		rc = EINVAL;
10675e111ed8SAndrew Rybchenko 		goto fail1;
10685e111ed8SAndrew Rybchenko 	}
10695e111ed8SAndrew Rybchenko 
10705e111ed8SAndrew Rybchenko 	memset(&type_data, 0, sizeof (type_data));
10715e111ed8SAndrew Rybchenko 
10725e111ed8SAndrew Rybchenko 	type_data.ertd_es_super_buffer.eessb_bufs_per_desc = n_bufs_per_desc;
10735e111ed8SAndrew Rybchenko 	type_data.ertd_es_super_buffer.eessb_max_dma_len = max_dma_len;
10745e111ed8SAndrew Rybchenko 	type_data.ertd_es_super_buffer.eessb_buf_stride = buf_stride;
10755e111ed8SAndrew Rybchenko 	type_data.ertd_es_super_buffer.eessb_hol_block_timeout =
10765e111ed8SAndrew Rybchenko 	    hol_block_timeout;
10775e111ed8SAndrew Rybchenko 
10785e111ed8SAndrew Rybchenko 	rc = efx_rx_qcreate_internal(enp, index, label,
10795e111ed8SAndrew Rybchenko 	    EFX_RXQ_TYPE_ES_SUPER_BUFFER, &type_data, esmp, ndescs,
10805e111ed8SAndrew Rybchenko 	    0 /* id unused on EF10 */, flags, eep, erpp);
10815e111ed8SAndrew Rybchenko 	if (rc != 0)
10825e111ed8SAndrew Rybchenko 		goto fail2;
10835e111ed8SAndrew Rybchenko 
10845e111ed8SAndrew Rybchenko 	return (0);
10855e111ed8SAndrew Rybchenko 
10865e111ed8SAndrew Rybchenko fail2:
10875e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
10885e111ed8SAndrew Rybchenko fail1:
10895e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
10905e111ed8SAndrew Rybchenko 
10915e111ed8SAndrew Rybchenko 	return (rc);
10925e111ed8SAndrew Rybchenko }
10935e111ed8SAndrew Rybchenko 
10945e111ed8SAndrew Rybchenko #endif
10955e111ed8SAndrew Rybchenko 
10965e111ed8SAndrew Rybchenko 
10975e111ed8SAndrew Rybchenko 			void
efx_rx_qdestroy(__in efx_rxq_t * erp)10985e111ed8SAndrew Rybchenko efx_rx_qdestroy(
10995e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp)
11005e111ed8SAndrew Rybchenko {
11015e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
11025e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
11035e111ed8SAndrew Rybchenko 
11045e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
11055e111ed8SAndrew Rybchenko 
11067d382a05SAndrew Rybchenko 	EFSYS_ASSERT(enp->en_rx_qcount != 0);
11077d382a05SAndrew Rybchenko 	--enp->en_rx_qcount;
11087d382a05SAndrew Rybchenko 
11095e111ed8SAndrew Rybchenko 	erxop->erxo_qdestroy(erp);
11106c055549SAndrew Rybchenko 
11116c055549SAndrew Rybchenko 	/* Free the RXQ object */
11126c055549SAndrew Rybchenko 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp);
11135e111ed8SAndrew Rybchenko }
11145e111ed8SAndrew Rybchenko 
11155e111ed8SAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_pseudo_hdr_pkt_length_get(__in efx_rxq_t * erp,__in uint8_t * buffer,__out uint16_t * lengthp)11165e111ed8SAndrew Rybchenko efx_pseudo_hdr_pkt_length_get(
11175e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
11185e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer,
11195e111ed8SAndrew Rybchenko 	__out		uint16_t *lengthp)
11205e111ed8SAndrew Rybchenko {
11215e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
11225e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
11235e111ed8SAndrew Rybchenko 
11245e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
11255e111ed8SAndrew Rybchenko 
11265e111ed8SAndrew Rybchenko 	return (erxop->erxo_prefix_pktlen(enp, buffer, lengthp));
11275e111ed8SAndrew Rybchenko }
11285e111ed8SAndrew Rybchenko 
11295e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
11305e111ed8SAndrew Rybchenko 	__checkReturn	uint32_t
efx_pseudo_hdr_hash_get(__in efx_rxq_t * erp,__in efx_rx_hash_alg_t func,__in uint8_t * buffer)11315e111ed8SAndrew Rybchenko efx_pseudo_hdr_hash_get(
11325e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
11335e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_alg_t func,
11345e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer)
11355e111ed8SAndrew Rybchenko {
11365e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
11375e111ed8SAndrew Rybchenko 	const efx_rx_ops_t *erxop = enp->en_erxop;
11385e111ed8SAndrew Rybchenko 
11395e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
11405e111ed8SAndrew Rybchenko 
11415e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(enp->en_hash_support, ==, EFX_RX_HASH_AVAILABLE);
11425e111ed8SAndrew Rybchenko 	return (erxop->erxo_prefix_hash(enp, func, buffer));
11435e111ed8SAndrew Rybchenko }
11445e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
11455e111ed8SAndrew Rybchenko 
11466bba823fSAndrew Rybchenko 	__checkReturn	efx_rc_t
efx_rx_prefix_get_layout(__in const efx_rxq_t * erp,__out efx_rx_prefix_layout_t * erplp)11476bba823fSAndrew Rybchenko efx_rx_prefix_get_layout(
11486bba823fSAndrew Rybchenko 	__in		const efx_rxq_t *erp,
11496bba823fSAndrew Rybchenko 	__out		efx_rx_prefix_layout_t *erplp)
11506bba823fSAndrew Rybchenko {
11516bba823fSAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
11526bba823fSAndrew Rybchenko 
11536bba823fSAndrew Rybchenko 	*erplp = erp->er_prefix_layout;
11546bba823fSAndrew Rybchenko 
11556bba823fSAndrew Rybchenko 	return (0);
11566bba823fSAndrew Rybchenko }
11576bba823fSAndrew Rybchenko 
11585e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
11595e111ed8SAndrew Rybchenko 
11605e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_init(__in efx_nic_t * enp)11615e111ed8SAndrew Rybchenko siena_rx_init(
11625e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp)
11635e111ed8SAndrew Rybchenko {
11645e111ed8SAndrew Rybchenko 	efx_oword_t oword;
11655e111ed8SAndrew Rybchenko 	unsigned int index;
11665e111ed8SAndrew Rybchenko 
11675e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
11685e111ed8SAndrew Rybchenko 
11695e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_DESC_PUSH_EN, 0);
11705e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 0);
11715e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, 0);
11725e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, 0);
11735e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, 0);
11745e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_USR_BUF_SIZE, 0x3000 / 32);
11755e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
11765e111ed8SAndrew Rybchenko 
11775e111ed8SAndrew Rybchenko 	/* Zero the RSS table */
11785e111ed8SAndrew Rybchenko 	for (index = 0; index < FR_BZ_RX_INDIRECTION_TBL_ROWS;
11795e111ed8SAndrew Rybchenko 	    index++) {
11805e111ed8SAndrew Rybchenko 		EFX_ZERO_OWORD(oword);
11815e111ed8SAndrew Rybchenko 		EFX_BAR_TBL_WRITEO(enp, FR_BZ_RX_INDIRECTION_TBL,
11825e111ed8SAndrew Rybchenko 				    index, &oword, B_TRUE);
11835e111ed8SAndrew Rybchenko 	}
11845e111ed8SAndrew Rybchenko 
11855e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
11865e111ed8SAndrew Rybchenko 	/* The RSS key and indirection table are writable. */
11875e111ed8SAndrew Rybchenko 	enp->en_rss_context_type = EFX_RX_SCALE_EXCLUSIVE;
11885e111ed8SAndrew Rybchenko 
11895e111ed8SAndrew Rybchenko 	/* Hardware can insert RX hash with/without RSS */
11905e111ed8SAndrew Rybchenko 	enp->en_hash_support = EFX_RX_HASH_AVAILABLE;
11915e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCALE */
11925e111ed8SAndrew Rybchenko 
11935e111ed8SAndrew Rybchenko 	return (0);
11945e111ed8SAndrew Rybchenko }
11955e111ed8SAndrew Rybchenko 
11965e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
11975e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_scatter_enable(__in efx_nic_t * enp,__in unsigned int buf_size)11985e111ed8SAndrew Rybchenko siena_rx_scatter_enable(
11995e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
12005e111ed8SAndrew Rybchenko 	__in		unsigned int buf_size)
12015e111ed8SAndrew Rybchenko {
12025e111ed8SAndrew Rybchenko 	unsigned int nbuf32;
12035e111ed8SAndrew Rybchenko 	efx_oword_t oword;
12045e111ed8SAndrew Rybchenko 	efx_rc_t rc;
12055e111ed8SAndrew Rybchenko 
12065e111ed8SAndrew Rybchenko 	nbuf32 = buf_size / 32;
12075e111ed8SAndrew Rybchenko 	if ((nbuf32 == 0) ||
12085e111ed8SAndrew Rybchenko 	    (nbuf32 >= (1 << FRF_BZ_RX_USR_BUF_SIZE_WIDTH)) ||
12095e111ed8SAndrew Rybchenko 	    ((buf_size % 32) != 0)) {
12105e111ed8SAndrew Rybchenko 		rc = EINVAL;
12115e111ed8SAndrew Rybchenko 		goto fail1;
12125e111ed8SAndrew Rybchenko 	}
12135e111ed8SAndrew Rybchenko 
12145e111ed8SAndrew Rybchenko 	if (enp->en_rx_qcount > 0) {
12155e111ed8SAndrew Rybchenko 		rc = EBUSY;
12165e111ed8SAndrew Rybchenko 		goto fail2;
12175e111ed8SAndrew Rybchenko 	}
12185e111ed8SAndrew Rybchenko 
12195e111ed8SAndrew Rybchenko 	/* Set scatter buffer size */
12205e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
12215e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_USR_BUF_SIZE, nbuf32);
12225e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
12235e111ed8SAndrew Rybchenko 
12245e111ed8SAndrew Rybchenko 	/* Enable scatter for packets not matching a filter */
12255e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
12265e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_BZ_SCATTER_ENBL_NO_MATCH_Q, 1);
12275e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
12285e111ed8SAndrew Rybchenko 
12295e111ed8SAndrew Rybchenko 	return (0);
12305e111ed8SAndrew Rybchenko 
12315e111ed8SAndrew Rybchenko fail2:
12325e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
12335e111ed8SAndrew Rybchenko fail1:
12345e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
12355e111ed8SAndrew Rybchenko 
12365e111ed8SAndrew Rybchenko 	return (rc);
12375e111ed8SAndrew Rybchenko }
12385e111ed8SAndrew Rybchenko #endif	/* EFSYS_OPT_RX_SCATTER */
12395e111ed8SAndrew Rybchenko 
12405e111ed8SAndrew Rybchenko 
12415e111ed8SAndrew Rybchenko #define	EFX_RX_LFSR_HASH(_enp, _insert)					\
12425e111ed8SAndrew Rybchenko 	do {								\
12435e111ed8SAndrew Rybchenko 		efx_oword_t oword;					\
12445e111ed8SAndrew Rybchenko 									\
12455e111ed8SAndrew Rybchenko 		EFX_BAR_READO((_enp), FR_AZ_RX_CFG_REG, &oword);	\
12465e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 0);	\
12475e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, 0);	\
12485e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, 0);	\
12495e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR,	\
12505e111ed8SAndrew Rybchenko 		    (_insert) ? 1 : 0);					\
12515e111ed8SAndrew Rybchenko 		EFX_BAR_WRITEO((_enp), FR_AZ_RX_CFG_REG, &oword);	\
12525e111ed8SAndrew Rybchenko 									\
12535e111ed8SAndrew Rybchenko 		if ((_enp)->en_family == EFX_FAMILY_SIENA) {		\
12545e111ed8SAndrew Rybchenko 			EFX_BAR_READO((_enp), FR_CZ_RX_RSS_IPV6_REG3,	\
12555e111ed8SAndrew Rybchenko 			    &oword);					\
12565e111ed8SAndrew Rybchenko 			EFX_SET_OWORD_FIELD(oword,			\
12575e111ed8SAndrew Rybchenko 			    FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 0);	\
12585e111ed8SAndrew Rybchenko 			EFX_BAR_WRITEO((_enp), FR_CZ_RX_RSS_IPV6_REG3,	\
12595e111ed8SAndrew Rybchenko 			    &oword);					\
12605e111ed8SAndrew Rybchenko 		}							\
12615e111ed8SAndrew Rybchenko 									\
12625e111ed8SAndrew Rybchenko 		_NOTE(CONSTANTCONDITION)				\
12635e111ed8SAndrew Rybchenko 	} while (B_FALSE)
12645e111ed8SAndrew Rybchenko 
12655e111ed8SAndrew Rybchenko #define	EFX_RX_TOEPLITZ_IPV4_HASH(_enp, _insert, _ip, _tcp)		\
12665e111ed8SAndrew Rybchenko 	do {								\
12675e111ed8SAndrew Rybchenko 		efx_oword_t oword;					\
12685e111ed8SAndrew Rybchenko 									\
12695e111ed8SAndrew Rybchenko 		EFX_BAR_READO((_enp), FR_AZ_RX_CFG_REG,	&oword);	\
12705e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 1);	\
12715e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH,		\
12725e111ed8SAndrew Rybchenko 		    (_ip) ? 1 : 0);					\
12735e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP,		\
12745e111ed8SAndrew Rybchenko 		    (_tcp) ? 0 : 1);					\
12755e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR,	\
12765e111ed8SAndrew Rybchenko 		    (_insert) ? 1 : 0);					\
12775e111ed8SAndrew Rybchenko 		EFX_BAR_WRITEO((_enp), FR_AZ_RX_CFG_REG, &oword);	\
12785e111ed8SAndrew Rybchenko 									\
12795e111ed8SAndrew Rybchenko 		_NOTE(CONSTANTCONDITION)				\
12805e111ed8SAndrew Rybchenko 	} while (B_FALSE)
12815e111ed8SAndrew Rybchenko 
12825e111ed8SAndrew Rybchenko #define	EFX_RX_TOEPLITZ_IPV6_HASH(_enp, _ip, _tcp, _rc)			\
12835e111ed8SAndrew Rybchenko 	do {								\
12845e111ed8SAndrew Rybchenko 		efx_oword_t oword;					\
12855e111ed8SAndrew Rybchenko 									\
12865e111ed8SAndrew Rybchenko 		EFX_BAR_READO((_enp), FR_CZ_RX_RSS_IPV6_REG3, &oword);	\
12875e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword,				\
12885e111ed8SAndrew Rybchenko 		    FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1);		\
12895e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword,				\
12905e111ed8SAndrew Rybchenko 		    FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, (_ip) ? 1 : 0);	\
12915e111ed8SAndrew Rybchenko 		EFX_SET_OWORD_FIELD(oword,				\
12925e111ed8SAndrew Rybchenko 		    FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS, (_tcp) ? 0 : 1);	\
12935e111ed8SAndrew Rybchenko 		EFX_BAR_WRITEO((_enp), FR_CZ_RX_RSS_IPV6_REG3, &oword);	\
12945e111ed8SAndrew Rybchenko 									\
12955e111ed8SAndrew Rybchenko 		(_rc) = 0;						\
12965e111ed8SAndrew Rybchenko 									\
12975e111ed8SAndrew Rybchenko 		_NOTE(CONSTANTCONDITION)				\
12985e111ed8SAndrew Rybchenko 	} while (B_FALSE)
12995e111ed8SAndrew Rybchenko 
13005e111ed8SAndrew Rybchenko 
13015e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
13025e111ed8SAndrew Rybchenko 
13035e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_scale_mode_set(__in efx_nic_t * enp,__in uint32_t rss_context,__in efx_rx_hash_alg_t alg,__in efx_rx_hash_type_t type,__in boolean_t insert)13045e111ed8SAndrew Rybchenko siena_rx_scale_mode_set(
13055e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
13065e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context,
13075e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_alg_t alg,
13085e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_type_t type,
13095e111ed8SAndrew Rybchenko 	__in		boolean_t insert)
13105e111ed8SAndrew Rybchenko {
13115e111ed8SAndrew Rybchenko 	efx_rc_t rc;
13125e111ed8SAndrew Rybchenko 
13135e111ed8SAndrew Rybchenko 	if (rss_context != EFX_RSS_CONTEXT_DEFAULT) {
13145e111ed8SAndrew Rybchenko 		rc = EINVAL;
13155e111ed8SAndrew Rybchenko 		goto fail1;
13165e111ed8SAndrew Rybchenko 	}
13175e111ed8SAndrew Rybchenko 
13185e111ed8SAndrew Rybchenko 	switch (alg) {
13195e111ed8SAndrew Rybchenko 	case EFX_RX_HASHALG_LFSR:
13205e111ed8SAndrew Rybchenko 		EFX_RX_LFSR_HASH(enp, insert);
13215e111ed8SAndrew Rybchenko 		break;
13225e111ed8SAndrew Rybchenko 
13235e111ed8SAndrew Rybchenko 	case EFX_RX_HASHALG_TOEPLITZ:
13245e111ed8SAndrew Rybchenko 		EFX_RX_TOEPLITZ_IPV4_HASH(enp, insert,
13255e111ed8SAndrew Rybchenko 		    (type & EFX_RX_HASH_IPV4) ? B_TRUE : B_FALSE,
13265e111ed8SAndrew Rybchenko 		    (type & EFX_RX_HASH_TCPIPV4) ? B_TRUE : B_FALSE);
13275e111ed8SAndrew Rybchenko 
13285e111ed8SAndrew Rybchenko 		EFX_RX_TOEPLITZ_IPV6_HASH(enp,
13295e111ed8SAndrew Rybchenko 		    (type & EFX_RX_HASH_IPV6) ? B_TRUE : B_FALSE,
13305e111ed8SAndrew Rybchenko 		    (type & EFX_RX_HASH_TCPIPV6) ? B_TRUE : B_FALSE,
13315e111ed8SAndrew Rybchenko 		    rc);
13325e111ed8SAndrew Rybchenko 		if (rc != 0)
13335e111ed8SAndrew Rybchenko 			goto fail2;
13345e111ed8SAndrew Rybchenko 
13355e111ed8SAndrew Rybchenko 		break;
13365e111ed8SAndrew Rybchenko 
13375e111ed8SAndrew Rybchenko 	default:
13385e111ed8SAndrew Rybchenko 		rc = EINVAL;
13395e111ed8SAndrew Rybchenko 		goto fail3;
13405e111ed8SAndrew Rybchenko 	}
13415e111ed8SAndrew Rybchenko 
13425e111ed8SAndrew Rybchenko 	return (0);
13435e111ed8SAndrew Rybchenko 
13445e111ed8SAndrew Rybchenko fail3:
13455e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail3);
13465e111ed8SAndrew Rybchenko fail2:
13475e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
13485e111ed8SAndrew Rybchenko fail1:
13495e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
13505e111ed8SAndrew Rybchenko 
13515e111ed8SAndrew Rybchenko 	EFX_RX_LFSR_HASH(enp, B_FALSE);
13525e111ed8SAndrew Rybchenko 
13535e111ed8SAndrew Rybchenko 	return (rc);
13545e111ed8SAndrew Rybchenko }
13555e111ed8SAndrew Rybchenko #endif
13565e111ed8SAndrew Rybchenko 
13575e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
13585e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_scale_key_set(__in efx_nic_t * enp,__in uint32_t rss_context,__in_ecount (n)uint8_t * key,__in size_t n)13595e111ed8SAndrew Rybchenko siena_rx_scale_key_set(
13605e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
13615e111ed8SAndrew Rybchenko 	__in		uint32_t rss_context,
13625e111ed8SAndrew Rybchenko 	__in_ecount(n)	uint8_t *key,
13635e111ed8SAndrew Rybchenko 	__in		size_t n)
13645e111ed8SAndrew Rybchenko {
13655e111ed8SAndrew Rybchenko 	efx_oword_t oword;
13665e111ed8SAndrew Rybchenko 	unsigned int byte;
13675e111ed8SAndrew Rybchenko 	unsigned int offset;
13685e111ed8SAndrew Rybchenko 	efx_rc_t rc;
13695e111ed8SAndrew Rybchenko 
13705e111ed8SAndrew Rybchenko 	if (rss_context != EFX_RSS_CONTEXT_DEFAULT) {
13715e111ed8SAndrew Rybchenko 		rc = EINVAL;
13725e111ed8SAndrew Rybchenko 		goto fail1;
13735e111ed8SAndrew Rybchenko 	}
13745e111ed8SAndrew Rybchenko 
13755e111ed8SAndrew Rybchenko 	byte = 0;
13765e111ed8SAndrew Rybchenko 
13775e111ed8SAndrew Rybchenko 	/* Write Toeplitz IPv4 hash key */
13785e111ed8SAndrew Rybchenko 	EFX_ZERO_OWORD(oword);
13795e111ed8SAndrew Rybchenko 	for (offset = (FRF_BZ_RX_RSS_TKEY_LBN + FRF_BZ_RX_RSS_TKEY_WIDTH) / 8;
13805e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
13815e111ed8SAndrew Rybchenko 	    --offset)
13825e111ed8SAndrew Rybchenko 		oword.eo_u8[offset - 1] = key[byte++];
13835e111ed8SAndrew Rybchenko 
13845e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_BZ_RX_RSS_TKEY_REG, &oword);
13855e111ed8SAndrew Rybchenko 
13865e111ed8SAndrew Rybchenko 	byte = 0;
13875e111ed8SAndrew Rybchenko 
13885e111ed8SAndrew Rybchenko 	/* Verify Toeplitz IPv4 hash key */
13895e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_BZ_RX_RSS_TKEY_REG, &oword);
13905e111ed8SAndrew Rybchenko 	for (offset = (FRF_BZ_RX_RSS_TKEY_LBN + FRF_BZ_RX_RSS_TKEY_WIDTH) / 8;
13915e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
13925e111ed8SAndrew Rybchenko 	    --offset) {
13935e111ed8SAndrew Rybchenko 		if (oword.eo_u8[offset - 1] != key[byte++]) {
13945e111ed8SAndrew Rybchenko 			rc = EFAULT;
13955e111ed8SAndrew Rybchenko 			goto fail2;
13965e111ed8SAndrew Rybchenko 		}
13975e111ed8SAndrew Rybchenko 	}
13985e111ed8SAndrew Rybchenko 
13995e111ed8SAndrew Rybchenko 	if ((enp->en_features & EFX_FEATURE_IPV6) == 0)
14005e111ed8SAndrew Rybchenko 		goto done;
14015e111ed8SAndrew Rybchenko 
14025e111ed8SAndrew Rybchenko 	byte = 0;
14035e111ed8SAndrew Rybchenko 
14045e111ed8SAndrew Rybchenko 	/* Write Toeplitz IPv6 hash key 3 */
14055e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG3, &oword);
14065e111ed8SAndrew Rybchenko 	for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN +
14075e111ed8SAndrew Rybchenko 	    FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH) / 8;
14085e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
14095e111ed8SAndrew Rybchenko 	    --offset)
14105e111ed8SAndrew Rybchenko 		oword.eo_u8[offset - 1] = key[byte++];
14115e111ed8SAndrew Rybchenko 
14125e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_CZ_RX_RSS_IPV6_REG3, &oword);
14135e111ed8SAndrew Rybchenko 
14145e111ed8SAndrew Rybchenko 	/* Write Toeplitz IPv6 hash key 2 */
14155e111ed8SAndrew Rybchenko 	EFX_ZERO_OWORD(oword);
14165e111ed8SAndrew Rybchenko 	for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN +
14175e111ed8SAndrew Rybchenko 	    FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH) / 8;
14185e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
14195e111ed8SAndrew Rybchenko 	    --offset)
14205e111ed8SAndrew Rybchenko 		oword.eo_u8[offset - 1] = key[byte++];
14215e111ed8SAndrew Rybchenko 
14225e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_CZ_RX_RSS_IPV6_REG2, &oword);
14235e111ed8SAndrew Rybchenko 
14245e111ed8SAndrew Rybchenko 	/* Write Toeplitz IPv6 hash key 1 */
14255e111ed8SAndrew Rybchenko 	EFX_ZERO_OWORD(oword);
14265e111ed8SAndrew Rybchenko 	for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN +
14275e111ed8SAndrew Rybchenko 	    FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH) / 8;
14285e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
14295e111ed8SAndrew Rybchenko 	    --offset)
14305e111ed8SAndrew Rybchenko 		oword.eo_u8[offset - 1] = key[byte++];
14315e111ed8SAndrew Rybchenko 
14325e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_CZ_RX_RSS_IPV6_REG1, &oword);
14335e111ed8SAndrew Rybchenko 
14345e111ed8SAndrew Rybchenko 	byte = 0;
14355e111ed8SAndrew Rybchenko 
14365e111ed8SAndrew Rybchenko 	/* Verify Toeplitz IPv6 hash key 3 */
14375e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG3, &oword);
14385e111ed8SAndrew Rybchenko 	for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN +
14395e111ed8SAndrew Rybchenko 	    FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH) / 8;
14405e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
14415e111ed8SAndrew Rybchenko 	    --offset) {
14425e111ed8SAndrew Rybchenko 		if (oword.eo_u8[offset - 1] != key[byte++]) {
14435e111ed8SAndrew Rybchenko 			rc = EFAULT;
14445e111ed8SAndrew Rybchenko 			goto fail3;
14455e111ed8SAndrew Rybchenko 		}
14465e111ed8SAndrew Rybchenko 	}
14475e111ed8SAndrew Rybchenko 
14485e111ed8SAndrew Rybchenko 	/* Verify Toeplitz IPv6 hash key 2 */
14495e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG2, &oword);
14505e111ed8SAndrew Rybchenko 	for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN +
14515e111ed8SAndrew Rybchenko 	    FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH) / 8;
14525e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
14535e111ed8SAndrew Rybchenko 	    --offset) {
14545e111ed8SAndrew Rybchenko 		if (oword.eo_u8[offset - 1] != key[byte++]) {
14555e111ed8SAndrew Rybchenko 			rc = EFAULT;
14565e111ed8SAndrew Rybchenko 			goto fail4;
14575e111ed8SAndrew Rybchenko 		}
14585e111ed8SAndrew Rybchenko 	}
14595e111ed8SAndrew Rybchenko 
14605e111ed8SAndrew Rybchenko 	/* Verify Toeplitz IPv6 hash key 1 */
14615e111ed8SAndrew Rybchenko 	EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG1, &oword);
14625e111ed8SAndrew Rybchenko 	for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN +
14635e111ed8SAndrew Rybchenko 	    FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH) / 8;
14645e111ed8SAndrew Rybchenko 	    offset > 0 && byte < n;
14655e111ed8SAndrew Rybchenko 	    --offset) {
14665e111ed8SAndrew Rybchenko 		if (oword.eo_u8[offset - 1] != key[byte++]) {
14675e111ed8SAndrew Rybchenko 			rc = EFAULT;
14685e111ed8SAndrew Rybchenko 			goto fail5;
14695e111ed8SAndrew Rybchenko 		}
14705e111ed8SAndrew Rybchenko 	}
14715e111ed8SAndrew Rybchenko 
14725e111ed8SAndrew Rybchenko done:
14735e111ed8SAndrew Rybchenko 	return (0);
14745e111ed8SAndrew Rybchenko 
14755e111ed8SAndrew Rybchenko fail5:
14765e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail5);
14775e111ed8SAndrew Rybchenko fail4:
14785e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail4);
14795e111ed8SAndrew Rybchenko fail3:
14805e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail3);
14815e111ed8SAndrew Rybchenko fail2:
14825e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
14835e111ed8SAndrew Rybchenko fail1:
14845e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
14855e111ed8SAndrew Rybchenko 
14865e111ed8SAndrew Rybchenko 	return (rc);
14875e111ed8SAndrew Rybchenko }
14885e111ed8SAndrew Rybchenko #endif
14895e111ed8SAndrew Rybchenko 
14905e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
14915e111ed8SAndrew Rybchenko static	__checkReturn		efx_rc_t
siena_rx_scale_tbl_set(__in efx_nic_t * enp,__in uint32_t rss_context,__in_ecount (nentries)unsigned int * table,__in size_t nentries)14925e111ed8SAndrew Rybchenko siena_rx_scale_tbl_set(
14935e111ed8SAndrew Rybchenko 	__in			efx_nic_t *enp,
14945e111ed8SAndrew Rybchenko 	__in			uint32_t rss_context,
14957a71c15dSIvan Malov 	__in_ecount(nentries)	unsigned int *table,
14967a71c15dSIvan Malov 	__in			size_t nentries)
14975e111ed8SAndrew Rybchenko {
14985e111ed8SAndrew Rybchenko 	efx_oword_t oword;
14995e111ed8SAndrew Rybchenko 	int index;
15005e111ed8SAndrew Rybchenko 	efx_rc_t rc;
15015e111ed8SAndrew Rybchenko 
15025e111ed8SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RSS_TBL_SIZE == FR_BZ_RX_INDIRECTION_TBL_ROWS);
15035e111ed8SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_MAXRSS == (1 << FRF_BZ_IT_QUEUE_WIDTH));
15045e111ed8SAndrew Rybchenko 
15055e111ed8SAndrew Rybchenko 	if (rss_context != EFX_RSS_CONTEXT_DEFAULT) {
15065e111ed8SAndrew Rybchenko 		rc = EINVAL;
15075e111ed8SAndrew Rybchenko 		goto fail1;
15085e111ed8SAndrew Rybchenko 	}
15095e111ed8SAndrew Rybchenko 
15107a71c15dSIvan Malov 	if (nentries > FR_BZ_RX_INDIRECTION_TBL_ROWS) {
15115e111ed8SAndrew Rybchenko 		rc = EINVAL;
15125e111ed8SAndrew Rybchenko 		goto fail2;
15135e111ed8SAndrew Rybchenko 	}
15145e111ed8SAndrew Rybchenko 
15155e111ed8SAndrew Rybchenko 	for (index = 0; index < FR_BZ_RX_INDIRECTION_TBL_ROWS; index++) {
15165e111ed8SAndrew Rybchenko 		uint32_t byte;
15175e111ed8SAndrew Rybchenko 
15185e111ed8SAndrew Rybchenko 		/* Calculate the entry to place in the table */
15197a71c15dSIvan Malov 		byte = (nentries > 0) ? (uint32_t)table[index % nentries] : 0;
15205e111ed8SAndrew Rybchenko 
15215e111ed8SAndrew Rybchenko 		EFSYS_PROBE2(table, int, index, uint32_t, byte);
15225e111ed8SAndrew Rybchenko 
15235e111ed8SAndrew Rybchenko 		EFX_POPULATE_OWORD_1(oword, FRF_BZ_IT_QUEUE, byte);
15245e111ed8SAndrew Rybchenko 
15255e111ed8SAndrew Rybchenko 		/* Write the table */
15265e111ed8SAndrew Rybchenko 		EFX_BAR_TBL_WRITEO(enp, FR_BZ_RX_INDIRECTION_TBL,
15275e111ed8SAndrew Rybchenko 				    index, &oword, B_TRUE);
15285e111ed8SAndrew Rybchenko 	}
15295e111ed8SAndrew Rybchenko 
15305e111ed8SAndrew Rybchenko 	for (index = FR_BZ_RX_INDIRECTION_TBL_ROWS - 1; index >= 0; --index) {
15315e111ed8SAndrew Rybchenko 		uint32_t byte;
15325e111ed8SAndrew Rybchenko 
15335e111ed8SAndrew Rybchenko 		/* Determine if we're starting a new batch */
15347a71c15dSIvan Malov 		byte = (nentries > 0) ? (uint32_t)table[index % nentries] : 0;
15355e111ed8SAndrew Rybchenko 
15365e111ed8SAndrew Rybchenko 		/* Read the table */
15375e111ed8SAndrew Rybchenko 		EFX_BAR_TBL_READO(enp, FR_BZ_RX_INDIRECTION_TBL,
15385e111ed8SAndrew Rybchenko 				    index, &oword, B_TRUE);
15395e111ed8SAndrew Rybchenko 
15405e111ed8SAndrew Rybchenko 		/* Verify the entry */
15415e111ed8SAndrew Rybchenko 		if (EFX_OWORD_FIELD(oword, FRF_BZ_IT_QUEUE) != byte) {
15425e111ed8SAndrew Rybchenko 			rc = EFAULT;
15435e111ed8SAndrew Rybchenko 			goto fail3;
15445e111ed8SAndrew Rybchenko 		}
15455e111ed8SAndrew Rybchenko 	}
15465e111ed8SAndrew Rybchenko 
15475e111ed8SAndrew Rybchenko 	return (0);
15485e111ed8SAndrew Rybchenko 
15495e111ed8SAndrew Rybchenko fail3:
15505e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail3);
15515e111ed8SAndrew Rybchenko fail2:
15525e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
15535e111ed8SAndrew Rybchenko fail1:
15545e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
15555e111ed8SAndrew Rybchenko 
15565e111ed8SAndrew Rybchenko 	return (rc);
15575e111ed8SAndrew Rybchenko }
15585e111ed8SAndrew Rybchenko #endif
15595e111ed8SAndrew Rybchenko 
15605e111ed8SAndrew Rybchenko /*
15615e111ed8SAndrew Rybchenko  * Falcon/Siena pseudo-header
15625e111ed8SAndrew Rybchenko  * --------------------------
15635e111ed8SAndrew Rybchenko  *
15645e111ed8SAndrew Rybchenko  * Receive packets are prefixed by an optional 16 byte pseudo-header.
15655e111ed8SAndrew Rybchenko  * The pseudo-header is a byte array of one of the forms:
15665e111ed8SAndrew Rybchenko  *
15675e111ed8SAndrew Rybchenko  *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
15685e111ed8SAndrew Rybchenko  * xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.TT.TT.TT.TT
15695e111ed8SAndrew Rybchenko  * xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.LL.LL
15705e111ed8SAndrew Rybchenko  *
15715e111ed8SAndrew Rybchenko  * where:
15725e111ed8SAndrew Rybchenko  *   TT.TT.TT.TT   Toeplitz hash (32-bit big-endian)
15735e111ed8SAndrew Rybchenko  *   LL.LL         LFSR hash     (16-bit big-endian)
15745e111ed8SAndrew Rybchenko  */
15755e111ed8SAndrew Rybchenko 
15766bba823fSAndrew Rybchenko /*
15776bba823fSAndrew Rybchenko  * Provide Rx prefix layout with Toeplitz hash only since LSFR is
15786bba823fSAndrew Rybchenko  * used by no supported drivers.
15796bba823fSAndrew Rybchenko  *
15806bba823fSAndrew Rybchenko  * Siena does not support Rx prefix choice via MC_CMD_GET_RX_PREFIX_ID
15816bba823fSAndrew Rybchenko  * and query its layout using MC_CMD_QUERY_RX_PREFIX_ID.
15826bba823fSAndrew Rybchenko  */
15836bba823fSAndrew Rybchenko static const efx_rx_prefix_layout_t siena_toeplitz_rx_prefix_layout = {
15846bba823fSAndrew Rybchenko 	.erpl_id	= 0,
15856bba823fSAndrew Rybchenko 	.erpl_length	= 16,
15866bba823fSAndrew Rybchenko 	.erpl_fields	= {
15876bba823fSAndrew Rybchenko 		[EFX_RX_PREFIX_FIELD_RSS_HASH] = { 12 * 8, 32, B_TRUE },
15886bba823fSAndrew Rybchenko 	}
15896bba823fSAndrew Rybchenko };
15906bba823fSAndrew Rybchenko 
15915e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE
15925e111ed8SAndrew Rybchenko static	__checkReturn	uint32_t
siena_rx_prefix_hash(__in efx_nic_t * enp,__in efx_rx_hash_alg_t func,__in uint8_t * buffer)15935e111ed8SAndrew Rybchenko siena_rx_prefix_hash(
15945e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
15955e111ed8SAndrew Rybchenko 	__in		efx_rx_hash_alg_t func,
15965e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer)
15975e111ed8SAndrew Rybchenko {
15985e111ed8SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp))
15995e111ed8SAndrew Rybchenko 
16005e111ed8SAndrew Rybchenko 	switch (func) {
16015e111ed8SAndrew Rybchenko 	case EFX_RX_HASHALG_TOEPLITZ:
16025e111ed8SAndrew Rybchenko 		return ((buffer[12] << 24) |
16035e111ed8SAndrew Rybchenko 		    (buffer[13] << 16) |
16045e111ed8SAndrew Rybchenko 		    (buffer[14] <<  8) |
16055e111ed8SAndrew Rybchenko 		    buffer[15]);
16065e111ed8SAndrew Rybchenko 
16075e111ed8SAndrew Rybchenko 	case EFX_RX_HASHALG_LFSR:
16085e111ed8SAndrew Rybchenko 		return ((buffer[14] << 8) | buffer[15]);
16095e111ed8SAndrew Rybchenko 
16105e111ed8SAndrew Rybchenko 	default:
16115e111ed8SAndrew Rybchenko 		EFSYS_ASSERT(0);
16125e111ed8SAndrew Rybchenko 		return (0);
16135e111ed8SAndrew Rybchenko 	}
16145e111ed8SAndrew Rybchenko }
16155e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCALE */
16165e111ed8SAndrew Rybchenko 
16175e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_prefix_pktlen(__in efx_nic_t * enp,__in uint8_t * buffer,__out uint16_t * lengthp)16185e111ed8SAndrew Rybchenko siena_rx_prefix_pktlen(
16195e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
16205e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer,
16215e111ed8SAndrew Rybchenko 	__out		uint16_t *lengthp)
16225e111ed8SAndrew Rybchenko {
16235e111ed8SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp, buffer, lengthp))
16245e111ed8SAndrew Rybchenko 
16255e111ed8SAndrew Rybchenko 	/* Not supported by Falcon/Siena hardware */
16265e111ed8SAndrew Rybchenko 	EFSYS_ASSERT(0);
16275e111ed8SAndrew Rybchenko 	return (ENOTSUP);
16285e111ed8SAndrew Rybchenko }
16295e111ed8SAndrew Rybchenko 
16305e111ed8SAndrew Rybchenko 
16315e111ed8SAndrew Rybchenko static				void
siena_rx_qpost(__in efx_rxq_t * erp,__in_ecount (ndescs)efsys_dma_addr_t * addrp,__in size_t size,__in unsigned int ndescs,__in unsigned int completed,__in unsigned int added)16325e111ed8SAndrew Rybchenko siena_rx_qpost(
16335e111ed8SAndrew Rybchenko 	__in			efx_rxq_t *erp,
16345e111ed8SAndrew Rybchenko 	__in_ecount(ndescs)	efsys_dma_addr_t *addrp,
16355e111ed8SAndrew Rybchenko 	__in			size_t size,
16365e111ed8SAndrew Rybchenko 	__in			unsigned int ndescs,
16375e111ed8SAndrew Rybchenko 	__in			unsigned int completed,
16385e111ed8SAndrew Rybchenko 	__in			unsigned int added)
16395e111ed8SAndrew Rybchenko {
16405e111ed8SAndrew Rybchenko 	efx_qword_t qword;
16415e111ed8SAndrew Rybchenko 	unsigned int i;
16425e111ed8SAndrew Rybchenko 	unsigned int offset;
16435e111ed8SAndrew Rybchenko 	unsigned int id;
16445e111ed8SAndrew Rybchenko 
16455e111ed8SAndrew Rybchenko 	/* The client driver must not overfill the queue */
16465e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(added - completed + ndescs, <=,
16475e111ed8SAndrew Rybchenko 	    EFX_RXQ_LIMIT(erp->er_mask + 1));
16485e111ed8SAndrew Rybchenko 
16495e111ed8SAndrew Rybchenko 	id = added & (erp->er_mask);
16505e111ed8SAndrew Rybchenko 	for (i = 0; i < ndescs; i++) {
16515e111ed8SAndrew Rybchenko 		EFSYS_PROBE4(rx_post, unsigned int, erp->er_index,
16525e111ed8SAndrew Rybchenko 		    unsigned int, id, efsys_dma_addr_t, addrp[i],
16535e111ed8SAndrew Rybchenko 		    size_t, size);
16545e111ed8SAndrew Rybchenko 
16555e111ed8SAndrew Rybchenko 		EFX_POPULATE_QWORD_3(qword,
16565e111ed8SAndrew Rybchenko 		    FSF_AZ_RX_KER_BUF_SIZE, (uint32_t)(size),
16575e111ed8SAndrew Rybchenko 		    FSF_AZ_RX_KER_BUF_ADDR_DW0,
16585e111ed8SAndrew Rybchenko 		    (uint32_t)(addrp[i] & 0xffffffff),
16595e111ed8SAndrew Rybchenko 		    FSF_AZ_RX_KER_BUF_ADDR_DW1,
16605e111ed8SAndrew Rybchenko 		    (uint32_t)(addrp[i] >> 32));
16615e111ed8SAndrew Rybchenko 
16625e111ed8SAndrew Rybchenko 		offset = id * sizeof (efx_qword_t);
16635e111ed8SAndrew Rybchenko 		EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword);
16645e111ed8SAndrew Rybchenko 
16655e111ed8SAndrew Rybchenko 		id = (id + 1) & (erp->er_mask);
16665e111ed8SAndrew Rybchenko 	}
16675e111ed8SAndrew Rybchenko }
16685e111ed8SAndrew Rybchenko 
16695e111ed8SAndrew Rybchenko static			void
siena_rx_qpush(__in efx_rxq_t * erp,__in unsigned int added,__inout unsigned int * pushedp)16705e111ed8SAndrew Rybchenko siena_rx_qpush(
16715e111ed8SAndrew Rybchenko 	__in	efx_rxq_t *erp,
16725e111ed8SAndrew Rybchenko 	__in	unsigned int added,
16735e111ed8SAndrew Rybchenko 	__inout	unsigned int *pushedp)
16745e111ed8SAndrew Rybchenko {
16755e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
16765e111ed8SAndrew Rybchenko 	unsigned int pushed = *pushedp;
16775e111ed8SAndrew Rybchenko 	uint32_t wptr;
16785e111ed8SAndrew Rybchenko 	efx_oword_t oword;
16795e111ed8SAndrew Rybchenko 	efx_dword_t dword;
16805e111ed8SAndrew Rybchenko 
16815e111ed8SAndrew Rybchenko 	/* All descriptors are pushed */
16825e111ed8SAndrew Rybchenko 	*pushedp = added;
16835e111ed8SAndrew Rybchenko 
16845e111ed8SAndrew Rybchenko 	/* Push the populated descriptors out */
16855e111ed8SAndrew Rybchenko 	wptr = added & erp->er_mask;
16865e111ed8SAndrew Rybchenko 
16875e111ed8SAndrew Rybchenko 	EFX_POPULATE_OWORD_1(oword, FRF_AZ_RX_DESC_WPTR, wptr);
16885e111ed8SAndrew Rybchenko 
16895e111ed8SAndrew Rybchenko 	/* Only write the third DWORD */
16905e111ed8SAndrew Rybchenko 	EFX_POPULATE_DWORD_1(dword,
16915e111ed8SAndrew Rybchenko 	    EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3));
16925e111ed8SAndrew Rybchenko 
16935e111ed8SAndrew Rybchenko 	/* Guarantee ordering of memory (descriptors) and PIO (doorbell) */
16945e111ed8SAndrew Rybchenko 	EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1,
169582192e22SAndrew Rybchenko 	    SIENA_RXQ_DESC_SIZE, wptr, pushed & erp->er_mask);
16965e111ed8SAndrew Rybchenko 	EFSYS_PIO_WRITE_BARRIER();
16975e111ed8SAndrew Rybchenko 	EFX_BAR_TBL_WRITED3(enp, FR_BZ_RX_DESC_UPD_REGP0,
16985e111ed8SAndrew Rybchenko 			    erp->er_index, &dword, B_FALSE);
16995e111ed8SAndrew Rybchenko }
17005e111ed8SAndrew Rybchenko 
17015e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_PACKED_STREAM
17025e111ed8SAndrew Rybchenko static		void
siena_rx_qpush_ps_credits(__in efx_rxq_t * erp)17035e111ed8SAndrew Rybchenko siena_rx_qpush_ps_credits(
17045e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp)
17055e111ed8SAndrew Rybchenko {
17065e111ed8SAndrew Rybchenko 	/* Not supported by Siena hardware */
17075e111ed8SAndrew Rybchenko 	EFSYS_ASSERT(0);
17085e111ed8SAndrew Rybchenko }
17095e111ed8SAndrew Rybchenko 
17105e111ed8SAndrew Rybchenko static		uint8_t *
siena_rx_qps_packet_info(__in efx_rxq_t * erp,__in uint8_t * buffer,__in uint32_t buffer_length,__in uint32_t current_offset,__out uint16_t * lengthp,__out uint32_t * next_offsetp,__out uint32_t * timestamp)17115e111ed8SAndrew Rybchenko siena_rx_qps_packet_info(
17125e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp,
17135e111ed8SAndrew Rybchenko 	__in		uint8_t *buffer,
17145e111ed8SAndrew Rybchenko 	__in		uint32_t buffer_length,
17155e111ed8SAndrew Rybchenko 	__in		uint32_t current_offset,
17165e111ed8SAndrew Rybchenko 	__out		uint16_t *lengthp,
17175e111ed8SAndrew Rybchenko 	__out		uint32_t *next_offsetp,
17185e111ed8SAndrew Rybchenko 	__out		uint32_t *timestamp)
17195e111ed8SAndrew Rybchenko {
17205e111ed8SAndrew Rybchenko 	/* Not supported by Siena hardware */
17215e111ed8SAndrew Rybchenko 	EFSYS_ASSERT(0);
17225e111ed8SAndrew Rybchenko 
17235e111ed8SAndrew Rybchenko 	return (NULL);
17245e111ed8SAndrew Rybchenko }
17255e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_PACKED_STREAM */
17265e111ed8SAndrew Rybchenko 
17275e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_qflush(__in efx_rxq_t * erp)17285e111ed8SAndrew Rybchenko siena_rx_qflush(
17295e111ed8SAndrew Rybchenko 	__in	efx_rxq_t *erp)
17305e111ed8SAndrew Rybchenko {
17315e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
17325e111ed8SAndrew Rybchenko 	efx_oword_t oword;
17335e111ed8SAndrew Rybchenko 	uint32_t label;
17345e111ed8SAndrew Rybchenko 
17355e111ed8SAndrew Rybchenko 	label = erp->er_index;
17365e111ed8SAndrew Rybchenko 
17375e111ed8SAndrew Rybchenko 	/* Flush the queue */
17385e111ed8SAndrew Rybchenko 	EFX_POPULATE_OWORD_2(oword, FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
17395e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_FLUSH_DESCQ, label);
17405e111ed8SAndrew Rybchenko 	EFX_BAR_WRITEO(enp, FR_AZ_RX_FLUSH_DESCQ_REG, &oword);
17415e111ed8SAndrew Rybchenko 
17425e111ed8SAndrew Rybchenko 	return (0);
17435e111ed8SAndrew Rybchenko }
17445e111ed8SAndrew Rybchenko 
17455e111ed8SAndrew Rybchenko static		void
siena_rx_qenable(__in efx_rxq_t * erp)17465e111ed8SAndrew Rybchenko siena_rx_qenable(
17475e111ed8SAndrew Rybchenko 	__in	efx_rxq_t *erp)
17485e111ed8SAndrew Rybchenko {
17495e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
17505e111ed8SAndrew Rybchenko 	efx_oword_t oword;
17515e111ed8SAndrew Rybchenko 
17525e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC);
17535e111ed8SAndrew Rybchenko 
17545e111ed8SAndrew Rybchenko 	EFX_BAR_TBL_READO(enp, FR_AZ_RX_DESC_PTR_TBL,
17555e111ed8SAndrew Rybchenko 			    erp->er_index, &oword, B_TRUE);
17565e111ed8SAndrew Rybchenko 
17575e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DC_HW_RPTR, 0);
17585e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DESCQ_HW_RPTR, 0);
17595e111ed8SAndrew Rybchenko 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DESCQ_EN, 1);
17605e111ed8SAndrew Rybchenko 
17615e111ed8SAndrew Rybchenko 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL,
17625e111ed8SAndrew Rybchenko 			    erp->er_index, &oword, B_TRUE);
17635e111ed8SAndrew Rybchenko }
17645e111ed8SAndrew Rybchenko 
17655e111ed8SAndrew Rybchenko static	__checkReturn	efx_rc_t
siena_rx_qcreate(__in efx_nic_t * enp,__in unsigned int index,__in unsigned int label,__in efx_rxq_type_t type,__in_opt const efx_rxq_type_data_t * type_data,__in efsys_mem_t * esmp,__in size_t ndescs,__in uint32_t id,__in unsigned int flags,__in efx_evq_t * eep,__in efx_rxq_t * erp)17665e111ed8SAndrew Rybchenko siena_rx_qcreate(
17675e111ed8SAndrew Rybchenko 	__in		efx_nic_t *enp,
17685e111ed8SAndrew Rybchenko 	__in		unsigned int index,
17695e111ed8SAndrew Rybchenko 	__in		unsigned int label,
17705e111ed8SAndrew Rybchenko 	__in		efx_rxq_type_t type,
17715e111ed8SAndrew Rybchenko 	__in_opt	const efx_rxq_type_data_t *type_data,
17725e111ed8SAndrew Rybchenko 	__in		efsys_mem_t *esmp,
17735e111ed8SAndrew Rybchenko 	__in		size_t ndescs,
17745e111ed8SAndrew Rybchenko 	__in		uint32_t id,
17755e111ed8SAndrew Rybchenko 	__in		unsigned int flags,
17765e111ed8SAndrew Rybchenko 	__in		efx_evq_t *eep,
17775e111ed8SAndrew Rybchenko 	__in		efx_rxq_t *erp)
17785e111ed8SAndrew Rybchenko {
17795e111ed8SAndrew Rybchenko 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
17805e111ed8SAndrew Rybchenko 	efx_oword_t oword;
17815e111ed8SAndrew Rybchenko 	uint32_t size;
17825e111ed8SAndrew Rybchenko 	boolean_t jumbo = B_FALSE;
17835e111ed8SAndrew Rybchenko 	efx_rc_t rc;
17845e111ed8SAndrew Rybchenko 
17855e111ed8SAndrew Rybchenko 	_NOTE(ARGUNUSED(esmp))
17865e111ed8SAndrew Rybchenko 
17875e111ed8SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS ==
17885e111ed8SAndrew Rybchenko 	    (1 << FRF_AZ_RX_DESCQ_LABEL_WIDTH));
17895e111ed8SAndrew Rybchenko 	EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS);
17905e111ed8SAndrew Rybchenko 
17915e111ed8SAndrew Rybchenko 	for (size = 0;
17925e111ed8SAndrew Rybchenko 	    (1U << size) <= encp->enc_rxq_max_ndescs / encp->enc_rxq_min_ndescs;
17935e111ed8SAndrew Rybchenko 	    size++)
17945e111ed8SAndrew Rybchenko 		if ((1U << size) == (uint32_t)ndescs / encp->enc_rxq_min_ndescs)
17955e111ed8SAndrew Rybchenko 			break;
17965e111ed8SAndrew Rybchenko 	if (id + (1 << size) >= encp->enc_buftbl_limit) {
17975e111ed8SAndrew Rybchenko 		rc = EINVAL;
1798e9b9b2e5SAndrew Rybchenko 		goto fail1;
17995e111ed8SAndrew Rybchenko 	}
18005e111ed8SAndrew Rybchenko 
18015e111ed8SAndrew Rybchenko 	switch (type) {
18025e111ed8SAndrew Rybchenko 	case EFX_RXQ_TYPE_DEFAULT:
18035e111ed8SAndrew Rybchenko 		erp->er_buf_size = type_data->ertd_default.ed_buf_size;
1804f784cdc5SAndrew Rybchenko 		/*
1805f784cdc5SAndrew Rybchenko 		 * Ignore EFX_RXQ_FLAG_RSS_HASH since if RSS hash is calculated
1806f784cdc5SAndrew Rybchenko 		 * it is always delivered from HW in the pseudo-header.
1807f784cdc5SAndrew Rybchenko 		 */
18085e111ed8SAndrew Rybchenko 		break;
18095e111ed8SAndrew Rybchenko 
18105e111ed8SAndrew Rybchenko 	default:
18115e111ed8SAndrew Rybchenko 		rc = EINVAL;
1812e9b9b2e5SAndrew Rybchenko 		goto fail2;
18135e111ed8SAndrew Rybchenko 	}
18145e111ed8SAndrew Rybchenko 
18155e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER
1816aa3e21f0SIgor Romanov #define SUPPORTED_RXQ_FLAGS EFX_RXQ_FLAG_SCATTER
18175e111ed8SAndrew Rybchenko #else
1818aa3e21f0SIgor Romanov #define SUPPORTED_RXQ_FLAGS EFX_RXQ_FLAG_NONE
1819aa3e21f0SIgor Romanov #endif
1820aa3e21f0SIgor Romanov 	/* Reject flags for unsupported queue features */
1821aa3e21f0SIgor Romanov 	if ((flags & ~SUPPORTED_RXQ_FLAGS) != 0) {
18225e111ed8SAndrew Rybchenko 		rc = EINVAL;
1823e9b9b2e5SAndrew Rybchenko 		goto fail3;
18245e111ed8SAndrew Rybchenko 	}
1825aa3e21f0SIgor Romanov #undef SUPPORTED_RXQ_FLAGS
1826aa3e21f0SIgor Romanov 
1827aa3e21f0SIgor Romanov 	if (flags & EFX_RXQ_FLAG_SCATTER)
1828aa3e21f0SIgor Romanov 		jumbo = B_TRUE;
18295e111ed8SAndrew Rybchenko 
18305e111ed8SAndrew Rybchenko 	/* Set up the new descriptor queue */
18315e111ed8SAndrew Rybchenko 	EFX_POPULATE_OWORD_7(oword,
18325e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_BUF_BASE_ID, id,
18335e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_EVQ_ID, eep->ee_index,
18345e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_OWNER_ID, 0,
18355e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_LABEL, label,
18365e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_SIZE, size,
18375e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_TYPE, 0,
18385e111ed8SAndrew Rybchenko 	    FRF_AZ_RX_DESCQ_JUMBO, jumbo);
18395e111ed8SAndrew Rybchenko 
18405e111ed8SAndrew Rybchenko 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL,
18415e111ed8SAndrew Rybchenko 			    erp->er_index, &oword, B_TRUE);
18425e111ed8SAndrew Rybchenko 
18436bba823fSAndrew Rybchenko 	erp->er_prefix_layout = siena_toeplitz_rx_prefix_layout;
18446bba823fSAndrew Rybchenko 
18455e111ed8SAndrew Rybchenko 	return (0);
18465e111ed8SAndrew Rybchenko 
18475e111ed8SAndrew Rybchenko fail3:
18485e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail3);
18495e111ed8SAndrew Rybchenko fail2:
18505e111ed8SAndrew Rybchenko 	EFSYS_PROBE(fail2);
18515e111ed8SAndrew Rybchenko fail1:
18525e111ed8SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
18535e111ed8SAndrew Rybchenko 
18545e111ed8SAndrew Rybchenko 	return (rc);
18555e111ed8SAndrew Rybchenko }
18565e111ed8SAndrew Rybchenko 
18575e111ed8SAndrew Rybchenko static		void
siena_rx_qdestroy(__in efx_rxq_t * erp)18585e111ed8SAndrew Rybchenko siena_rx_qdestroy(
18595e111ed8SAndrew Rybchenko 	__in	efx_rxq_t *erp)
18605e111ed8SAndrew Rybchenko {
18615e111ed8SAndrew Rybchenko 	efx_nic_t *enp = erp->er_enp;
18625e111ed8SAndrew Rybchenko 	efx_oword_t oword;
18635e111ed8SAndrew Rybchenko 
18645e111ed8SAndrew Rybchenko 	/* Purge descriptor queue */
18655e111ed8SAndrew Rybchenko 	EFX_ZERO_OWORD(oword);
18665e111ed8SAndrew Rybchenko 
18675e111ed8SAndrew Rybchenko 	EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL,
18685e111ed8SAndrew Rybchenko 			    erp->er_index, &oword, B_TRUE);
18695e111ed8SAndrew Rybchenko }
18705e111ed8SAndrew Rybchenko 
18715e111ed8SAndrew Rybchenko static		void
siena_rx_fini(__in efx_nic_t * enp)18725e111ed8SAndrew Rybchenko siena_rx_fini(
18735e111ed8SAndrew Rybchenko 	__in	efx_nic_t *enp)
18745e111ed8SAndrew Rybchenko {
18755e111ed8SAndrew Rybchenko 	_NOTE(ARGUNUSED(enp))
18765e111ed8SAndrew Rybchenko }
18775e111ed8SAndrew Rybchenko 
18785e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
1879840478c2SAndrew Rybchenko 
1880840478c2SAndrew Rybchenko static	__checkReturn	boolean_t
efx_rx_prefix_layout_fields_match(__in const efx_rx_prefix_field_info_t * erpfip1,__in const efx_rx_prefix_field_info_t * erpfip2)1881840478c2SAndrew Rybchenko efx_rx_prefix_layout_fields_match(
1882840478c2SAndrew Rybchenko 	__in		const efx_rx_prefix_field_info_t *erpfip1,
1883840478c2SAndrew Rybchenko 	__in		const efx_rx_prefix_field_info_t *erpfip2)
1884840478c2SAndrew Rybchenko {
1885840478c2SAndrew Rybchenko 	if (erpfip1->erpfi_offset_bits != erpfip2->erpfi_offset_bits)
1886840478c2SAndrew Rybchenko 		return (B_FALSE);
1887840478c2SAndrew Rybchenko 
1888840478c2SAndrew Rybchenko 	if (erpfip1->erpfi_width_bits != erpfip2->erpfi_width_bits)
1889840478c2SAndrew Rybchenko 		return (B_FALSE);
1890840478c2SAndrew Rybchenko 
1891840478c2SAndrew Rybchenko 	if (erpfip1->erpfi_big_endian != erpfip2->erpfi_big_endian)
1892840478c2SAndrew Rybchenko 		return (B_FALSE);
1893840478c2SAndrew Rybchenko 
1894840478c2SAndrew Rybchenko 	return (B_TRUE);
1895840478c2SAndrew Rybchenko }
1896840478c2SAndrew Rybchenko 
1897840478c2SAndrew Rybchenko 	__checkReturn	uint32_t
efx_rx_prefix_layout_check(__in const efx_rx_prefix_layout_t * available,__in const efx_rx_prefix_layout_t * wanted)1898840478c2SAndrew Rybchenko efx_rx_prefix_layout_check(
1899840478c2SAndrew Rybchenko 	__in		const efx_rx_prefix_layout_t *available,
1900840478c2SAndrew Rybchenko 	__in		const efx_rx_prefix_layout_t *wanted)
1901840478c2SAndrew Rybchenko {
1902840478c2SAndrew Rybchenko 	uint32_t result = 0;
1903840478c2SAndrew Rybchenko 	unsigned int i;
1904840478c2SAndrew Rybchenko 
1905840478c2SAndrew Rybchenko 	EFX_STATIC_ASSERT(EFX_RX_PREFIX_NFIELDS < sizeof (result) * 8);
1906840478c2SAndrew Rybchenko 	for (i = 0; i < EFX_RX_PREFIX_NFIELDS; ++i) {
1907840478c2SAndrew Rybchenko 		/* Skip the field if driver does not want to use it */
1908840478c2SAndrew Rybchenko 		if (wanted->erpl_fields[i].erpfi_width_bits == 0)
1909840478c2SAndrew Rybchenko 			continue;
1910840478c2SAndrew Rybchenko 
1911840478c2SAndrew Rybchenko 		if (efx_rx_prefix_layout_fields_match(
1912840478c2SAndrew Rybchenko 			    &available->erpl_fields[i],
1913840478c2SAndrew Rybchenko 			    &wanted->erpl_fields[i]) == B_FALSE)
1914840478c2SAndrew Rybchenko 			result |= (1U << i);
1915840478c2SAndrew Rybchenko 	}
1916840478c2SAndrew Rybchenko 
1917840478c2SAndrew Rybchenko 	return (result);
1918840478c2SAndrew Rybchenko }
1919