xref: /dpdk/drivers/common/sfc_efx/base/rhead_tunnel.c (revision 672386c1e9e1f64f7aa3b1360ad22dc737ea8d72)
1d874d2a1SIgor Romanov /* SPDX-License-Identifier: BSD-3-Clause
2d874d2a1SIgor Romanov  *
3*672386c1SAndrew Rybchenko  * Copyright(c) 2021 Xilinx, Inc.
4d874d2a1SIgor Romanov  */
5d874d2a1SIgor Romanov 
6d874d2a1SIgor Romanov #include "efx.h"
7d874d2a1SIgor Romanov #include "efx_impl.h"
8d874d2a1SIgor Romanov 
9d874d2a1SIgor Romanov #if EFSYS_OPT_RIVERHEAD && EFSYS_OPT_TUNNEL
10d874d2a1SIgor Romanov 
11d874d2a1SIgor Romanov /* Match by Ether-type */
12d874d2a1SIgor Romanov #define	EFX_VNIC_ENCAP_RULE_MATCH_ETHER_TYPE \
13d874d2a1SIgor Romanov 	(1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_ETHER_TYPE_LBN)
14d874d2a1SIgor Romanov /* Match by outer VLAN ID */
15d874d2a1SIgor Romanov #define	EFX_VNIC_ENCAP_RULE_MATCH_OUTER_VID \
16d874d2a1SIgor Romanov 	(1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_OUTER_VLAN_LBN)
17d874d2a1SIgor Romanov /* Match by local IP host address */
18d874d2a1SIgor Romanov #define	EFX_VNIC_ENCAP_RULE_MATCH_LOC_HOST \
19d874d2a1SIgor Romanov 	(1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_DST_IP_LBN)
20d874d2a1SIgor Romanov /* Match by IP transport protocol */
21d874d2a1SIgor Romanov #define	EFX_VNIC_ENCAP_RULE_MATCH_IP_PROTO \
22d874d2a1SIgor Romanov 	(1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_IP_PROTO_LBN)
23d874d2a1SIgor Romanov /* Match by local TCP/UDP port */
24d874d2a1SIgor Romanov #define	EFX_VNIC_ENCAP_RULE_MATCH_LOC_PORT \
25d874d2a1SIgor Romanov 	(1u << MC_CMD_VNIC_ENCAP_RULE_ADD_IN_MATCH_DST_PORT_LBN)
26d874d2a1SIgor Romanov 
27d874d2a1SIgor Romanov /*
28d874d2a1SIgor Romanov  * Helper structure to pass parameters to MCDI function to add a VNIC
29d874d2a1SIgor Romanov  * encapsulation rule.
30d874d2a1SIgor Romanov  */
31d874d2a1SIgor Romanov typedef struct efx_vnic_encap_rule_spec_s {
32d874d2a1SIgor Romanov 	uint32_t		evers_mport_selector; /* Host-endian */
33d874d2a1SIgor Romanov 	uint32_t		evers_match_flags; /* Host-endian */
34d874d2a1SIgor Romanov 	uint16_t		evers_ether_type; /* Host-endian */
35d874d2a1SIgor Romanov 	uint16_t		evers_outer_vid; /* Host-endian */
36d874d2a1SIgor Romanov 	efx_oword_t		evers_loc_host; /* Big-endian */
37d874d2a1SIgor Romanov 	uint8_t			evers_ip_proto;
38d874d2a1SIgor Romanov 	uint16_t		evers_loc_port; /* Host-endian */
39d874d2a1SIgor Romanov 	efx_tunnel_protocol_t	evers_encap_type;
40d874d2a1SIgor Romanov } efx_vnic_encap_rule_spec_t;
41d874d2a1SIgor Romanov 
42d874d2a1SIgor Romanov static				uint32_t
efx_tunnel_protocol2mae_encap_type(__in efx_tunnel_protocol_t proto,__out uint32_t * typep)43d874d2a1SIgor Romanov efx_tunnel_protocol2mae_encap_type(
44d874d2a1SIgor Romanov 	__in		efx_tunnel_protocol_t proto,
45d874d2a1SIgor Romanov 	__out		uint32_t *typep)
46d874d2a1SIgor Romanov {
47d874d2a1SIgor Romanov 	efx_rc_t rc;
48d874d2a1SIgor Romanov 
49d874d2a1SIgor Romanov 	switch (proto) {
50d874d2a1SIgor Romanov 	case EFX_TUNNEL_PROTOCOL_NONE:
51d874d2a1SIgor Romanov 		*typep = MAE_MCDI_ENCAP_TYPE_NONE;
52d874d2a1SIgor Romanov 		break;
53d874d2a1SIgor Romanov 	case EFX_TUNNEL_PROTOCOL_VXLAN:
54d874d2a1SIgor Romanov 		*typep = MAE_MCDI_ENCAP_TYPE_VXLAN;
55d874d2a1SIgor Romanov 		break;
56d874d2a1SIgor Romanov 	case EFX_TUNNEL_PROTOCOL_GENEVE:
57d874d2a1SIgor Romanov 		*typep = MAE_MCDI_ENCAP_TYPE_GENEVE;
58d874d2a1SIgor Romanov 		break;
59d874d2a1SIgor Romanov 	case EFX_TUNNEL_PROTOCOL_NVGRE:
60d874d2a1SIgor Romanov 		*typep = MAE_MCDI_ENCAP_TYPE_NVGRE;
61d874d2a1SIgor Romanov 		break;
62d874d2a1SIgor Romanov 	default:
63d874d2a1SIgor Romanov 		rc = EINVAL;
64d874d2a1SIgor Romanov 		goto fail1;
65d874d2a1SIgor Romanov 	}
66d874d2a1SIgor Romanov 
67d874d2a1SIgor Romanov 	return (0);
68d874d2a1SIgor Romanov 
69d874d2a1SIgor Romanov fail1:
70d874d2a1SIgor Romanov 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
71d874d2a1SIgor Romanov 
72d874d2a1SIgor Romanov 	return (rc);
73d874d2a1SIgor Romanov }
74d874d2a1SIgor Romanov 
75d874d2a1SIgor Romanov static	__checkReturn		efx_rc_t
efx_mcdi_vnic_encap_rule_add(__in efx_nic_t * enp,__in const efx_vnic_encap_rule_spec_t * spec,__out efx_vnic_encap_rule_handle_t * handle)76d874d2a1SIgor Romanov efx_mcdi_vnic_encap_rule_add(
77d874d2a1SIgor Romanov 	__in			efx_nic_t *enp,
78d874d2a1SIgor Romanov 	__in			const efx_vnic_encap_rule_spec_t *spec,
79d874d2a1SIgor Romanov 	__out			efx_vnic_encap_rule_handle_t *handle)
80d874d2a1SIgor Romanov 
81d874d2a1SIgor Romanov {
82d874d2a1SIgor Romanov 	efx_mcdi_req_t req;
83d874d2a1SIgor Romanov 	EFX_MCDI_DECLARE_BUF(payload,
84d874d2a1SIgor Romanov 		MC_CMD_VNIC_ENCAP_RULE_ADD_IN_LEN,
85d874d2a1SIgor Romanov 		MC_CMD_VNIC_ENCAP_RULE_ADD_OUT_LEN);
86d874d2a1SIgor Romanov 	uint32_t encap_type;
87d874d2a1SIgor Romanov 	efx_rc_t rc;
88d874d2a1SIgor Romanov 
89d874d2a1SIgor Romanov 	req.emr_cmd = MC_CMD_VNIC_ENCAP_RULE_ADD;
90d874d2a1SIgor Romanov 	req.emr_in_buf = payload;
91d874d2a1SIgor Romanov 	req.emr_in_length = MC_CMD_VNIC_ENCAP_RULE_ADD_IN_LEN;
92d874d2a1SIgor Romanov 	req.emr_out_buf = payload;
93d874d2a1SIgor Romanov 	req.emr_out_length = MC_CMD_VNIC_ENCAP_RULE_ADD_OUT_LEN;
94d874d2a1SIgor Romanov 
95d874d2a1SIgor Romanov 	MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_ADD_IN_MPORT_SELECTOR,
96d874d2a1SIgor Romanov 	    spec->evers_mport_selector);
97d874d2a1SIgor Romanov 	MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_ADD_IN_MATCH_FLAGS,
98d874d2a1SIgor Romanov 	    spec->evers_match_flags);
99d874d2a1SIgor Romanov 
100d874d2a1SIgor Romanov 	MCDI_IN_SET_WORD_NATIVE(req, VNIC_ENCAP_RULE_ADD_IN_ETHER_TYPE,
101d874d2a1SIgor Romanov 	    __CPU_TO_BE_16(spec->evers_ether_type));
102d874d2a1SIgor Romanov 	MCDI_IN_SET_WORD_NATIVE(req, VNIC_ENCAP_RULE_ADD_IN_OUTER_VLAN_WORD,
103d874d2a1SIgor Romanov 	    __CPU_TO_BE_16(spec->evers_outer_vid));
104d874d2a1SIgor Romanov 
105d874d2a1SIgor Romanov 	/*
106d874d2a1SIgor Romanov 	 * Address is already in network order as well as the MCDI field,
107d874d2a1SIgor Romanov 	 * so plain copy is used.
108d874d2a1SIgor Romanov 	 */
109d874d2a1SIgor Romanov 	EFX_STATIC_ASSERT(sizeof (spec->evers_loc_host) ==
110d874d2a1SIgor Romanov 	    MC_CMD_VNIC_ENCAP_RULE_ADD_IN_DST_IP_LEN);
111d874d2a1SIgor Romanov 	memcpy(MCDI_IN2(req, uint8_t, VNIC_ENCAP_RULE_ADD_IN_DST_IP),
112d874d2a1SIgor Romanov 	    &spec->evers_loc_host.eo_byte[0],
113d874d2a1SIgor Romanov 	    MC_CMD_VNIC_ENCAP_RULE_ADD_IN_DST_IP_LEN);
114d874d2a1SIgor Romanov 
115d874d2a1SIgor Romanov 	MCDI_IN_SET_BYTE(req, VNIC_ENCAP_RULE_ADD_IN_IP_PROTO,
116d874d2a1SIgor Romanov 	    spec->evers_ip_proto);
117d874d2a1SIgor Romanov 	MCDI_IN_SET_WORD_NATIVE(req, VNIC_ENCAP_RULE_ADD_IN_DST_PORT,
118d874d2a1SIgor Romanov 	    __CPU_TO_BE_16(spec->evers_loc_port));
119d874d2a1SIgor Romanov 
120d874d2a1SIgor Romanov 	rc = efx_tunnel_protocol2mae_encap_type(spec->evers_encap_type,
121d874d2a1SIgor Romanov 	    &encap_type);
122d874d2a1SIgor Romanov 	if (rc != 0)
123d874d2a1SIgor Romanov 		goto fail1;
124d874d2a1SIgor Romanov 
125d874d2a1SIgor Romanov 	MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_ADD_IN_ENCAP_TYPE, encap_type);
126d874d2a1SIgor Romanov 
127d874d2a1SIgor Romanov 	efx_mcdi_execute(enp, &req);
128d874d2a1SIgor Romanov 
129d874d2a1SIgor Romanov 	if (req.emr_rc != 0) {
130d874d2a1SIgor Romanov 		rc = req.emr_rc;
131d874d2a1SIgor Romanov 		goto fail2;
132d874d2a1SIgor Romanov 	}
133d874d2a1SIgor Romanov 
134d874d2a1SIgor Romanov 	if (req.emr_out_length_used != MC_CMD_VNIC_ENCAP_RULE_ADD_OUT_LEN) {
135d874d2a1SIgor Romanov 		rc = EMSGSIZE;
136d874d2a1SIgor Romanov 		goto fail3;
137d874d2a1SIgor Romanov 	}
138d874d2a1SIgor Romanov 
139d874d2a1SIgor Romanov 	if (handle != NULL)
140d874d2a1SIgor Romanov 		*handle = MCDI_OUT_DWORD(req, VNIC_ENCAP_RULE_ADD_OUT_HANDLE);
141d874d2a1SIgor Romanov 
142d874d2a1SIgor Romanov 	return (0);
143d874d2a1SIgor Romanov 
144d874d2a1SIgor Romanov fail3:
145d874d2a1SIgor Romanov 	EFSYS_PROBE(fail3);
146d874d2a1SIgor Romanov 
147d874d2a1SIgor Romanov fail2:
148d874d2a1SIgor Romanov 	EFSYS_PROBE(fail2);
149d874d2a1SIgor Romanov 
150d874d2a1SIgor Romanov fail1:
151d874d2a1SIgor Romanov 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
152d874d2a1SIgor Romanov 
153d874d2a1SIgor Romanov 	return (rc);
154d874d2a1SIgor Romanov }
155d874d2a1SIgor Romanov 
156d874d2a1SIgor Romanov static	__checkReturn		efx_rc_t
efx_mcdi_vnic_encap_rule_remove(__in efx_nic_t * enp,__in efx_vnic_encap_rule_handle_t handle)157d874d2a1SIgor Romanov efx_mcdi_vnic_encap_rule_remove(
158d874d2a1SIgor Romanov 	__in			efx_nic_t *enp,
159d874d2a1SIgor Romanov 	__in			efx_vnic_encap_rule_handle_t handle)
160d874d2a1SIgor Romanov 
161d874d2a1SIgor Romanov {
162d874d2a1SIgor Romanov 	efx_mcdi_req_t req;
163d874d2a1SIgor Romanov 	EFX_MCDI_DECLARE_BUF(payload,
164d874d2a1SIgor Romanov 	    MC_CMD_VNIC_ENCAP_RULE_REMOVE_IN_LEN,
165d874d2a1SIgor Romanov 	    MC_CMD_VNIC_ENCAP_RULE_REMOVE_OUT_LEN);
166d874d2a1SIgor Romanov 	efx_rc_t rc;
167d874d2a1SIgor Romanov 
168d874d2a1SIgor Romanov 	req.emr_cmd = MC_CMD_VNIC_ENCAP_RULE_REMOVE;
169d874d2a1SIgor Romanov 	req.emr_in_buf = payload;
170d874d2a1SIgor Romanov 	req.emr_in_length = MC_CMD_VNIC_ENCAP_RULE_REMOVE_IN_LEN;
171d874d2a1SIgor Romanov 	req.emr_out_buf = payload;
172d874d2a1SIgor Romanov 	req.emr_out_length = MC_CMD_VNIC_ENCAP_RULE_REMOVE_OUT_LEN;
173d874d2a1SIgor Romanov 
174d874d2a1SIgor Romanov 	MCDI_IN_SET_DWORD(req, VNIC_ENCAP_RULE_REMOVE_IN_HANDLE, handle);
175d874d2a1SIgor Romanov 
176d874d2a1SIgor Romanov 	efx_mcdi_execute(enp, &req);
177d874d2a1SIgor Romanov 
178d874d2a1SIgor Romanov 	if (req.emr_rc != 0) {
179d874d2a1SIgor Romanov 		rc = req.emr_rc;
180d874d2a1SIgor Romanov 		goto fail1;
181d874d2a1SIgor Romanov 	}
182d874d2a1SIgor Romanov 
183d874d2a1SIgor Romanov 	if (req.emr_out_length_used != MC_CMD_VNIC_ENCAP_RULE_REMOVE_OUT_LEN) {
184d874d2a1SIgor Romanov 		rc = EMSGSIZE;
185d874d2a1SIgor Romanov 		goto fail2;
186d874d2a1SIgor Romanov 	}
187d874d2a1SIgor Romanov 
188d874d2a1SIgor Romanov 	return (0);
189d874d2a1SIgor Romanov 
190d874d2a1SIgor Romanov fail2:
191d874d2a1SIgor Romanov 	EFSYS_PROBE(fail2);
192d874d2a1SIgor Romanov 
193d874d2a1SIgor Romanov fail1:
194d874d2a1SIgor Romanov 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
195d874d2a1SIgor Romanov 
196d874d2a1SIgor Romanov 	return (rc);
197d874d2a1SIgor Romanov }
198d874d2a1SIgor Romanov 
199d874d2a1SIgor Romanov static			void
rhead_vnic_encap_rule_spec_init(__in const efx_tunnel_udp_entry_t * etuep,__out efx_vnic_encap_rule_spec_t * spec)200d874d2a1SIgor Romanov rhead_vnic_encap_rule_spec_init(
201d874d2a1SIgor Romanov 	__in		const efx_tunnel_udp_entry_t *etuep,
202d874d2a1SIgor Romanov 	__out		efx_vnic_encap_rule_spec_t *spec)
203d874d2a1SIgor Romanov {
204d874d2a1SIgor Romanov 	memset(spec, 0, sizeof (*spec));
205d874d2a1SIgor Romanov 
206d874d2a1SIgor Romanov 	spec->evers_mport_selector = MAE_MPORT_SELECTOR_ASSIGNED;
207d874d2a1SIgor Romanov 	spec->evers_match_flags = EFX_VNIC_ENCAP_RULE_MATCH_IP_PROTO |
208d874d2a1SIgor Romanov 	    EFX_VNIC_ENCAP_RULE_MATCH_LOC_PORT;
209d874d2a1SIgor Romanov 	spec->evers_ip_proto = EFX_IPPROTO_UDP;
210d874d2a1SIgor Romanov 	spec->evers_loc_port = etuep->etue_port;
211d874d2a1SIgor Romanov 	spec->evers_encap_type = etuep->etue_protocol;
212d874d2a1SIgor Romanov }
213d874d2a1SIgor Romanov 
214d874d2a1SIgor Romanov static	__checkReturn	efx_rc_t
rhead_udp_port_tunnel_add(__in efx_nic_t * enp,__inout efx_tunnel_udp_entry_t * etuep)215d874d2a1SIgor Romanov rhead_udp_port_tunnel_add(
216d874d2a1SIgor Romanov 	__in		efx_nic_t *enp,
217d874d2a1SIgor Romanov 	__inout		efx_tunnel_udp_entry_t *etuep)
218d874d2a1SIgor Romanov {
219d874d2a1SIgor Romanov 	efx_vnic_encap_rule_spec_t spec;
220d874d2a1SIgor Romanov 
221d874d2a1SIgor Romanov 	rhead_vnic_encap_rule_spec_init(etuep, &spec);
222d874d2a1SIgor Romanov 	return (efx_mcdi_vnic_encap_rule_add(enp, &spec, &etuep->etue_handle));
223d874d2a1SIgor Romanov }
224d874d2a1SIgor Romanov 
225d874d2a1SIgor Romanov static	__checkReturn	efx_rc_t
rhead_udp_port_tunnel_remove(__in efx_nic_t * enp,__in efx_tunnel_udp_entry_t * etuep)226d874d2a1SIgor Romanov rhead_udp_port_tunnel_remove(
227d874d2a1SIgor Romanov 	__in		efx_nic_t *enp,
228d874d2a1SIgor Romanov 	__in		efx_tunnel_udp_entry_t *etuep)
229d874d2a1SIgor Romanov {
230d874d2a1SIgor Romanov 	return (efx_mcdi_vnic_encap_rule_remove(enp, etuep->etue_handle));
231d874d2a1SIgor Romanov }
232d874d2a1SIgor Romanov 
233d874d2a1SIgor Romanov 	__checkReturn	efx_rc_t
rhead_tunnel_reconfigure(__in efx_nic_t * enp)234d874d2a1SIgor Romanov rhead_tunnel_reconfigure(
235d874d2a1SIgor Romanov 	__in		efx_nic_t *enp)
236d874d2a1SIgor Romanov {
237d874d2a1SIgor Romanov 	efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
238d874d2a1SIgor Romanov 	efx_rc_t rc;
239d874d2a1SIgor Romanov 	efsys_lock_state_t state;
240d874d2a1SIgor Romanov 	efx_tunnel_cfg_t etc;
241d874d2a1SIgor Romanov 	efx_tunnel_cfg_t added;
242d874d2a1SIgor Romanov 	unsigned int i;
243d874d2a1SIgor Romanov 	unsigned int j;
244d874d2a1SIgor Romanov 
245d874d2a1SIgor Romanov 	memset(&added, 0, sizeof(added));
246d874d2a1SIgor Romanov 
247d874d2a1SIgor Romanov 	/*
248d874d2a1SIgor Romanov 	 * Make a local copy of UDP tunnel table to release the lock
249d874d2a1SIgor Romanov 	 * when executing MCDIs.
250d874d2a1SIgor Romanov 	 */
251d874d2a1SIgor Romanov 	EFSYS_LOCK(enp->en_eslp, state);
252d874d2a1SIgor Romanov 	memcpy(&etc, etcp, sizeof (etc));
253d874d2a1SIgor Romanov 	EFSYS_UNLOCK(enp->en_eslp, state);
254d874d2a1SIgor Romanov 
255d874d2a1SIgor Romanov 	for (i = 0; i < etc.etc_udp_entries_num; i++) {
256d874d2a1SIgor Romanov 		efx_tunnel_udp_entry_t *etc_entry = &etc.etc_udp_entries[i];
257d874d2a1SIgor Romanov 
258d874d2a1SIgor Romanov 		if (etc_entry->etue_busy == B_FALSE)
259d874d2a1SIgor Romanov 			continue;
260d874d2a1SIgor Romanov 
261d874d2a1SIgor Romanov 		switch (etc_entry->etue_state) {
262d874d2a1SIgor Romanov 		case EFX_TUNNEL_UDP_ENTRY_APPLIED:
263d874d2a1SIgor Romanov 			break;
264d874d2a1SIgor Romanov 		case EFX_TUNNEL_UDP_ENTRY_ADDED:
265d874d2a1SIgor Romanov 			rc = rhead_udp_port_tunnel_add(enp, etc_entry);
266d874d2a1SIgor Romanov 			if (rc != 0)
267d874d2a1SIgor Romanov 				goto fail1;
268d874d2a1SIgor Romanov 			added.etc_udp_entries[added.etc_udp_entries_num] =
269d874d2a1SIgor Romanov 			    *etc_entry;
270d874d2a1SIgor Romanov 			added.etc_udp_entries_num++;
271d874d2a1SIgor Romanov 			break;
272d874d2a1SIgor Romanov 		case EFX_TUNNEL_UDP_ENTRY_REMOVED:
273d874d2a1SIgor Romanov 			rc = rhead_udp_port_tunnel_remove(enp, etc_entry);
274d874d2a1SIgor Romanov 			if (rc != 0)
275d874d2a1SIgor Romanov 				goto fail2;
276d874d2a1SIgor Romanov 			break;
277d874d2a1SIgor Romanov 		default:
278d874d2a1SIgor Romanov 			EFSYS_ASSERT(0);
279d874d2a1SIgor Romanov 			break;
280d874d2a1SIgor Romanov 		}
281d874d2a1SIgor Romanov 	}
282d874d2a1SIgor Romanov 
283d874d2a1SIgor Romanov 	EFSYS_LOCK(enp->en_eslp, state);
284d874d2a1SIgor Romanov 
285d874d2a1SIgor Romanov 	/*
286d874d2a1SIgor Romanov 	 * Adding or removing non-busy entries does not change the
287d874d2a1SIgor Romanov 	 * order of busy entries. Therefore one linear search iteration
288d874d2a1SIgor Romanov 	 * suffices.
289d874d2a1SIgor Romanov 	 */
290d874d2a1SIgor Romanov 	for (i = 0, j = 0; i < etcp->etc_udp_entries_num; i++) {
291d874d2a1SIgor Romanov 		efx_tunnel_udp_entry_t *cur_entry = &etcp->etc_udp_entries[i];
292d874d2a1SIgor Romanov 		efx_tunnel_udp_entry_t *added_entry = &added.etc_udp_entries[j];
293d874d2a1SIgor Romanov 
294d874d2a1SIgor Romanov 		if (cur_entry->etue_state == EFX_TUNNEL_UDP_ENTRY_ADDED &&
295d874d2a1SIgor Romanov 		    cur_entry->etue_port == added_entry->etue_port) {
296d874d2a1SIgor Romanov 			cur_entry->etue_handle = added_entry->etue_handle;
297d874d2a1SIgor Romanov 			j++;
298d874d2a1SIgor Romanov 		}
299d874d2a1SIgor Romanov 	}
300d874d2a1SIgor Romanov 
301d874d2a1SIgor Romanov 	EFSYS_UNLOCK(enp->en_eslp, state);
302d874d2a1SIgor Romanov 
303d874d2a1SIgor Romanov 	return (0);
304d874d2a1SIgor Romanov 
305d874d2a1SIgor Romanov fail2:
306d874d2a1SIgor Romanov 	EFSYS_PROBE(fail2);
307d874d2a1SIgor Romanov 
308d874d2a1SIgor Romanov fail1:
309d874d2a1SIgor Romanov 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
310d874d2a1SIgor Romanov 
311d874d2a1SIgor Romanov 	while (i-- > 0) {
312d874d2a1SIgor Romanov 		if (etc.etc_udp_entries[i].etue_busy == B_FALSE)
313d874d2a1SIgor Romanov 			continue;
314d874d2a1SIgor Romanov 
315d874d2a1SIgor Romanov 		switch (etc.etc_udp_entries[i].etue_state) {
316d874d2a1SIgor Romanov 		case EFX_TUNNEL_UDP_ENTRY_APPLIED:
317d874d2a1SIgor Romanov 			break;
318d874d2a1SIgor Romanov 		case EFX_TUNNEL_UDP_ENTRY_ADDED:
319d874d2a1SIgor Romanov 			(void) rhead_udp_port_tunnel_remove(enp,
320d874d2a1SIgor Romanov 					&etc.etc_udp_entries[i]);
321d874d2a1SIgor Romanov 			break;
322d874d2a1SIgor Romanov 		case EFX_TUNNEL_UDP_ENTRY_REMOVED:
323d874d2a1SIgor Romanov 			(void) rhead_udp_port_tunnel_add(enp,
324d874d2a1SIgor Romanov 					&etc.etc_udp_entries[i]);
325d874d2a1SIgor Romanov 			break;
326d874d2a1SIgor Romanov 		default:
327d874d2a1SIgor Romanov 			EFSYS_ASSERT(0);
328d874d2a1SIgor Romanov 			break;
329d874d2a1SIgor Romanov 		}
330d874d2a1SIgor Romanov 	}
331d874d2a1SIgor Romanov 
332d874d2a1SIgor Romanov 	return (rc);
333d874d2a1SIgor Romanov }
334d874d2a1SIgor Romanov 
335d874d2a1SIgor Romanov 			void
rhead_tunnel_fini(__in efx_nic_t * enp)336d874d2a1SIgor Romanov rhead_tunnel_fini(
337d874d2a1SIgor Romanov 	__in		efx_nic_t *enp)
338d874d2a1SIgor Romanov {
339d874d2a1SIgor Romanov 	(void) efx_tunnel_config_clear(enp);
340d874d2a1SIgor Romanov 	(void) efx_tunnel_reconfigure(enp);
341d874d2a1SIgor Romanov }
342d874d2a1SIgor Romanov 
343d874d2a1SIgor Romanov #endif	/* EFSYS_OPT_RIVERHEAD && EFSYS_OPT_TUNNEL */
344