15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3*672386c1SAndrew 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
1072e9af05SIgor Romanov /*
1172e9af05SIgor Romanov * State diagram of the UDP tunnel table entries
1272e9af05SIgor Romanov * (efx_tunnel_udp_entry_state_t and busy flag):
1372e9af05SIgor Romanov *
1472e9af05SIgor Romanov * +---------+
1572e9af05SIgor Romanov * +--------| APPLIED |<-------+
1672e9af05SIgor Romanov * | +---------+ |
1772e9af05SIgor Romanov * | |
1872e9af05SIgor Romanov * | efx_tunnel_reconfigure (end)
1972e9af05SIgor Romanov * efx_tunnel_config_udp_remove |
2072e9af05SIgor Romanov * | +------------+
2172e9af05SIgor Romanov * v | BUSY ADDED |
2272e9af05SIgor Romanov * +---------+ +------------+
2372e9af05SIgor Romanov * | REMOVED | ^
2472e9af05SIgor Romanov * +---------+ |
2572e9af05SIgor Romanov * | efx_tunnel_reconfigure (begin)
2672e9af05SIgor Romanov * efx_tunnel_reconfigure (begin) |
2772e9af05SIgor Romanov * | |
2872e9af05SIgor Romanov * v +-----------+
2972e9af05SIgor Romanov * +--------------+ | ADDED |<---------+
3072e9af05SIgor Romanov * | BUSY REMOVED | +-----------+ |
3172e9af05SIgor Romanov * +--------------+ | |
3272e9af05SIgor Romanov * | efx_tunnel_config_udp_remove |
3372e9af05SIgor Romanov * efx_tunnel_reconfigure (end) | |
3472e9af05SIgor Romanov * | | |
3572e9af05SIgor Romanov * | +---------+ | |
3672e9af05SIgor Romanov * | |+-------+| | |
3772e9af05SIgor Romanov * +------->|| empty ||<-------+ |
3872e9af05SIgor Romanov * |+-------+| |
3972e9af05SIgor Romanov * +---------+ efx_tunnel_config_udp_add
4072e9af05SIgor Romanov * | |
4172e9af05SIgor Romanov * +------------------------------+
4272e9af05SIgor Romanov *
4372e9af05SIgor Romanov * Note that there is no BUSY APPLIED state since removing an applied entry
4472e9af05SIgor Romanov * should not be blocked by ongoing reconfiguration in another thread -
4572e9af05SIgor Romanov * reconfiguration will remove only busy entries.
4672e9af05SIgor Romanov */
475e111ed8SAndrew Rybchenko
485e111ed8SAndrew Rybchenko #if EFSYS_OPT_TUNNEL
495e111ed8SAndrew Rybchenko
505e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
515e111ed8SAndrew Rybchenko static __checkReturn boolean_t
525e111ed8SAndrew Rybchenko ef10_udp_encap_supported(
535e111ed8SAndrew Rybchenko __in efx_nic_t *enp);
545e111ed8SAndrew Rybchenko
555e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
565e111ed8SAndrew Rybchenko ef10_tunnel_reconfigure(
575e111ed8SAndrew Rybchenko __in efx_nic_t *enp);
585e111ed8SAndrew Rybchenko
594dda992fSIgor Romanov static void
604dda992fSIgor Romanov ef10_tunnel_fini(
614dda992fSIgor Romanov __in efx_nic_t *enp);
62d874d2a1SIgor Romanov #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
634dda992fSIgor Romanov
64d874d2a1SIgor Romanov #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON
65d874d2a1SIgor Romanov static const efx_tunnel_ops_t __efx_tunnel_dummy_ops = {
66d874d2a1SIgor Romanov NULL, /* eto_reconfigure */
67d874d2a1SIgor Romanov NULL, /* eto_fini */
68d874d2a1SIgor Romanov };
69d874d2a1SIgor Romanov #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON */
70d874d2a1SIgor Romanov
71d874d2a1SIgor Romanov #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
725e111ed8SAndrew Rybchenko static const efx_tunnel_ops_t __efx_tunnel_ef10_ops = {
735e111ed8SAndrew Rybchenko ef10_tunnel_reconfigure, /* eto_reconfigure */
744dda992fSIgor Romanov ef10_tunnel_fini, /* eto_fini */
755e111ed8SAndrew Rybchenko };
765e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
775e111ed8SAndrew Rybchenko
78d874d2a1SIgor Romanov #if EFSYS_OPT_RIVERHEAD
79d874d2a1SIgor Romanov static const efx_tunnel_ops_t __efx_tunnel_rhead_ops = {
80d874d2a1SIgor Romanov rhead_tunnel_reconfigure, /* eto_reconfigure */
81d874d2a1SIgor Romanov rhead_tunnel_fini, /* eto_fini */
82d874d2a1SIgor Romanov };
83d874d2a1SIgor Romanov #endif /* EFSYS_OPT_RIVERHEAD */
84d874d2a1SIgor Romanov
8572e9af05SIgor Romanov /* Indicates that an entry is to be set */
8672e9af05SIgor Romanov static __checkReturn boolean_t
ef10_entry_staged(__in efx_tunnel_udp_entry_t * entry)8772e9af05SIgor Romanov ef10_entry_staged(
8872e9af05SIgor Romanov __in efx_tunnel_udp_entry_t *entry)
8972e9af05SIgor Romanov {
9072e9af05SIgor Romanov switch (entry->etue_state) {
9172e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_ADDED:
9272e9af05SIgor Romanov return (entry->etue_busy);
9372e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_REMOVED:
9472e9af05SIgor Romanov return (!entry->etue_busy);
9572e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_APPLIED:
9672e9af05SIgor Romanov return (B_TRUE);
9772e9af05SIgor Romanov default:
9872e9af05SIgor Romanov EFSYS_ASSERT(0);
9972e9af05SIgor Romanov return (B_FALSE);
10072e9af05SIgor Romanov }
10172e9af05SIgor Romanov }
10272e9af05SIgor Romanov
1035e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
efx_mcdi_set_tunnel_encap_udp_ports(__in efx_nic_t * enp,__in efx_tunnel_cfg_t * etcp,__in boolean_t unloading,__out boolean_t * resetting)1045e111ed8SAndrew Rybchenko efx_mcdi_set_tunnel_encap_udp_ports(
1055e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1065e111ed8SAndrew Rybchenko __in efx_tunnel_cfg_t *etcp,
1075e111ed8SAndrew Rybchenko __in boolean_t unloading,
1085e111ed8SAndrew Rybchenko __out boolean_t *resetting)
1095e111ed8SAndrew Rybchenko {
1105e111ed8SAndrew Rybchenko efx_mcdi_req_t req;
1115e111ed8SAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload,
1125e111ed8SAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX,
1135e111ed8SAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN);
1145e111ed8SAndrew Rybchenko efx_word_t flags;
1155e111ed8SAndrew Rybchenko efx_rc_t rc;
1165e111ed8SAndrew Rybchenko unsigned int i;
1175e111ed8SAndrew Rybchenko unsigned int entries_num;
11872e9af05SIgor Romanov unsigned int entry;
1195e111ed8SAndrew Rybchenko
1205e111ed8SAndrew Rybchenko entries_num = 0;
12172e9af05SIgor Romanov if (etcp != NULL) {
12272e9af05SIgor Romanov for (i = 0; i < etcp->etc_udp_entries_num; i++) {
12372e9af05SIgor Romanov if (ef10_entry_staged(&etcp->etc_udp_entries[i]) !=
12472e9af05SIgor Romanov B_FALSE) {
12572e9af05SIgor Romanov entries_num++;
12672e9af05SIgor Romanov }
12772e9af05SIgor Romanov }
12872e9af05SIgor Romanov }
1295e111ed8SAndrew Rybchenko
1305e111ed8SAndrew Rybchenko req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS;
1315e111ed8SAndrew Rybchenko req.emr_in_buf = payload;
1325e111ed8SAndrew Rybchenko req.emr_in_length =
1335e111ed8SAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num);
1345e111ed8SAndrew Rybchenko req.emr_out_buf = payload;
1355e111ed8SAndrew Rybchenko req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN;
1365e111ed8SAndrew Rybchenko
1375e111ed8SAndrew Rybchenko EFX_POPULATE_WORD_1(flags,
1385e111ed8SAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING,
1395e111ed8SAndrew Rybchenko (unloading == B_TRUE) ? 1 : 0);
1405e111ed8SAndrew Rybchenko MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS,
1415e111ed8SAndrew Rybchenko EFX_WORD_FIELD(flags, EFX_WORD_0));
1425e111ed8SAndrew Rybchenko
1435e111ed8SAndrew Rybchenko MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES,
1445e111ed8SAndrew Rybchenko entries_num);
1455e111ed8SAndrew Rybchenko
14672e9af05SIgor Romanov for (i = 0, entry = 0; entry < entries_num; ++entry, ++i) {
1475e111ed8SAndrew Rybchenko uint16_t mcdi_udp_protocol;
1485e111ed8SAndrew Rybchenko
14972e9af05SIgor Romanov while (ef10_entry_staged(&etcp->etc_udp_entries[i]) == B_FALSE)
15072e9af05SIgor Romanov i++;
15172e9af05SIgor Romanov
1525e111ed8SAndrew Rybchenko switch (etcp->etc_udp_entries[i].etue_protocol) {
1535e111ed8SAndrew Rybchenko case EFX_TUNNEL_PROTOCOL_VXLAN:
1545e111ed8SAndrew Rybchenko mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN;
1555e111ed8SAndrew Rybchenko break;
1565e111ed8SAndrew Rybchenko case EFX_TUNNEL_PROTOCOL_GENEVE:
1575e111ed8SAndrew Rybchenko mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
1585e111ed8SAndrew Rybchenko break;
1595e111ed8SAndrew Rybchenko default:
1605e111ed8SAndrew Rybchenko rc = EINVAL;
1615e111ed8SAndrew Rybchenko goto fail1;
1625e111ed8SAndrew Rybchenko }
1635e111ed8SAndrew Rybchenko
1645e111ed8SAndrew Rybchenko /*
1655e111ed8SAndrew Rybchenko * UDP port is MCDI native little-endian in the request
1665e111ed8SAndrew Rybchenko * and EFX_POPULATE_DWORD cares about conversion from
1675e111ed8SAndrew Rybchenko * host/CPU byte order to little-endian.
1685e111ed8SAndrew Rybchenko */
1695e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (efx_dword_t) ==
1705e111ed8SAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN);
1715e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_2(
1725e111ed8SAndrew Rybchenko MCDI_IN2(req, efx_dword_t,
17372e9af05SIgor Romanov SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[entry],
1745e111ed8SAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT,
1755e111ed8SAndrew Rybchenko etcp->etc_udp_entries[i].etue_port,
1765e111ed8SAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL,
1775e111ed8SAndrew Rybchenko mcdi_udp_protocol);
1785e111ed8SAndrew Rybchenko }
1795e111ed8SAndrew Rybchenko
1805e111ed8SAndrew Rybchenko efx_mcdi_execute(enp, &req);
1815e111ed8SAndrew Rybchenko
1825e111ed8SAndrew Rybchenko if (req.emr_rc != 0) {
1835e111ed8SAndrew Rybchenko rc = req.emr_rc;
1845e111ed8SAndrew Rybchenko goto fail2;
1855e111ed8SAndrew Rybchenko }
1865e111ed8SAndrew Rybchenko
1875e111ed8SAndrew Rybchenko if (req.emr_out_length_used !=
1885e111ed8SAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) {
1895e111ed8SAndrew Rybchenko rc = EMSGSIZE;
1905e111ed8SAndrew Rybchenko goto fail3;
1915e111ed8SAndrew Rybchenko }
1925e111ed8SAndrew Rybchenko
1935e111ed8SAndrew Rybchenko *resetting = MCDI_OUT_WORD_FIELD(req,
1945e111ed8SAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS,
1955e111ed8SAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING);
1965e111ed8SAndrew Rybchenko
1975e111ed8SAndrew Rybchenko return (0);
1985e111ed8SAndrew Rybchenko
1995e111ed8SAndrew Rybchenko fail3:
2005e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
2015e111ed8SAndrew Rybchenko
2025e111ed8SAndrew Rybchenko fail2:
2035e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
2045e111ed8SAndrew Rybchenko
2055e111ed8SAndrew Rybchenko fail1:
2065e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2075e111ed8SAndrew Rybchenko
2085e111ed8SAndrew Rybchenko return (rc);
2095e111ed8SAndrew Rybchenko }
2105e111ed8SAndrew Rybchenko
2115e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_tunnel_init(__in efx_nic_t * enp)2125e111ed8SAndrew Rybchenko efx_tunnel_init(
2135e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
2145e111ed8SAndrew Rybchenko {
2155e111ed8SAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
2165e111ed8SAndrew Rybchenko const efx_tunnel_ops_t *etop;
2175e111ed8SAndrew Rybchenko efx_rc_t rc;
2185e111ed8SAndrew Rybchenko
2195e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2205e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2215e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL));
2225e111ed8SAndrew Rybchenko
2235e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES ==
2245e111ed8SAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM);
2255e111ed8SAndrew Rybchenko
2265e111ed8SAndrew Rybchenko switch (enp->en_family) {
2275e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
2285e111ed8SAndrew Rybchenko case EFX_FAMILY_SIENA:
2295e111ed8SAndrew Rybchenko etop = &__efx_tunnel_dummy_ops;
2305e111ed8SAndrew Rybchenko break;
2315e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
2325e111ed8SAndrew Rybchenko
2335e111ed8SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
2345e111ed8SAndrew Rybchenko case EFX_FAMILY_HUNTINGTON:
2355e111ed8SAndrew Rybchenko etop = &__efx_tunnel_dummy_ops;
2365e111ed8SAndrew Rybchenko break;
2375e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
2385e111ed8SAndrew Rybchenko
2395e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
2405e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD:
2415e111ed8SAndrew Rybchenko etop = &__efx_tunnel_ef10_ops;
2425e111ed8SAndrew Rybchenko break;
2435e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
2445e111ed8SAndrew Rybchenko
2455e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
2465e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD2:
2475e111ed8SAndrew Rybchenko etop = &__efx_tunnel_ef10_ops;
2485e111ed8SAndrew Rybchenko break;
2495e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
2505e111ed8SAndrew Rybchenko
251a33217d5SAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD
252a33217d5SAndrew Rybchenko case EFX_FAMILY_RIVERHEAD:
253d874d2a1SIgor Romanov etop = &__efx_tunnel_rhead_ops;
254a33217d5SAndrew Rybchenko break;
255a33217d5SAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */
256a33217d5SAndrew Rybchenko
2575e111ed8SAndrew Rybchenko default:
2585e111ed8SAndrew Rybchenko EFSYS_ASSERT(0);
2595e111ed8SAndrew Rybchenko rc = ENOTSUP;
2605e111ed8SAndrew Rybchenko goto fail1;
2615e111ed8SAndrew Rybchenko }
2625e111ed8SAndrew Rybchenko
2635e111ed8SAndrew Rybchenko memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
2645e111ed8SAndrew Rybchenko etcp->etc_udp_entries_num = 0;
2655e111ed8SAndrew Rybchenko
2665e111ed8SAndrew Rybchenko enp->en_etop = etop;
2675e111ed8SAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_TUNNEL;
2685e111ed8SAndrew Rybchenko
2695e111ed8SAndrew Rybchenko return (0);
2705e111ed8SAndrew Rybchenko
2715e111ed8SAndrew Rybchenko fail1:
2725e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2735e111ed8SAndrew Rybchenko
2745e111ed8SAndrew Rybchenko enp->en_etop = NULL;
2755e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
2765e111ed8SAndrew Rybchenko
2775e111ed8SAndrew Rybchenko return (rc);
2785e111ed8SAndrew Rybchenko }
2795e111ed8SAndrew Rybchenko
2805e111ed8SAndrew Rybchenko void
efx_tunnel_fini(__in efx_nic_t * enp)2815e111ed8SAndrew Rybchenko efx_tunnel_fini(
2825e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
2835e111ed8SAndrew Rybchenko {
2845e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2855e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2865e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
2875e111ed8SAndrew Rybchenko
2884dda992fSIgor Romanov if (enp->en_etop->eto_fini != NULL)
2894dda992fSIgor Romanov enp->en_etop->eto_fini(enp);
2905e111ed8SAndrew Rybchenko
2915e111ed8SAndrew Rybchenko enp->en_etop = NULL;
2925e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
2935e111ed8SAndrew Rybchenko }
2945e111ed8SAndrew Rybchenko
2955e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
efx_tunnel_config_find_udp_tunnel_entry(__in efx_tunnel_cfg_t * etcp,__in uint16_t port,__out unsigned int * entryp)2965e111ed8SAndrew Rybchenko efx_tunnel_config_find_udp_tunnel_entry(
2975e111ed8SAndrew Rybchenko __in efx_tunnel_cfg_t *etcp,
2985e111ed8SAndrew Rybchenko __in uint16_t port,
2995e111ed8SAndrew Rybchenko __out unsigned int *entryp)
3005e111ed8SAndrew Rybchenko {
3015e111ed8SAndrew Rybchenko unsigned int i;
3025e111ed8SAndrew Rybchenko
3035e111ed8SAndrew Rybchenko for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
3045e111ed8SAndrew Rybchenko efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
3055e111ed8SAndrew Rybchenko
30672e9af05SIgor Romanov if (p->etue_port == port &&
30772e9af05SIgor Romanov p->etue_state != EFX_TUNNEL_UDP_ENTRY_REMOVED) {
3085e111ed8SAndrew Rybchenko *entryp = i;
3095e111ed8SAndrew Rybchenko return (0);
3105e111ed8SAndrew Rybchenko }
3115e111ed8SAndrew Rybchenko }
3125e111ed8SAndrew Rybchenko
3135e111ed8SAndrew Rybchenko return (ENOENT);
3145e111ed8SAndrew Rybchenko }
3155e111ed8SAndrew Rybchenko
3165e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_tunnel_config_udp_add(__in efx_nic_t * enp,__in uint16_t port,__in efx_tunnel_protocol_t protocol)3175e111ed8SAndrew Rybchenko efx_tunnel_config_udp_add(
3185e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
3195e111ed8SAndrew Rybchenko __in uint16_t port /* host/cpu-endian */,
3205e111ed8SAndrew Rybchenko __in efx_tunnel_protocol_t protocol)
3215e111ed8SAndrew Rybchenko {
3225e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
3235e111ed8SAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
3245e111ed8SAndrew Rybchenko efsys_lock_state_t state;
3255e111ed8SAndrew Rybchenko efx_rc_t rc;
3265e111ed8SAndrew Rybchenko unsigned int entry;
3275e111ed8SAndrew Rybchenko
3285e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
3295e111ed8SAndrew Rybchenko
3305e111ed8SAndrew Rybchenko if (protocol >= EFX_TUNNEL_NPROTOS) {
3315e111ed8SAndrew Rybchenko rc = EINVAL;
3325e111ed8SAndrew Rybchenko goto fail1;
3335e111ed8SAndrew Rybchenko }
3345e111ed8SAndrew Rybchenko
3355e111ed8SAndrew Rybchenko if ((encp->enc_tunnel_encapsulations_supported &
3365e111ed8SAndrew Rybchenko (1u << protocol)) == 0) {
3375e111ed8SAndrew Rybchenko rc = ENOTSUP;
3385e111ed8SAndrew Rybchenko goto fail2;
3395e111ed8SAndrew Rybchenko }
3405e111ed8SAndrew Rybchenko
3415e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
3425e111ed8SAndrew Rybchenko
3435e111ed8SAndrew Rybchenko rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
3445e111ed8SAndrew Rybchenko if (rc == 0) {
3455e111ed8SAndrew Rybchenko rc = EEXIST;
3465e111ed8SAndrew Rybchenko goto fail3;
3475e111ed8SAndrew Rybchenko }
3485e111ed8SAndrew Rybchenko
3495e111ed8SAndrew Rybchenko if (etcp->etc_udp_entries_num ==
3505e111ed8SAndrew Rybchenko encp->enc_tunnel_config_udp_entries_max) {
3515e111ed8SAndrew Rybchenko rc = ENOSPC;
3525e111ed8SAndrew Rybchenko goto fail4;
3535e111ed8SAndrew Rybchenko }
3545e111ed8SAndrew Rybchenko
3555e111ed8SAndrew Rybchenko etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port;
3565e111ed8SAndrew Rybchenko etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol =
3575e111ed8SAndrew Rybchenko protocol;
35872e9af05SIgor Romanov etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_state =
35972e9af05SIgor Romanov EFX_TUNNEL_UDP_ENTRY_ADDED;
3605e111ed8SAndrew Rybchenko
3615e111ed8SAndrew Rybchenko etcp->etc_udp_entries_num++;
3625e111ed8SAndrew Rybchenko
3635e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
3645e111ed8SAndrew Rybchenko
3655e111ed8SAndrew Rybchenko return (0);
3665e111ed8SAndrew Rybchenko
3675e111ed8SAndrew Rybchenko fail4:
3685e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
3695e111ed8SAndrew Rybchenko
3705e111ed8SAndrew Rybchenko fail3:
3715e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
3725e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
3735e111ed8SAndrew Rybchenko
3745e111ed8SAndrew Rybchenko fail2:
3755e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
3765e111ed8SAndrew Rybchenko
3775e111ed8SAndrew Rybchenko fail1:
3785e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
3795e111ed8SAndrew Rybchenko
3805e111ed8SAndrew Rybchenko return (rc);
3815e111ed8SAndrew Rybchenko }
3825e111ed8SAndrew Rybchenko
38372e9af05SIgor Romanov /*
38472e9af05SIgor Romanov * Returns the index of the entry after the deleted one,
38572e9af05SIgor Romanov * or one past the last entry.
38672e9af05SIgor Romanov */
38772e9af05SIgor Romanov static unsigned int
efx_tunnel_config_udp_do_remove(__in efx_tunnel_cfg_t * etcp,__in unsigned int entry)38872e9af05SIgor Romanov efx_tunnel_config_udp_do_remove(
38972e9af05SIgor Romanov __in efx_tunnel_cfg_t *etcp,
39072e9af05SIgor Romanov __in unsigned int entry)
39172e9af05SIgor Romanov {
39272e9af05SIgor Romanov EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
39372e9af05SIgor Romanov etcp->etc_udp_entries_num--;
39472e9af05SIgor Romanov
39572e9af05SIgor Romanov if (entry < etcp->etc_udp_entries_num) {
39672e9af05SIgor Romanov memmove(&etcp->etc_udp_entries[entry],
39772e9af05SIgor Romanov &etcp->etc_udp_entries[entry + 1],
39872e9af05SIgor Romanov (etcp->etc_udp_entries_num - entry) *
39972e9af05SIgor Romanov sizeof (etcp->etc_udp_entries[0]));
40072e9af05SIgor Romanov }
40172e9af05SIgor Romanov
40272e9af05SIgor Romanov memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
40372e9af05SIgor Romanov sizeof (etcp->etc_udp_entries[0]));
40472e9af05SIgor Romanov
40572e9af05SIgor Romanov return (entry);
40672e9af05SIgor Romanov }
40772e9af05SIgor Romanov
40872e9af05SIgor Romanov /*
40972e9af05SIgor Romanov * Returns the index of the entry after the specified one,
41072e9af05SIgor Romanov * or one past the last entry. The index is correct whether
41172e9af05SIgor Romanov * the specified entry was removed or not.
41272e9af05SIgor Romanov */
41372e9af05SIgor Romanov static unsigned int
efx_tunnel_config_udp_remove_prepare(__in efx_tunnel_cfg_t * etcp,__in unsigned int entry)41472e9af05SIgor Romanov efx_tunnel_config_udp_remove_prepare(
41572e9af05SIgor Romanov __in efx_tunnel_cfg_t *etcp,
41672e9af05SIgor Romanov __in unsigned int entry)
41772e9af05SIgor Romanov {
41872e9af05SIgor Romanov unsigned int next = entry + 1;
41972e9af05SIgor Romanov
42072e9af05SIgor Romanov switch (etcp->etc_udp_entries[entry].etue_state) {
42172e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_ADDED:
42272e9af05SIgor Romanov next = efx_tunnel_config_udp_do_remove(etcp, entry);
42372e9af05SIgor Romanov break;
42472e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_REMOVED:
42572e9af05SIgor Romanov break;
42672e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_APPLIED:
42772e9af05SIgor Romanov etcp->etc_udp_entries[entry].etue_state =
42872e9af05SIgor Romanov EFX_TUNNEL_UDP_ENTRY_REMOVED;
42972e9af05SIgor Romanov break;
43072e9af05SIgor Romanov default:
43172e9af05SIgor Romanov EFSYS_ASSERT(0);
43272e9af05SIgor Romanov break;
43372e9af05SIgor Romanov }
43472e9af05SIgor Romanov
43572e9af05SIgor Romanov return (next);
43672e9af05SIgor Romanov }
43772e9af05SIgor Romanov
4385e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_tunnel_config_udp_remove(__in efx_nic_t * enp,__in uint16_t port,__in efx_tunnel_protocol_t protocol)4395e111ed8SAndrew Rybchenko efx_tunnel_config_udp_remove(
4405e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
4415e111ed8SAndrew Rybchenko __in uint16_t port /* host/cpu-endian */,
4425e111ed8SAndrew Rybchenko __in efx_tunnel_protocol_t protocol)
4435e111ed8SAndrew Rybchenko {
4445e111ed8SAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
4455e111ed8SAndrew Rybchenko efsys_lock_state_t state;
4465e111ed8SAndrew Rybchenko unsigned int entry;
4475e111ed8SAndrew Rybchenko efx_rc_t rc;
4485e111ed8SAndrew Rybchenko
4495e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
4505e111ed8SAndrew Rybchenko
4515e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
4525e111ed8SAndrew Rybchenko
4535e111ed8SAndrew Rybchenko rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
4545e111ed8SAndrew Rybchenko if (rc != 0)
4555e111ed8SAndrew Rybchenko goto fail1;
4565e111ed8SAndrew Rybchenko
45772e9af05SIgor Romanov if (etcp->etc_udp_entries[entry].etue_busy != B_FALSE) {
45872e9af05SIgor Romanov rc = EBUSY;
4595e111ed8SAndrew Rybchenko goto fail2;
4605e111ed8SAndrew Rybchenko }
4615e111ed8SAndrew Rybchenko
46272e9af05SIgor Romanov if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
46372e9af05SIgor Romanov rc = EINVAL;
46472e9af05SIgor Romanov goto fail3;
4655e111ed8SAndrew Rybchenko }
4665e111ed8SAndrew Rybchenko
46772e9af05SIgor Romanov (void) efx_tunnel_config_udp_remove_prepare(etcp, entry);
4685e111ed8SAndrew Rybchenko
4695e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
4705e111ed8SAndrew Rybchenko
4715e111ed8SAndrew Rybchenko return (0);
4725e111ed8SAndrew Rybchenko
47372e9af05SIgor Romanov fail3:
47472e9af05SIgor Romanov EFSYS_PROBE(fail3);
47572e9af05SIgor Romanov
4765e111ed8SAndrew Rybchenko fail2:
4775e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
4785e111ed8SAndrew Rybchenko
4795e111ed8SAndrew Rybchenko fail1:
4805e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4815e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
4825e111ed8SAndrew Rybchenko
4835e111ed8SAndrew Rybchenko return (rc);
4845e111ed8SAndrew Rybchenko }
4855e111ed8SAndrew Rybchenko
48672e9af05SIgor Romanov static boolean_t
efx_tunnel_table_all_available(__in efx_tunnel_cfg_t * etcp)48772e9af05SIgor Romanov efx_tunnel_table_all_available(
48872e9af05SIgor Romanov __in efx_tunnel_cfg_t *etcp)
48972e9af05SIgor Romanov {
49072e9af05SIgor Romanov unsigned int i;
49172e9af05SIgor Romanov
49272e9af05SIgor Romanov for (i = 0; i < etcp->etc_udp_entries_num; i++) {
49372e9af05SIgor Romanov if (etcp->etc_udp_entries[i].etue_busy != B_FALSE)
49472e9af05SIgor Romanov return (B_FALSE);
49572e9af05SIgor Romanov }
49672e9af05SIgor Romanov
49772e9af05SIgor Romanov return (B_TRUE);
49872e9af05SIgor Romanov }
49972e9af05SIgor Romanov
50072e9af05SIgor Romanov __checkReturn efx_rc_t
efx_tunnel_config_clear(__in efx_nic_t * enp)5015e111ed8SAndrew Rybchenko efx_tunnel_config_clear(
5025e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
5035e111ed8SAndrew Rybchenko {
5045e111ed8SAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
5055e111ed8SAndrew Rybchenko efsys_lock_state_t state;
50672e9af05SIgor Romanov unsigned int i;
50772e9af05SIgor Romanov efx_rc_t rc;
5085e111ed8SAndrew Rybchenko
5095e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
5105e111ed8SAndrew Rybchenko
5115e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
5125e111ed8SAndrew Rybchenko
51372e9af05SIgor Romanov if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
51472e9af05SIgor Romanov rc = EBUSY;
51572e9af05SIgor Romanov goto fail1;
51672e9af05SIgor Romanov }
51772e9af05SIgor Romanov
51872e9af05SIgor Romanov i = 0;
51972e9af05SIgor Romanov while (i < etcp->etc_udp_entries_num)
52072e9af05SIgor Romanov i = efx_tunnel_config_udp_remove_prepare(etcp, i);
5215e111ed8SAndrew Rybchenko
5225e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
52372e9af05SIgor Romanov
52472e9af05SIgor Romanov return (0);
52572e9af05SIgor Romanov
52672e9af05SIgor Romanov fail1:
52772e9af05SIgor Romanov EFSYS_PROBE1(fail1, efx_rc_t, rc);
52872e9af05SIgor Romanov EFSYS_UNLOCK(enp->en_eslp, state);
52972e9af05SIgor Romanov
53072e9af05SIgor Romanov return (rc);
5315e111ed8SAndrew Rybchenko }
5325e111ed8SAndrew Rybchenko
5335e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_tunnel_reconfigure(__in efx_nic_t * enp)5345e111ed8SAndrew Rybchenko efx_tunnel_reconfigure(
5355e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
5365e111ed8SAndrew Rybchenko {
5375e111ed8SAndrew Rybchenko const efx_tunnel_ops_t *etop = enp->en_etop;
53872e9af05SIgor Romanov efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
53972e9af05SIgor Romanov efx_tunnel_udp_entry_t *entry;
54072e9af05SIgor Romanov boolean_t locked = B_FALSE;
54172e9af05SIgor Romanov efsys_lock_state_t state;
54272e9af05SIgor Romanov boolean_t resetting;
54372e9af05SIgor Romanov unsigned int i;
5445e111ed8SAndrew Rybchenko efx_rc_t rc;
5455e111ed8SAndrew Rybchenko
5465e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
5475e111ed8SAndrew Rybchenko
5485e111ed8SAndrew Rybchenko if (etop->eto_reconfigure == NULL) {
5495e111ed8SAndrew Rybchenko rc = ENOTSUP;
5505e111ed8SAndrew Rybchenko goto fail1;
5515e111ed8SAndrew Rybchenko }
5525e111ed8SAndrew Rybchenko
55372e9af05SIgor Romanov EFSYS_LOCK(enp->en_eslp, state);
55472e9af05SIgor Romanov locked = B_TRUE;
5555e111ed8SAndrew Rybchenko
55672e9af05SIgor Romanov if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
55772e9af05SIgor Romanov rc = EBUSY;
55872e9af05SIgor Romanov goto fail2;
55972e9af05SIgor Romanov }
56072e9af05SIgor Romanov
56172e9af05SIgor Romanov for (i = 0; i < etcp->etc_udp_entries_num; i++) {
56272e9af05SIgor Romanov entry = &etcp->etc_udp_entries[i];
56372e9af05SIgor Romanov if (entry->etue_state != EFX_TUNNEL_UDP_ENTRY_APPLIED)
56472e9af05SIgor Romanov entry->etue_busy = B_TRUE;
56572e9af05SIgor Romanov }
56672e9af05SIgor Romanov
56772e9af05SIgor Romanov EFSYS_UNLOCK(enp->en_eslp, state);
56872e9af05SIgor Romanov locked = B_FALSE;
56972e9af05SIgor Romanov
57072e9af05SIgor Romanov rc = enp->en_etop->eto_reconfigure(enp);
57172e9af05SIgor Romanov if (rc != 0 && rc != EAGAIN)
57272e9af05SIgor Romanov goto fail3;
57372e9af05SIgor Romanov
57472e9af05SIgor Romanov resetting = (rc == EAGAIN) ? B_TRUE : B_FALSE;
57572e9af05SIgor Romanov
57672e9af05SIgor Romanov EFSYS_LOCK(enp->en_eslp, state);
57772e9af05SIgor Romanov locked = B_TRUE;
57872e9af05SIgor Romanov
57972e9af05SIgor Romanov /*
58072e9af05SIgor Romanov * Delete entries marked for removal since they are no longer
58172e9af05SIgor Romanov * needed after successful NIC-specific reconfiguration.
58272e9af05SIgor Romanov * Added entries become applied because they are installed in
58372e9af05SIgor Romanov * the hardware.
58472e9af05SIgor Romanov */
58572e9af05SIgor Romanov
58672e9af05SIgor Romanov i = 0;
58772e9af05SIgor Romanov while (i < etcp->etc_udp_entries_num) {
58872e9af05SIgor Romanov unsigned int next = i + 1;
58972e9af05SIgor Romanov
59072e9af05SIgor Romanov entry = &etcp->etc_udp_entries[i];
59172e9af05SIgor Romanov if (entry->etue_busy != B_FALSE) {
59272e9af05SIgor Romanov entry->etue_busy = B_FALSE;
59372e9af05SIgor Romanov
59472e9af05SIgor Romanov switch (entry->etue_state) {
59572e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_APPLIED:
59672e9af05SIgor Romanov break;
59772e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_ADDED:
59872e9af05SIgor Romanov entry->etue_state =
59972e9af05SIgor Romanov EFX_TUNNEL_UDP_ENTRY_APPLIED;
60072e9af05SIgor Romanov break;
60172e9af05SIgor Romanov case EFX_TUNNEL_UDP_ENTRY_REMOVED:
60272e9af05SIgor Romanov next = efx_tunnel_config_udp_do_remove(etcp, i);
60372e9af05SIgor Romanov break;
60472e9af05SIgor Romanov default:
60572e9af05SIgor Romanov EFSYS_ASSERT(0);
60672e9af05SIgor Romanov break;
60772e9af05SIgor Romanov }
60872e9af05SIgor Romanov }
60972e9af05SIgor Romanov
61072e9af05SIgor Romanov i = next;
61172e9af05SIgor Romanov }
61272e9af05SIgor Romanov
61372e9af05SIgor Romanov EFSYS_UNLOCK(enp->en_eslp, state);
61472e9af05SIgor Romanov locked = B_FALSE;
61572e9af05SIgor Romanov
61672e9af05SIgor Romanov return ((resetting == B_FALSE) ? 0 : EAGAIN);
61772e9af05SIgor Romanov
61872e9af05SIgor Romanov fail3:
61972e9af05SIgor Romanov EFSYS_PROBE(fail3);
62072e9af05SIgor Romanov
62172e9af05SIgor Romanov EFSYS_ASSERT(locked == B_FALSE);
62272e9af05SIgor Romanov EFSYS_LOCK(enp->en_eslp, state);
62372e9af05SIgor Romanov
62472e9af05SIgor Romanov for (i = 0; i < etcp->etc_udp_entries_num; i++)
62572e9af05SIgor Romanov etcp->etc_udp_entries[i].etue_busy = B_FALSE;
62672e9af05SIgor Romanov
62772e9af05SIgor Romanov EFSYS_UNLOCK(enp->en_eslp, state);
6285e111ed8SAndrew Rybchenko
6295e111ed8SAndrew Rybchenko fail2:
6305e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
6315e111ed8SAndrew Rybchenko
6325e111ed8SAndrew Rybchenko fail1:
6335e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
63472e9af05SIgor Romanov if (locked)
63572e9af05SIgor Romanov EFSYS_UNLOCK(enp->en_eslp, state);
6365e111ed8SAndrew Rybchenko
6375e111ed8SAndrew Rybchenko return (rc);
6385e111ed8SAndrew Rybchenko }
6395e111ed8SAndrew Rybchenko
6405e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
6415e111ed8SAndrew Rybchenko static __checkReturn boolean_t
ef10_udp_encap_supported(__in efx_nic_t * enp)6425e111ed8SAndrew Rybchenko ef10_udp_encap_supported(
6435e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
6445e111ed8SAndrew Rybchenko {
6455e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
6465e111ed8SAndrew Rybchenko uint32_t udp_tunnels_mask = 0;
6475e111ed8SAndrew Rybchenko
6485e111ed8SAndrew Rybchenko udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN);
6495e111ed8SAndrew Rybchenko udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE);
6505e111ed8SAndrew Rybchenko
6515e111ed8SAndrew Rybchenko return ((encp->enc_tunnel_encapsulations_supported &
6525e111ed8SAndrew Rybchenko udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
6535e111ed8SAndrew Rybchenko }
6545e111ed8SAndrew Rybchenko
6555e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
ef10_tunnel_reconfigure(__in efx_nic_t * enp)6565e111ed8SAndrew Rybchenko ef10_tunnel_reconfigure(
6575e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
6585e111ed8SAndrew Rybchenko {
6595e111ed8SAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
6605e111ed8SAndrew Rybchenko efx_rc_t rc;
6615e111ed8SAndrew Rybchenko boolean_t resetting = B_FALSE;
6625e111ed8SAndrew Rybchenko efsys_lock_state_t state;
6635e111ed8SAndrew Rybchenko efx_tunnel_cfg_t etc;
6645e111ed8SAndrew Rybchenko
6655e111ed8SAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state);
6665e111ed8SAndrew Rybchenko memcpy(&etc, etcp, sizeof (etc));
6675e111ed8SAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state);
6685e111ed8SAndrew Rybchenko
6695e111ed8SAndrew Rybchenko if (ef10_udp_encap_supported(enp) == B_FALSE) {
6705e111ed8SAndrew Rybchenko /*
6715e111ed8SAndrew Rybchenko * It is OK to apply empty UDP tunnel ports when UDP
6725e111ed8SAndrew Rybchenko * tunnel encapsulations are not supported - just nothing
6735e111ed8SAndrew Rybchenko * should be done.
6745e111ed8SAndrew Rybchenko */
6755e111ed8SAndrew Rybchenko if (etc.etc_udp_entries_num == 0)
6765e111ed8SAndrew Rybchenko return (0);
6775e111ed8SAndrew Rybchenko rc = ENOTSUP;
6785e111ed8SAndrew Rybchenko goto fail1;
6795e111ed8SAndrew Rybchenko } else {
6805e111ed8SAndrew Rybchenko /*
6815e111ed8SAndrew Rybchenko * All PCI functions can see a reset upon the
6825e111ed8SAndrew Rybchenko * MCDI request completion
6835e111ed8SAndrew Rybchenko */
6845e111ed8SAndrew Rybchenko rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
6855e111ed8SAndrew Rybchenko &resetting);
6865e111ed8SAndrew Rybchenko if (rc != 0) {
6875e111ed8SAndrew Rybchenko /*
6885e111ed8SAndrew Rybchenko * Do not fail if the access is denied when no
6895e111ed8SAndrew Rybchenko * tunnel encap UDP ports are configured.
6905e111ed8SAndrew Rybchenko */
6915e111ed8SAndrew Rybchenko if (rc != EACCES || etc.etc_udp_entries_num != 0)
6925e111ed8SAndrew Rybchenko goto fail2;
6935e111ed8SAndrew Rybchenko }
6945e111ed8SAndrew Rybchenko
6955e111ed8SAndrew Rybchenko /*
6965e111ed8SAndrew Rybchenko * Although the caller should be able to handle MC reboot,
6975e111ed8SAndrew Rybchenko * it might come in handy to report the impending reboot
6985e111ed8SAndrew Rybchenko * by returning EAGAIN
6995e111ed8SAndrew Rybchenko */
7005e111ed8SAndrew Rybchenko return ((resetting) ? EAGAIN : 0);
7015e111ed8SAndrew Rybchenko }
7025e111ed8SAndrew Rybchenko fail2:
7035e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
7045e111ed8SAndrew Rybchenko
7055e111ed8SAndrew Rybchenko fail1:
7065e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
7075e111ed8SAndrew Rybchenko
7085e111ed8SAndrew Rybchenko return (rc);
7095e111ed8SAndrew Rybchenko }
7104dda992fSIgor Romanov
7114dda992fSIgor Romanov static void
ef10_tunnel_fini(__in efx_nic_t * enp)7124dda992fSIgor Romanov ef10_tunnel_fini(
7134dda992fSIgor Romanov __in efx_nic_t *enp)
7144dda992fSIgor Romanov {
7154dda992fSIgor Romanov boolean_t resetting;
7164dda992fSIgor Romanov
7174dda992fSIgor Romanov if (ef10_udp_encap_supported(enp) != B_FALSE) {
7184dda992fSIgor Romanov /*
7194dda992fSIgor Romanov * The UNLOADING flag allows the MC to suppress the datapath
7204dda992fSIgor Romanov * reset if it was set on the last call to
7214dda992fSIgor Romanov * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions
7224dda992fSIgor Romanov */
7234dda992fSIgor Romanov (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
7244dda992fSIgor Romanov &resetting);
7254dda992fSIgor Romanov }
7264dda992fSIgor Romanov }
7275e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
7285e111ed8SAndrew Rybchenko
7295e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_TUNNEL */
730