15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3672386c1SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko * Copyright(c) 2009-2019 Solarflare Communications Inc.
55e111ed8SAndrew Rybchenko */
65e111ed8SAndrew Rybchenko
75e111ed8SAndrew Rybchenko #include "efx.h"
85e111ed8SAndrew Rybchenko #include "efx_impl.h"
95e111ed8SAndrew Rybchenko
105e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_port_init(__in efx_nic_t * enp)115e111ed8SAndrew Rybchenko efx_port_init(
125e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
135e111ed8SAndrew Rybchenko {
145e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
155e111ed8SAndrew Rybchenko const efx_phy_ops_t *epop = epp->ep_epop;
165e111ed8SAndrew Rybchenko efx_rc_t rc;
175e111ed8SAndrew Rybchenko
185e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
195e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
205e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
215e111ed8SAndrew Rybchenko
225e111ed8SAndrew Rybchenko if (enp->en_mod_flags & EFX_MOD_PORT) {
235e111ed8SAndrew Rybchenko rc = EINVAL;
245e111ed8SAndrew Rybchenko goto fail1;
255e111ed8SAndrew Rybchenko }
265e111ed8SAndrew Rybchenko
275e111ed8SAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_PORT;
285e111ed8SAndrew Rybchenko
295e111ed8SAndrew Rybchenko epp->ep_mac_type = EFX_MAC_INVALID;
305e111ed8SAndrew Rybchenko epp->ep_link_mode = EFX_LINK_UNKNOWN;
315e111ed8SAndrew Rybchenko epp->ep_mac_drain = B_TRUE;
325e111ed8SAndrew Rybchenko
335e111ed8SAndrew Rybchenko /* Configure the MAC */
345e111ed8SAndrew Rybchenko if ((rc = efx_mac_select(enp)) != 0)
355e111ed8SAndrew Rybchenko goto fail1;
365e111ed8SAndrew Rybchenko
375e111ed8SAndrew Rybchenko epp->ep_emop->emo_reconfigure(enp);
385e111ed8SAndrew Rybchenko
395e111ed8SAndrew Rybchenko /* Pick up current phy capababilities */
405e111ed8SAndrew Rybchenko (void) efx_port_poll(enp, NULL);
415e111ed8SAndrew Rybchenko
425e111ed8SAndrew Rybchenko /*
435e111ed8SAndrew Rybchenko * Turn on the PHY if available, otherwise reset it, and
445e111ed8SAndrew Rybchenko * reconfigure it with the current configuration.
455e111ed8SAndrew Rybchenko */
465e111ed8SAndrew Rybchenko if (epop->epo_power != NULL) {
475e111ed8SAndrew Rybchenko if ((rc = epop->epo_power(enp, B_TRUE)) != 0)
485e111ed8SAndrew Rybchenko goto fail2;
495e111ed8SAndrew Rybchenko } else {
505e111ed8SAndrew Rybchenko if ((rc = epop->epo_reset(enp)) != 0)
515e111ed8SAndrew Rybchenko goto fail2;
525e111ed8SAndrew Rybchenko }
535e111ed8SAndrew Rybchenko
545e111ed8SAndrew Rybchenko EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
555e111ed8SAndrew Rybchenko enp->en_reset_flags &= ~EFX_RESET_PHY;
565e111ed8SAndrew Rybchenko
575e111ed8SAndrew Rybchenko if ((rc = epop->epo_reconfigure(enp)) != 0)
585e111ed8SAndrew Rybchenko goto fail3;
595e111ed8SAndrew Rybchenko
605e111ed8SAndrew Rybchenko return (0);
615e111ed8SAndrew Rybchenko
625e111ed8SAndrew Rybchenko fail3:
635e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
645e111ed8SAndrew Rybchenko fail2:
655e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
665e111ed8SAndrew Rybchenko fail1:
675e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
685e111ed8SAndrew Rybchenko
695e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_PORT;
705e111ed8SAndrew Rybchenko
715e111ed8SAndrew Rybchenko return (rc);
725e111ed8SAndrew Rybchenko }
735e111ed8SAndrew Rybchenko
745e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_port_poll(__in efx_nic_t * enp,__out_opt efx_link_mode_t * link_modep)755e111ed8SAndrew Rybchenko efx_port_poll(
765e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
775e111ed8SAndrew Rybchenko __out_opt efx_link_mode_t *link_modep)
785e111ed8SAndrew Rybchenko {
795e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
805e111ed8SAndrew Rybchenko const efx_mac_ops_t *emop = epp->ep_emop;
815e111ed8SAndrew Rybchenko efx_link_mode_t ignore_link_mode;
825e111ed8SAndrew Rybchenko efx_rc_t rc;
835e111ed8SAndrew Rybchenko
845e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
855e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
865e111ed8SAndrew Rybchenko
875e111ed8SAndrew Rybchenko EFSYS_ASSERT(emop != NULL);
885e111ed8SAndrew Rybchenko
895e111ed8SAndrew Rybchenko if (link_modep == NULL)
905e111ed8SAndrew Rybchenko link_modep = &ignore_link_mode;
915e111ed8SAndrew Rybchenko
925e111ed8SAndrew Rybchenko if ((rc = emop->emo_poll(enp, link_modep)) != 0)
935e111ed8SAndrew Rybchenko goto fail1;
945e111ed8SAndrew Rybchenko
955e111ed8SAndrew Rybchenko return (0);
965e111ed8SAndrew Rybchenko
975e111ed8SAndrew Rybchenko fail1:
985e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
995e111ed8SAndrew Rybchenko
1005e111ed8SAndrew Rybchenko return (rc);
1015e111ed8SAndrew Rybchenko }
1025e111ed8SAndrew Rybchenko
1035e111ed8SAndrew Rybchenko #if EFSYS_OPT_LOOPBACK
1045e111ed8SAndrew Rybchenko
1055e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_port_loopback_set(__in efx_nic_t * enp,__in efx_link_mode_t link_mode,__in efx_loopback_type_t loopback_type)1065e111ed8SAndrew Rybchenko efx_port_loopback_set(
1075e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1085e111ed8SAndrew Rybchenko __in efx_link_mode_t link_mode,
1095e111ed8SAndrew Rybchenko __in efx_loopback_type_t loopback_type)
1105e111ed8SAndrew Rybchenko {
1115e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
1125e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1135e111ed8SAndrew Rybchenko const efx_mac_ops_t *emop = epp->ep_emop;
1145e111ed8SAndrew Rybchenko efx_rc_t rc;
1155e111ed8SAndrew Rybchenko
1165e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1175e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
1185e111ed8SAndrew Rybchenko EFSYS_ASSERT(emop != NULL);
1195e111ed8SAndrew Rybchenko
1205e111ed8SAndrew Rybchenko EFSYS_ASSERT(link_mode < EFX_LINK_NMODES);
1215e111ed8SAndrew Rybchenko
1225e111ed8SAndrew Rybchenko if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode],
1235e111ed8SAndrew Rybchenko (int)loopback_type) == 0) {
1245e111ed8SAndrew Rybchenko rc = ENOTSUP;
1255e111ed8SAndrew Rybchenko goto fail1;
1265e111ed8SAndrew Rybchenko }
1275e111ed8SAndrew Rybchenko
1285e111ed8SAndrew Rybchenko if (epp->ep_loopback_type == loopback_type &&
1295e111ed8SAndrew Rybchenko epp->ep_loopback_link_mode == link_mode)
1305e111ed8SAndrew Rybchenko return (0);
1315e111ed8SAndrew Rybchenko
1325e111ed8SAndrew Rybchenko if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0)
1335e111ed8SAndrew Rybchenko goto fail2;
1345e111ed8SAndrew Rybchenko
1355e111ed8SAndrew Rybchenko return (0);
1365e111ed8SAndrew Rybchenko
1375e111ed8SAndrew Rybchenko fail2:
1385e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
1395e111ed8SAndrew Rybchenko fail1:
1405e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1415e111ed8SAndrew Rybchenko
1425e111ed8SAndrew Rybchenko return (rc);
1435e111ed8SAndrew Rybchenko }
1445e111ed8SAndrew Rybchenko
1455e111ed8SAndrew Rybchenko #if EFSYS_OPT_NAMES
1465e111ed8SAndrew Rybchenko
1475e111ed8SAndrew Rybchenko static const char * const __efx_loopback_type_name[] = {
1485e111ed8SAndrew Rybchenko "OFF",
1495e111ed8SAndrew Rybchenko "DATA",
1505e111ed8SAndrew Rybchenko "GMAC",
1515e111ed8SAndrew Rybchenko "XGMII",
1525e111ed8SAndrew Rybchenko "XGXS",
1535e111ed8SAndrew Rybchenko "XAUI",
1545e111ed8SAndrew Rybchenko "GMII",
1555e111ed8SAndrew Rybchenko "SGMII",
1565e111ed8SAndrew Rybchenko "XGBR",
1575e111ed8SAndrew Rybchenko "XFI",
1585e111ed8SAndrew Rybchenko "XAUI_FAR",
1595e111ed8SAndrew Rybchenko "GMII_FAR",
1605e111ed8SAndrew Rybchenko "SGMII_FAR",
1615e111ed8SAndrew Rybchenko "XFI_FAR",
1625e111ed8SAndrew Rybchenko "GPHY",
1635e111ed8SAndrew Rybchenko "PHY_XS",
1645e111ed8SAndrew Rybchenko "PCS",
1655e111ed8SAndrew Rybchenko "PMA_PMD",
1665e111ed8SAndrew Rybchenko "XPORT",
1675e111ed8SAndrew Rybchenko "XGMII_WS",
1685e111ed8SAndrew Rybchenko "XAUI_WS",
1695e111ed8SAndrew Rybchenko "XAUI_WS_FAR",
1705e111ed8SAndrew Rybchenko "XAUI_WS_NEAR",
1715e111ed8SAndrew Rybchenko "GMII_WS",
1725e111ed8SAndrew Rybchenko "XFI_WS",
1735e111ed8SAndrew Rybchenko "XFI_WS_FAR",
1745e111ed8SAndrew Rybchenko "PHYXS_WS",
1755e111ed8SAndrew Rybchenko "PMA_INT",
1765e111ed8SAndrew Rybchenko "SD_NEAR",
1775e111ed8SAndrew Rybchenko "SD_FAR",
1785e111ed8SAndrew Rybchenko "PMA_INT_WS",
1795e111ed8SAndrew Rybchenko "SD_FEP2_WS",
1805e111ed8SAndrew Rybchenko "SD_FEP1_5_WS",
1815e111ed8SAndrew Rybchenko "SD_FEP_WS",
1825e111ed8SAndrew Rybchenko "SD_FES_WS",
1835e111ed8SAndrew Rybchenko "AOE_INT_NEAR",
1845e111ed8SAndrew Rybchenko "DATA_WS",
1855e111ed8SAndrew Rybchenko "FORCE_EXT_LINK",
1865e111ed8SAndrew Rybchenko };
1875e111ed8SAndrew Rybchenko
1885e111ed8SAndrew Rybchenko __checkReturn const char *
efx_loopback_type_name(__in efx_nic_t * enp,__in efx_loopback_type_t type)1895e111ed8SAndrew Rybchenko efx_loopback_type_name(
1905e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1915e111ed8SAndrew Rybchenko __in efx_loopback_type_t type)
1925e111ed8SAndrew Rybchenko {
1935e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) ==
1945e111ed8SAndrew Rybchenko EFX_LOOPBACK_NTYPES);
1955e111ed8SAndrew Rybchenko
1965e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(enp))
1975e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1985e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES);
1995e111ed8SAndrew Rybchenko
2005e111ed8SAndrew Rybchenko return (__efx_loopback_type_name[type]);
2015e111ed8SAndrew Rybchenko }
2025e111ed8SAndrew Rybchenko
2035e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_NAMES */
2045e111ed8SAndrew Rybchenko
2055e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_LOOPBACK */
2065e111ed8SAndrew Rybchenko
207*e5e5c127SArtemii Morozov __checkReturn efx_rc_t
efx_port_vlan_strip_set(__in efx_nic_t * enp,__in boolean_t enabled)208*e5e5c127SArtemii Morozov efx_port_vlan_strip_set(
209*e5e5c127SArtemii Morozov __in efx_nic_t *enp,
210*e5e5c127SArtemii Morozov __in boolean_t enabled)
211*e5e5c127SArtemii Morozov {
212*e5e5c127SArtemii Morozov efx_port_t *epp = &(enp->en_port);
213*e5e5c127SArtemii Morozov efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
214*e5e5c127SArtemii Morozov uint32_t filter_count = 0;
215*e5e5c127SArtemii Morozov efx_rc_t rc;
216*e5e5c127SArtemii Morozov
217*e5e5c127SArtemii Morozov EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
218*e5e5c127SArtemii Morozov
219*e5e5c127SArtemii Morozov if (enabled && !encp->enc_rx_vlan_stripping_supported) {
220*e5e5c127SArtemii Morozov rc = ENOTSUP;
221*e5e5c127SArtemii Morozov goto fail1;
222*e5e5c127SArtemii Morozov }
223*e5e5c127SArtemii Morozov
224*e5e5c127SArtemii Morozov if ((rc = efx_filter_get_count(enp, &filter_count)) != 0)
225*e5e5c127SArtemii Morozov goto fail2;
226*e5e5c127SArtemii Morozov
227*e5e5c127SArtemii Morozov if (filter_count != 0) {
228*e5e5c127SArtemii Morozov rc = EINVAL;
229*e5e5c127SArtemii Morozov goto fail3;
230*e5e5c127SArtemii Morozov }
231*e5e5c127SArtemii Morozov
232*e5e5c127SArtemii Morozov epp->ep_vlan_strip = enabled;
233*e5e5c127SArtemii Morozov
234*e5e5c127SArtemii Morozov return (0);
235*e5e5c127SArtemii Morozov
236*e5e5c127SArtemii Morozov fail3:
237*e5e5c127SArtemii Morozov EFSYS_PROBE(fail3);
238*e5e5c127SArtemii Morozov fail2:
239*e5e5c127SArtemii Morozov EFSYS_PROBE(fail2);
240*e5e5c127SArtemii Morozov fail1:
241*e5e5c127SArtemii Morozov EFSYS_PROBE1(fail1, efx_rc_t, rc);
242*e5e5c127SArtemii Morozov
243*e5e5c127SArtemii Morozov return (rc);
244*e5e5c127SArtemii Morozov }
245*e5e5c127SArtemii Morozov
2465e111ed8SAndrew Rybchenko void
efx_port_fini(__in efx_nic_t * enp)2475e111ed8SAndrew Rybchenko efx_port_fini(
2485e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
2495e111ed8SAndrew Rybchenko {
2505e111ed8SAndrew Rybchenko efx_port_t *epp = &(enp->en_port);
2515e111ed8SAndrew Rybchenko const efx_phy_ops_t *epop = epp->ep_epop;
2525e111ed8SAndrew Rybchenko
2535e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2545e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
2555e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
2565e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
2575e111ed8SAndrew Rybchenko
2585e111ed8SAndrew Rybchenko EFSYS_ASSERT(epp->ep_mac_drain);
2595e111ed8SAndrew Rybchenko
2605e111ed8SAndrew Rybchenko epp->ep_emop = NULL;
2615e111ed8SAndrew Rybchenko epp->ep_mac_type = EFX_MAC_INVALID;
2625e111ed8SAndrew Rybchenko epp->ep_mac_drain = B_FALSE;
2635e111ed8SAndrew Rybchenko
2645e111ed8SAndrew Rybchenko /* Turn off the PHY */
2655e111ed8SAndrew Rybchenko if (epop->epo_power != NULL)
2665e111ed8SAndrew Rybchenko (void) epop->epo_power(enp, B_FALSE);
2675e111ed8SAndrew Rybchenko
2685e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_PORT;
2695e111ed8SAndrew Rybchenko }
270