1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2834e23ddSShradha Shah /****************************************************************************
3834e23ddSShradha Shah * Driver for Solarflare network controllers and boards
4834e23ddSShradha Shah * Copyright 2015 Solarflare Communications Inc.
5834e23ddSShradha Shah */
64b5b1ac5SShyam Saini #include <linux/etherdevice.h>
7834e23ddSShradha Shah #include <linux/pci.h>
8834e23ddSShradha Shah #include <linux/module.h>
9834e23ddSShradha Shah #include "net_driver.h"
10834e23ddSShradha Shah #include "ef10_sriov.h"
11834e23ddSShradha Shah #include "efx.h"
12834e23ddSShradha Shah #include "nic.h"
13834e23ddSShradha Shah #include "mcdi_pcol.h"
14834e23ddSShradha Shah
efx_ef10_evb_port_assign(struct efx_nic * efx,unsigned int port_id,unsigned int vf_fn)153c5eb876SShradha Shah static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id,
163c5eb876SShradha Shah unsigned int vf_fn)
17834e23ddSShradha Shah {
183c5eb876SShradha Shah MCDI_DECLARE_BUF(inbuf, MC_CMD_EVB_PORT_ASSIGN_IN_LEN);
193c5eb876SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
20834e23ddSShradha Shah
213c5eb876SShradha Shah MCDI_SET_DWORD(inbuf, EVB_PORT_ASSIGN_IN_PORT_ID, port_id);
223c5eb876SShradha Shah MCDI_POPULATE_DWORD_2(inbuf, EVB_PORT_ASSIGN_IN_FUNCTION,
233c5eb876SShradha Shah EVB_PORT_ASSIGN_IN_PF, nic_data->pf_index,
243c5eb876SShradha Shah EVB_PORT_ASSIGN_IN_VF, vf_fn);
253c5eb876SShradha Shah
263c5eb876SShradha Shah return efx_mcdi_rpc(efx, MC_CMD_EVB_PORT_ASSIGN, inbuf, sizeof(inbuf),
273c5eb876SShradha Shah NULL, 0, NULL);
28834e23ddSShradha Shah }
29834e23ddSShradha Shah
efx_ef10_vswitch_alloc(struct efx_nic * efx,unsigned int port_id,unsigned int vswitch_type)306d8aaaf6SDaniel Pieczko static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id,
316d8aaaf6SDaniel Pieczko unsigned int vswitch_type)
326d8aaaf6SDaniel Pieczko {
336d8aaaf6SDaniel Pieczko MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN);
342d432f20SShradha Shah int rc;
356d8aaaf6SDaniel Pieczko
366d8aaaf6SDaniel Pieczko MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id);
376d8aaaf6SDaniel Pieczko MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type);
382d432f20SShradha Shah MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 2);
396d8aaaf6SDaniel Pieczko MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS,
406d8aaaf6SDaniel Pieczko VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0);
416d8aaaf6SDaniel Pieczko
422d432f20SShradha Shah /* Quietly try to allocate 2 VLAN tags */
432d432f20SShradha Shah rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf),
446d8aaaf6SDaniel Pieczko NULL, 0, NULL);
452d432f20SShradha Shah
462d432f20SShradha Shah /* If 2 VLAN tags is too many, revert to trying with 1 VLAN tags */
472d432f20SShradha Shah if (rc == -EPROTO) {
482d432f20SShradha Shah MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 1);
492d432f20SShradha Shah rc = efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf,
502d432f20SShradha Shah sizeof(inbuf), NULL, 0, NULL);
512d432f20SShradha Shah } else if (rc) {
522d432f20SShradha Shah efx_mcdi_display_error(efx, MC_CMD_VSWITCH_ALLOC,
532d432f20SShradha Shah MC_CMD_VSWITCH_ALLOC_IN_LEN,
542d432f20SShradha Shah NULL, 0, rc);
552d432f20SShradha Shah }
562d432f20SShradha Shah return rc;
576d8aaaf6SDaniel Pieczko }
586d8aaaf6SDaniel Pieczko
efx_ef10_vswitch_free(struct efx_nic * efx,unsigned int port_id)596d8aaaf6SDaniel Pieczko static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id)
606d8aaaf6SDaniel Pieczko {
616d8aaaf6SDaniel Pieczko MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_FREE_IN_LEN);
626d8aaaf6SDaniel Pieczko
636d8aaaf6SDaniel Pieczko MCDI_SET_DWORD(inbuf, VSWITCH_FREE_IN_UPSTREAM_PORT_ID, port_id);
646d8aaaf6SDaniel Pieczko
656d8aaaf6SDaniel Pieczko return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_FREE, inbuf, sizeof(inbuf),
666d8aaaf6SDaniel Pieczko NULL, 0, NULL);
676d8aaaf6SDaniel Pieczko }
686d8aaaf6SDaniel Pieczko
efx_ef10_vport_alloc(struct efx_nic * efx,unsigned int port_id_in,unsigned int vport_type,u16 vlan,unsigned int * port_id_out)696d8aaaf6SDaniel Pieczko static int efx_ef10_vport_alloc(struct efx_nic *efx,
706d8aaaf6SDaniel Pieczko unsigned int port_id_in,
716d8aaaf6SDaniel Pieczko unsigned int vport_type,
722d432f20SShradha Shah u16 vlan,
736d8aaaf6SDaniel Pieczko unsigned int *port_id_out)
746d8aaaf6SDaniel Pieczko {
756d8aaaf6SDaniel Pieczko MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN);
766d8aaaf6SDaniel Pieczko MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_ALLOC_OUT_LEN);
776d8aaaf6SDaniel Pieczko size_t outlen;
786d8aaaf6SDaniel Pieczko int rc;
796d8aaaf6SDaniel Pieczko
806d8aaaf6SDaniel Pieczko EFX_WARN_ON_PARANOID(!port_id_out);
816d8aaaf6SDaniel Pieczko
826d8aaaf6SDaniel Pieczko MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in);
836d8aaaf6SDaniel Pieczko MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type);
842d432f20SShradha Shah MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS,
852d432f20SShradha Shah (vlan != EFX_EF10_NO_VLAN));
866d8aaaf6SDaniel Pieczko MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS,
876d8aaaf6SDaniel Pieczko VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0);
882d432f20SShradha Shah if (vlan != EFX_EF10_NO_VLAN)
892d432f20SShradha Shah MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_VLAN_TAGS,
902d432f20SShradha Shah VPORT_ALLOC_IN_VLAN_TAG_0, vlan);
916d8aaaf6SDaniel Pieczko
926d8aaaf6SDaniel Pieczko rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, sizeof(inbuf),
936d8aaaf6SDaniel Pieczko outbuf, sizeof(outbuf), &outlen);
946d8aaaf6SDaniel Pieczko if (rc)
956d8aaaf6SDaniel Pieczko return rc;
966d8aaaf6SDaniel Pieczko if (outlen < MC_CMD_VPORT_ALLOC_OUT_LEN)
976d8aaaf6SDaniel Pieczko return -EIO;
986d8aaaf6SDaniel Pieczko
996d8aaaf6SDaniel Pieczko *port_id_out = MCDI_DWORD(outbuf, VPORT_ALLOC_OUT_VPORT_ID);
1006d8aaaf6SDaniel Pieczko return 0;
1016d8aaaf6SDaniel Pieczko }
1026d8aaaf6SDaniel Pieczko
efx_ef10_vport_free(struct efx_nic * efx,unsigned int port_id)1036d8aaaf6SDaniel Pieczko static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id)
1046d8aaaf6SDaniel Pieczko {
1056d8aaaf6SDaniel Pieczko MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_FREE_IN_LEN);
1066d8aaaf6SDaniel Pieczko
1076d8aaaf6SDaniel Pieczko MCDI_SET_DWORD(inbuf, VPORT_FREE_IN_VPORT_ID, port_id);
1086d8aaaf6SDaniel Pieczko
1096d8aaaf6SDaniel Pieczko return efx_mcdi_rpc(efx, MC_CMD_VPORT_FREE, inbuf, sizeof(inbuf),
1106d8aaaf6SDaniel Pieczko NULL, 0, NULL);
1116d8aaaf6SDaniel Pieczko }
1126d8aaaf6SDaniel Pieczko
efx_ef10_sriov_free_vf_vports(struct efx_nic * efx)1133c5eb876SShradha Shah static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
1143c5eb876SShradha Shah {
1153c5eb876SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
1163c5eb876SShradha Shah int i;
1173c5eb876SShradha Shah
1183c5eb876SShradha Shah if (!nic_data->vf)
1193c5eb876SShradha Shah return;
1203c5eb876SShradha Shah
1213c5eb876SShradha Shah for (i = 0; i < efx->vf_count; i++) {
1223c5eb876SShradha Shah struct ef10_vf *vf = nic_data->vf + i;
1233c5eb876SShradha Shah
1246598dad2SDaniel Pieczko /* If VF is assigned, do not free the vport */
1259a022e76SÍñigo Huguet if (vf->pci_dev && pci_is_dev_assigned(vf->pci_dev))
1266598dad2SDaniel Pieczko continue;
1276598dad2SDaniel Pieczko
1283c5eb876SShradha Shah if (vf->vport_assigned) {
1293c5eb876SShradha Shah efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i);
1303c5eb876SShradha Shah vf->vport_assigned = 0;
1313c5eb876SShradha Shah }
1323c5eb876SShradha Shah
1333c5eb876SShradha Shah if (!is_zero_ether_addr(vf->mac)) {
1343c5eb876SShradha Shah efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
1353c5eb876SShradha Shah eth_zero_addr(vf->mac);
1363c5eb876SShradha Shah }
1373c5eb876SShradha Shah
1383c5eb876SShradha Shah if (vf->vport_id) {
1393c5eb876SShradha Shah efx_ef10_vport_free(efx, vf->vport_id);
1403c5eb876SShradha Shah vf->vport_id = 0;
1413c5eb876SShradha Shah }
142f1122a34SShradha Shah
143f1122a34SShradha Shah vf->efx = NULL;
1443c5eb876SShradha Shah }
1453c5eb876SShradha Shah }
1463c5eb876SShradha Shah
efx_ef10_sriov_free_vf_vswitching(struct efx_nic * efx)1473c5eb876SShradha Shah static void efx_ef10_sriov_free_vf_vswitching(struct efx_nic *efx)
1483c5eb876SShradha Shah {
1493c5eb876SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
1503c5eb876SShradha Shah
1513c5eb876SShradha Shah efx_ef10_sriov_free_vf_vports(efx);
1523c5eb876SShradha Shah kfree(nic_data->vf);
1533c5eb876SShradha Shah nic_data->vf = NULL;
1543c5eb876SShradha Shah }
1553c5eb876SShradha Shah
efx_ef10_sriov_assign_vf_vport(struct efx_nic * efx,unsigned int vf_i)1563c5eb876SShradha Shah static int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx,
1573c5eb876SShradha Shah unsigned int vf_i)
1583c5eb876SShradha Shah {
1593c5eb876SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
1603c5eb876SShradha Shah struct ef10_vf *vf = nic_data->vf + vf_i;
1613c5eb876SShradha Shah int rc;
1623c5eb876SShradha Shah
1633c5eb876SShradha Shah if (WARN_ON_ONCE(!nic_data->vf))
1643c5eb876SShradha Shah return -EOPNOTSUPP;
1653c5eb876SShradha Shah
1663c5eb876SShradha Shah rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
1673c5eb876SShradha Shah MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
1682d432f20SShradha Shah vf->vlan, &vf->vport_id);
1693c5eb876SShradha Shah if (rc)
1703c5eb876SShradha Shah return rc;
1713c5eb876SShradha Shah
1723c5eb876SShradha Shah rc = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
1733c5eb876SShradha Shah if (rc) {
1743c5eb876SShradha Shah eth_zero_addr(vf->mac);
1753c5eb876SShradha Shah return rc;
1763c5eb876SShradha Shah }
1773c5eb876SShradha Shah
1783c5eb876SShradha Shah rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
1793c5eb876SShradha Shah if (rc)
1803c5eb876SShradha Shah return rc;
1813c5eb876SShradha Shah
1823c5eb876SShradha Shah vf->vport_assigned = 1;
1833c5eb876SShradha Shah return 0;
1843c5eb876SShradha Shah }
1853c5eb876SShradha Shah
efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic * efx)1863c5eb876SShradha Shah static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx)
1873c5eb876SShradha Shah {
1883c5eb876SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
1893c5eb876SShradha Shah unsigned int i;
1903c5eb876SShradha Shah int rc;
1913c5eb876SShradha Shah
1923c5eb876SShradha Shah nic_data->vf = kcalloc(efx->vf_count, sizeof(struct ef10_vf),
1933c5eb876SShradha Shah GFP_KERNEL);
1943c5eb876SShradha Shah if (!nic_data->vf)
1953c5eb876SShradha Shah return -ENOMEM;
1963c5eb876SShradha Shah
1973c5eb876SShradha Shah for (i = 0; i < efx->vf_count; i++) {
1986c1f0a1fSJoe Perches eth_random_addr(nic_data->vf[i].mac);
199f1122a34SShradha Shah nic_data->vf[i].efx = NULL;
2002d432f20SShradha Shah nic_data->vf[i].vlan = EFX_EF10_NO_VLAN;
2013c5eb876SShradha Shah
2023c5eb876SShradha Shah rc = efx_ef10_sriov_assign_vf_vport(efx, i);
2033c5eb876SShradha Shah if (rc)
2043c5eb876SShradha Shah goto fail;
2053c5eb876SShradha Shah }
2063c5eb876SShradha Shah
2073c5eb876SShradha Shah return 0;
2083c5eb876SShradha Shah fail:
2093ddd6e2fSÍñigo Huguet efx_ef10_sriov_free_vf_vswitching(efx);
2103c5eb876SShradha Shah return rc;
2113c5eb876SShradha Shah }
2123c5eb876SShradha Shah
efx_ef10_sriov_restore_vf_vswitching(struct efx_nic * efx)2133c5eb876SShradha Shah static int efx_ef10_sriov_restore_vf_vswitching(struct efx_nic *efx)
2143c5eb876SShradha Shah {
2153c5eb876SShradha Shah unsigned int i;
2163c5eb876SShradha Shah int rc;
2173c5eb876SShradha Shah
2183c5eb876SShradha Shah for (i = 0; i < efx->vf_count; i++) {
2193c5eb876SShradha Shah rc = efx_ef10_sriov_assign_vf_vport(efx, i);
2203c5eb876SShradha Shah if (rc)
2213c5eb876SShradha Shah goto fail;
2223c5eb876SShradha Shah }
2233c5eb876SShradha Shah
2243c5eb876SShradha Shah return 0;
2253c5eb876SShradha Shah fail:
2263c5eb876SShradha Shah efx_ef10_sriov_free_vf_vswitching(efx);
2273c5eb876SShradha Shah return rc;
2283c5eb876SShradha Shah }
2293c5eb876SShradha Shah
efx_ef10_vadaptor_alloc_set_features(struct efx_nic * efx)23038d27f38SAndrew Rybchenko static int efx_ef10_vadaptor_alloc_set_features(struct efx_nic *efx)
23138d27f38SAndrew Rybchenko {
23238d27f38SAndrew Rybchenko u32 port_flags;
23338d27f38SAndrew Rybchenko int rc;
23438d27f38SAndrew Rybchenko
235dfcabb07SEdward Cree rc = efx_ef10_vadaptor_alloc(efx, efx->vport_id);
23638d27f38SAndrew Rybchenko if (rc)
23738d27f38SAndrew Rybchenko goto fail_vadaptor_alloc;
23838d27f38SAndrew Rybchenko
239dfcabb07SEdward Cree rc = efx_ef10_vadaptor_query(efx, efx->vport_id,
24038d27f38SAndrew Rybchenko &port_flags, NULL, NULL);
24138d27f38SAndrew Rybchenko if (rc)
24238d27f38SAndrew Rybchenko goto fail_vadaptor_query;
24338d27f38SAndrew Rybchenko
24438d27f38SAndrew Rybchenko if (port_flags &
24538d27f38SAndrew Rybchenko (1 << MC_CMD_VPORT_ALLOC_IN_FLAG_VLAN_RESTRICT_LBN))
24638d27f38SAndrew Rybchenko efx->fixed_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
24738d27f38SAndrew Rybchenko else
24838d27f38SAndrew Rybchenko efx->fixed_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
24938d27f38SAndrew Rybchenko
25038d27f38SAndrew Rybchenko return 0;
25138d27f38SAndrew Rybchenko
25238d27f38SAndrew Rybchenko fail_vadaptor_query:
25338d27f38SAndrew Rybchenko efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
25438d27f38SAndrew Rybchenko fail_vadaptor_alloc:
25538d27f38SAndrew Rybchenko return rc;
25638d27f38SAndrew Rybchenko }
25738d27f38SAndrew Rybchenko
2586d8aaaf6SDaniel Pieczko /* On top of the default firmware vswitch setup, create a VEB vswitch and
2596d8aaaf6SDaniel Pieczko * expansion vport for use by this function.
2606d8aaaf6SDaniel Pieczko */
efx_ef10_vswitching_probe_pf(struct efx_nic * efx)2617b8c7b54SShradha Shah int efx_ef10_vswitching_probe_pf(struct efx_nic *efx)
2626d8aaaf6SDaniel Pieczko {
2636d8aaaf6SDaniel Pieczko struct efx_ef10_nic_data *nic_data = efx->nic_data;
2643c5eb876SShradha Shah struct net_device *net_dev = efx->net_dev;
2656d8aaaf6SDaniel Pieczko int rc;
2666d8aaaf6SDaniel Pieczko
2677b8c7b54SShradha Shah if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) {
2687b8c7b54SShradha Shah /* vswitch not needed as we have no VFs */
26938d27f38SAndrew Rybchenko efx_ef10_vadaptor_alloc_set_features(efx);
2707b8c7b54SShradha Shah return 0;
2717b8c7b54SShradha Shah }
2726d8aaaf6SDaniel Pieczko
2736d8aaaf6SDaniel Pieczko rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED,
2746d8aaaf6SDaniel Pieczko MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB);
2756d8aaaf6SDaniel Pieczko if (rc)
2766d8aaaf6SDaniel Pieczko goto fail1;
2776d8aaaf6SDaniel Pieczko
2786d8aaaf6SDaniel Pieczko rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
2796d8aaaf6SDaniel Pieczko MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
280dfcabb07SEdward Cree EFX_EF10_NO_VLAN, &efx->vport_id);
2816d8aaaf6SDaniel Pieczko if (rc)
2826d8aaaf6SDaniel Pieczko goto fail2;
2836d8aaaf6SDaniel Pieczko
284dfcabb07SEdward Cree rc = efx_ef10_vport_add_mac(efx, efx->vport_id, net_dev->dev_addr);
2853c5eb876SShradha Shah if (rc)
2863c5eb876SShradha Shah goto fail3;
2873c5eb876SShradha Shah ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr);
2883c5eb876SShradha Shah
28938d27f38SAndrew Rybchenko rc = efx_ef10_vadaptor_alloc_set_features(efx);
2907b8c7b54SShradha Shah if (rc)
2917b8c7b54SShradha Shah goto fail4;
2927b8c7b54SShradha Shah
2936d8aaaf6SDaniel Pieczko return 0;
2947b8c7b54SShradha Shah fail4:
295dfcabb07SEdward Cree efx_ef10_vport_del_mac(efx, efx->vport_id, nic_data->vport_mac);
2967b8c7b54SShradha Shah eth_zero_addr(nic_data->vport_mac);
2973c5eb876SShradha Shah fail3:
298dfcabb07SEdward Cree efx_ef10_vport_free(efx, efx->vport_id);
299dfcabb07SEdward Cree efx->vport_id = EVB_PORT_ID_ASSIGNED;
3006d8aaaf6SDaniel Pieczko fail2:
3016d8aaaf6SDaniel Pieczko efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED);
3026d8aaaf6SDaniel Pieczko fail1:
3036d8aaaf6SDaniel Pieczko return rc;
3046d8aaaf6SDaniel Pieczko }
3056d8aaaf6SDaniel Pieczko
efx_ef10_vswitching_probe_vf(struct efx_nic * efx)3067b8c7b54SShradha Shah int efx_ef10_vswitching_probe_vf(struct efx_nic *efx)
3077b8c7b54SShradha Shah {
30838d27f38SAndrew Rybchenko return efx_ef10_vadaptor_alloc_set_features(efx);
3097b8c7b54SShradha Shah }
3107b8c7b54SShradha Shah
efx_ef10_vswitching_restore_pf(struct efx_nic * efx)3117b8c7b54SShradha Shah int efx_ef10_vswitching_restore_pf(struct efx_nic *efx)
3126d8aaaf6SDaniel Pieczko {
3136d8aaaf6SDaniel Pieczko struct efx_ef10_nic_data *nic_data = efx->nic_data;
3146d8aaaf6SDaniel Pieczko int rc;
3156d8aaaf6SDaniel Pieczko
3166d8aaaf6SDaniel Pieczko if (!nic_data->must_probe_vswitching)
3176d8aaaf6SDaniel Pieczko return 0;
3186d8aaaf6SDaniel Pieczko
3197b8c7b54SShradha Shah rc = efx_ef10_vswitching_probe_pf(efx);
3203c5eb876SShradha Shah if (rc)
3213c5eb876SShradha Shah goto fail;
3226d8aaaf6SDaniel Pieczko
3233c5eb876SShradha Shah rc = efx_ef10_sriov_restore_vf_vswitching(efx);
3243c5eb876SShradha Shah if (rc)
3253c5eb876SShradha Shah goto fail;
3263c5eb876SShradha Shah
3276d8aaaf6SDaniel Pieczko nic_data->must_probe_vswitching = false;
3283c5eb876SShradha Shah fail:
3296d8aaaf6SDaniel Pieczko return rc;
3306d8aaaf6SDaniel Pieczko }
3316d8aaaf6SDaniel Pieczko
efx_ef10_vswitching_restore_vf(struct efx_nic * efx)3327b8c7b54SShradha Shah int efx_ef10_vswitching_restore_vf(struct efx_nic *efx)
3337b8c7b54SShradha Shah {
3347b8c7b54SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
3357b8c7b54SShradha Shah int rc;
3367b8c7b54SShradha Shah
3377b8c7b54SShradha Shah if (!nic_data->must_probe_vswitching)
3387b8c7b54SShradha Shah return 0;
3397b8c7b54SShradha Shah
3407b8c7b54SShradha Shah rc = efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
3417b8c7b54SShradha Shah if (rc)
3427b8c7b54SShradha Shah return rc;
3437b8c7b54SShradha Shah
3447b8c7b54SShradha Shah nic_data->must_probe_vswitching = false;
3457b8c7b54SShradha Shah return 0;
3467b8c7b54SShradha Shah }
3477b8c7b54SShradha Shah
efx_ef10_vswitching_remove_pf(struct efx_nic * efx)3487b8c7b54SShradha Shah void efx_ef10_vswitching_remove_pf(struct efx_nic *efx)
3496d8aaaf6SDaniel Pieczko {
3506d8aaaf6SDaniel Pieczko struct efx_ef10_nic_data *nic_data = efx->nic_data;
3516d8aaaf6SDaniel Pieczko
3523c5eb876SShradha Shah efx_ef10_sriov_free_vf_vswitching(efx);
3533c5eb876SShradha Shah
354dfcabb07SEdward Cree efx_ef10_vadaptor_free(efx, efx->vport_id);
3557b8c7b54SShradha Shah
356dfcabb07SEdward Cree if (efx->vport_id == EVB_PORT_ID_ASSIGNED)
3576d8aaaf6SDaniel Pieczko return; /* No vswitch was ever created */
3586d8aaaf6SDaniel Pieczko
3593c5eb876SShradha Shah if (!is_zero_ether_addr(nic_data->vport_mac)) {
360dfcabb07SEdward Cree efx_ef10_vport_del_mac(efx, efx->vport_id,
3613c5eb876SShradha Shah efx->net_dev->dev_addr);
3623c5eb876SShradha Shah eth_zero_addr(nic_data->vport_mac);
3633c5eb876SShradha Shah }
364dfcabb07SEdward Cree efx_ef10_vport_free(efx, efx->vport_id);
365dfcabb07SEdward Cree efx->vport_id = EVB_PORT_ID_ASSIGNED;
3666d8aaaf6SDaniel Pieczko
3676598dad2SDaniel Pieczko /* Only free the vswitch if no VFs are assigned */
3686598dad2SDaniel Pieczko if (!pci_vfs_assigned(efx->pci_dev))
369dfcabb07SEdward Cree efx_ef10_vswitch_free(efx, efx->vport_id);
3706d8aaaf6SDaniel Pieczko }
3713c5eb876SShradha Shah
efx_ef10_vswitching_remove_vf(struct efx_nic * efx)3727b8c7b54SShradha Shah void efx_ef10_vswitching_remove_vf(struct efx_nic *efx)
3737b8c7b54SShradha Shah {
3747b8c7b54SShradha Shah efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED);
3757b8c7b54SShradha Shah }
3767b8c7b54SShradha Shah
efx_ef10_pci_sriov_enable(struct efx_nic * efx,int num_vfs)3773c5eb876SShradha Shah static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs)
3783c5eb876SShradha Shah {
3793c5eb876SShradha Shah int rc = 0;
3803c5eb876SShradha Shah struct pci_dev *dev = efx->pci_dev;
3813c5eb876SShradha Shah
3823c5eb876SShradha Shah efx->vf_count = num_vfs;
3833c5eb876SShradha Shah
3843c5eb876SShradha Shah rc = efx_ef10_sriov_alloc_vf_vswitching(efx);
3853c5eb876SShradha Shah if (rc)
3863c5eb876SShradha Shah goto fail1;
3873c5eb876SShradha Shah
3883c5eb876SShradha Shah rc = pci_enable_sriov(dev, num_vfs);
3893c5eb876SShradha Shah if (rc)
3903c5eb876SShradha Shah goto fail2;
3913c5eb876SShradha Shah
3923c5eb876SShradha Shah return 0;
3933c5eb876SShradha Shah fail2:
3943c5eb876SShradha Shah efx_ef10_sriov_free_vf_vswitching(efx);
3953c5eb876SShradha Shah fail1:
3963c5eb876SShradha Shah efx->vf_count = 0;
3973c5eb876SShradha Shah netif_err(efx, probe, efx->net_dev,
3983c5eb876SShradha Shah "Failed to enable SRIOV VFs\n");
3993c5eb876SShradha Shah return rc;
4003c5eb876SShradha Shah }
4013c5eb876SShradha Shah
4021ebe4febSÍñigo Huguet /* Disable SRIOV and remove VFs
4031ebe4febSÍñigo Huguet * If some VFs are attached to a guest (using Xen, only) nothing is
4041ebe4febSÍñigo Huguet * done if force=false, and vports are freed if force=true (for the non
4051ebe4febSÍñigo Huguet * attachedc ones, only) but SRIOV is not disabled and VFs are not
4061ebe4febSÍñigo Huguet * removed in either case.
4071ebe4febSÍñigo Huguet */
efx_ef10_pci_sriov_disable(struct efx_nic * efx,bool force)4086598dad2SDaniel Pieczko static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
4093c5eb876SShradha Shah {
4103c5eb876SShradha Shah struct pci_dev *dev = efx->pci_dev;
411ebe41da5SÍñigo Huguet struct efx_ef10_nic_data *nic_data = efx->nic_data;
4121ebe4febSÍñigo Huguet unsigned int vfs_assigned = pci_vfs_assigned(dev);
413ebe41da5SÍñigo Huguet int i, rc = 0;
41471158bf2SDaniel Pieczko
4156598dad2SDaniel Pieczko if (vfs_assigned && !force) {
4166598dad2SDaniel Pieczko netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
41771158bf2SDaniel Pieczko "please detach them before disabling SR-IOV\n");
41871158bf2SDaniel Pieczko return -EBUSY;
41971158bf2SDaniel Pieczko }
42071158bf2SDaniel Pieczko
421ebe41da5SÍñigo Huguet if (!vfs_assigned) {
422ebe41da5SÍñigo Huguet for (i = 0; i < efx->vf_count; i++)
423ebe41da5SÍñigo Huguet nic_data->vf[i].pci_dev = NULL;
4243c5eb876SShradha Shah pci_disable_sriov(dev);
425ebe41da5SÍñigo Huguet } else {
4261ebe4febSÍñigo Huguet rc = -EBUSY;
427ebe41da5SÍñigo Huguet }
4286598dad2SDaniel Pieczko
4293c5eb876SShradha Shah efx_ef10_sriov_free_vf_vswitching(efx);
4303c5eb876SShradha Shah efx->vf_count = 0;
4311ebe4febSÍñigo Huguet return rc;
4323c5eb876SShradha Shah }
4333c5eb876SShradha Shah
efx_ef10_sriov_configure(struct efx_nic * efx,int num_vfs)4343c5eb876SShradha Shah int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
4353c5eb876SShradha Shah {
4363c5eb876SShradha Shah if (num_vfs == 0)
4376598dad2SDaniel Pieczko return efx_ef10_pci_sriov_disable(efx, false);
4383c5eb876SShradha Shah else
4393c5eb876SShradha Shah return efx_ef10_pci_sriov_enable(efx, num_vfs);
4403c5eb876SShradha Shah }
4413c5eb876SShradha Shah
efx_ef10_sriov_init(struct efx_nic * efx)4423c5eb876SShradha Shah int efx_ef10_sriov_init(struct efx_nic *efx)
4433c5eb876SShradha Shah {
4443c5eb876SShradha Shah return 0;
4453c5eb876SShradha Shah }
4463c5eb876SShradha Shah
efx_ef10_sriov_fini(struct efx_nic * efx)4473c5eb876SShradha Shah void efx_ef10_sriov_fini(struct efx_nic *efx)
4483c5eb876SShradha Shah {
4493c5eb876SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
4503c5eb876SShradha Shah int rc;
4513c5eb876SShradha Shah
4526598dad2SDaniel Pieczko if (!nic_data->vf) {
4539a022e76SÍñigo Huguet /* Remove any un-assigned orphaned VFs. This can happen if the PF driver
4549a022e76SÍñigo Huguet * was unloaded while any VF was assigned to a guest (using Xen, only).
4559a022e76SÍñigo Huguet */
4566598dad2SDaniel Pieczko if (pci_num_vf(efx->pci_dev) && !pci_vfs_assigned(efx->pci_dev))
4576598dad2SDaniel Pieczko pci_disable_sriov(efx->pci_dev);
4583c5eb876SShradha Shah return;
4596598dad2SDaniel Pieczko }
4603c5eb876SShradha Shah
46145423cffSÍñigo Huguet /* Disable SRIOV and remove any VFs in the host */
4626598dad2SDaniel Pieczko rc = efx_ef10_pci_sriov_disable(efx, true);
4633c5eb876SShradha Shah if (rc)
4643c5eb876SShradha Shah netif_dbg(efx, drv, efx->net_dev,
4653c5eb876SShradha Shah "Disabling SRIOV was not successful rc=%d\n", rc);
4663c5eb876SShradha Shah else
4673c5eb876SShradha Shah netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n");
4683c5eb876SShradha Shah }
469e340be92SShradha Shah
efx_ef10_vport_del_vf_mac(struct efx_nic * efx,unsigned int port_id,u8 * mac)470e340be92SShradha Shah static int efx_ef10_vport_del_vf_mac(struct efx_nic *efx, unsigned int port_id,
471e340be92SShradha Shah u8 *mac)
472e340be92SShradha Shah {
473e340be92SShradha Shah MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
474e340be92SShradha Shah MCDI_DECLARE_BUF_ERR(outbuf);
475e340be92SShradha Shah size_t outlen;
476e340be92SShradha Shah int rc;
477e340be92SShradha Shah
478e340be92SShradha Shah MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
479e340be92SShradha Shah ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
480e340be92SShradha Shah
481e340be92SShradha Shah rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
482e340be92SShradha Shah sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
483e340be92SShradha Shah
484e340be92SShradha Shah return rc;
485e340be92SShradha Shah }
486e340be92SShradha Shah
efx_ef10_sriov_set_vf_mac(struct efx_nic * efx,int vf_i,const u8 * mac)48776660757SJakub Kicinski int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac)
488e340be92SShradha Shah {
489e340be92SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
490e340be92SShradha Shah struct ef10_vf *vf;
491e340be92SShradha Shah int rc;
492e340be92SShradha Shah
493e340be92SShradha Shah if (!nic_data->vf)
494e340be92SShradha Shah return -EOPNOTSUPP;
495e340be92SShradha Shah
496e340be92SShradha Shah if (vf_i >= efx->vf_count)
497e340be92SShradha Shah return -EINVAL;
498e340be92SShradha Shah vf = nic_data->vf + vf_i;
499e340be92SShradha Shah
500e340be92SShradha Shah if (vf->efx) {
501e340be92SShradha Shah efx_device_detach_sync(vf->efx);
502e340be92SShradha Shah efx_net_stop(vf->efx->net_dev);
503e340be92SShradha Shah
504e340be92SShradha Shah vf->efx->type->filter_table_remove(vf->efx);
505e340be92SShradha Shah
506e340be92SShradha Shah rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
507*77eb4074SEdward Cree if (rc)
508e340be92SShradha Shah return rc;
509e340be92SShradha Shah }
510e340be92SShradha Shah
511e340be92SShradha Shah rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
512e340be92SShradha Shah if (rc)
513e340be92SShradha Shah return rc;
514e340be92SShradha Shah
515e340be92SShradha Shah if (!is_zero_ether_addr(vf->mac)) {
516e340be92SShradha Shah rc = efx_ef10_vport_del_vf_mac(efx, vf->vport_id, vf->mac);
517e340be92SShradha Shah if (rc)
518e340be92SShradha Shah return rc;
519e340be92SShradha Shah }
520e340be92SShradha Shah
521e340be92SShradha Shah if (!is_zero_ether_addr(mac)) {
522e340be92SShradha Shah rc = efx_ef10_vport_add_mac(efx, vf->vport_id, mac);
523db99d512SChristophe JAILLET if (rc)
524e340be92SShradha Shah goto fail;
525db99d512SChristophe JAILLET
526e340be92SShradha Shah if (vf->efx)
527f3956ebbSJakub Kicinski eth_hw_addr_set(vf->efx->net_dev, mac);
528e340be92SShradha Shah }
529e340be92SShradha Shah
530e340be92SShradha Shah ether_addr_copy(vf->mac, mac);
531e340be92SShradha Shah
532e340be92SShradha Shah rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
533e340be92SShradha Shah if (rc)
534e340be92SShradha Shah goto fail;
535e340be92SShradha Shah
536e340be92SShradha Shah if (vf->efx) {
537e340be92SShradha Shah /* VF cannot use the vport_id that the PF created */
538e340be92SShradha Shah rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
539*77eb4074SEdward Cree if (rc)
540e340be92SShradha Shah return rc;
541e340be92SShradha Shah vf->efx->type->filter_table_probe(vf->efx);
542e340be92SShradha Shah efx_net_open(vf->efx->net_dev);
5439c568fd8SPeter Dunning efx_device_attach_if_not_resetting(vf->efx);
544e340be92SShradha Shah }
545e340be92SShradha Shah
546e340be92SShradha Shah return 0;
547e340be92SShradha Shah
548e340be92SShradha Shah fail:
5494b5b1ac5SShyam Saini eth_zero_addr(vf->mac);
550e340be92SShradha Shah return rc;
551e340be92SShradha Shah }
552b9af9049SShradha Shah
efx_ef10_sriov_set_vf_vlan(struct efx_nic * efx,int vf_i,u16 vlan,u8 qos)5532d432f20SShradha Shah int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
5542d432f20SShradha Shah u8 qos)
5552d432f20SShradha Shah {
5562d432f20SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
5572d432f20SShradha Shah struct ef10_vf *vf;
5582e6dde5cSColin Ian King u16 new_vlan;
5592d432f20SShradha Shah int rc = 0, rc2 = 0;
5602d432f20SShradha Shah
5612d432f20SShradha Shah if (vf_i >= efx->vf_count)
5622d432f20SShradha Shah return -EINVAL;
5632d432f20SShradha Shah if (qos != 0)
5642d432f20SShradha Shah return -EINVAL;
5652d432f20SShradha Shah
5662d432f20SShradha Shah vf = nic_data->vf + vf_i;
5672d432f20SShradha Shah
5682d432f20SShradha Shah new_vlan = (vlan == 0) ? EFX_EF10_NO_VLAN : vlan;
5692d432f20SShradha Shah if (new_vlan == vf->vlan)
5702d432f20SShradha Shah return 0;
5712d432f20SShradha Shah
5722d432f20SShradha Shah if (vf->efx) {
5732d432f20SShradha Shah efx_device_detach_sync(vf->efx);
5742d432f20SShradha Shah efx_net_stop(vf->efx->net_dev);
5752d432f20SShradha Shah
576d248953aSMartin Habets mutex_lock(&vf->efx->mac_lock);
5772d432f20SShradha Shah vf->efx->type->filter_table_remove(vf->efx);
5782d432f20SShradha Shah
5792d432f20SShradha Shah rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
5802d432f20SShradha Shah if (rc)
5812d432f20SShradha Shah goto restore_filters;
5822d432f20SShradha Shah }
5832d432f20SShradha Shah
5842d432f20SShradha Shah if (vf->vport_assigned) {
5852d432f20SShradha Shah rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
5862d432f20SShradha Shah if (rc) {
5872d432f20SShradha Shah netif_warn(efx, drv, efx->net_dev,
5882d432f20SShradha Shah "Failed to change vlan on VF %d.\n", vf_i);
5892d432f20SShradha Shah netif_warn(efx, drv, efx->net_dev,
5902d432f20SShradha Shah "This is likely because the VF is bound to a driver in a VM.\n");
5912d432f20SShradha Shah netif_warn(efx, drv, efx->net_dev,
5922d432f20SShradha Shah "Please unload the driver in the VM.\n");
5932d432f20SShradha Shah goto restore_vadaptor;
5942d432f20SShradha Shah }
5952d432f20SShradha Shah vf->vport_assigned = 0;
5962d432f20SShradha Shah }
5972d432f20SShradha Shah
5982d432f20SShradha Shah if (!is_zero_ether_addr(vf->mac)) {
5992d432f20SShradha Shah rc = efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
6002d432f20SShradha Shah if (rc)
6012d432f20SShradha Shah goto restore_evb_port;
6022d432f20SShradha Shah }
6032d432f20SShradha Shah
6042d432f20SShradha Shah if (vf->vport_id) {
6052d432f20SShradha Shah rc = efx_ef10_vport_free(efx, vf->vport_id);
6062d432f20SShradha Shah if (rc)
6072d432f20SShradha Shah goto restore_mac;
6082d432f20SShradha Shah vf->vport_id = 0;
6092d432f20SShradha Shah }
6102d432f20SShradha Shah
6112d432f20SShradha Shah /* Do the actual vlan change */
6122d432f20SShradha Shah vf->vlan = new_vlan;
6132d432f20SShradha Shah
6142d432f20SShradha Shah /* Restore everything in reverse order */
6152d432f20SShradha Shah rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
6162d432f20SShradha Shah MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
6172d432f20SShradha Shah vf->vlan, &vf->vport_id);
6182d432f20SShradha Shah if (rc)
619671b53eeSShradha Shah goto reset_nic_up_write;
6202d432f20SShradha Shah
6212d432f20SShradha Shah restore_mac:
6222d432f20SShradha Shah if (!is_zero_ether_addr(vf->mac)) {
6232d432f20SShradha Shah rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
6242d432f20SShradha Shah if (rc2) {
6252d432f20SShradha Shah eth_zero_addr(vf->mac);
626671b53eeSShradha Shah goto reset_nic_up_write;
6272d432f20SShradha Shah }
6282d432f20SShradha Shah }
6292d432f20SShradha Shah
6302d432f20SShradha Shah restore_evb_port:
6312d432f20SShradha Shah rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
6322d432f20SShradha Shah if (rc2)
633671b53eeSShradha Shah goto reset_nic_up_write;
6342d432f20SShradha Shah else
6352d432f20SShradha Shah vf->vport_assigned = 1;
6362d432f20SShradha Shah
6372d432f20SShradha Shah restore_vadaptor:
6382d432f20SShradha Shah if (vf->efx) {
6392d432f20SShradha Shah rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
6402d432f20SShradha Shah if (rc2)
641671b53eeSShradha Shah goto reset_nic_up_write;
6422d432f20SShradha Shah }
6432d432f20SShradha Shah
6442d432f20SShradha Shah restore_filters:
6452d432f20SShradha Shah if (vf->efx) {
6462d432f20SShradha Shah rc2 = vf->efx->type->filter_table_probe(vf->efx);
6472d432f20SShradha Shah if (rc2)
648671b53eeSShradha Shah goto reset_nic_up_write;
649671b53eeSShradha Shah
650d248953aSMartin Habets mutex_unlock(&vf->efx->mac_lock);
6512d432f20SShradha Shah
6522d432f20SShradha Shah rc2 = efx_net_open(vf->efx->net_dev);
6532d432f20SShradha Shah if (rc2)
6542d432f20SShradha Shah goto reset_nic;
6552d432f20SShradha Shah
6569c568fd8SPeter Dunning efx_device_attach_if_not_resetting(vf->efx);
6572d432f20SShradha Shah }
6582d432f20SShradha Shah return rc;
6592d432f20SShradha Shah
660671b53eeSShradha Shah reset_nic_up_write:
661*77eb4074SEdward Cree if (vf->efx)
662d248953aSMartin Habets mutex_unlock(&vf->efx->mac_lock);
6632d432f20SShradha Shah reset_nic:
6642d432f20SShradha Shah if (vf->efx) {
6652d432f20SShradha Shah netif_err(efx, drv, efx->net_dev,
6662d432f20SShradha Shah "Failed to restore VF - scheduling reset.\n");
6672d432f20SShradha Shah efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH);
6682d432f20SShradha Shah } else {
6692d432f20SShradha Shah netif_err(efx, drv, efx->net_dev,
6702d432f20SShradha Shah "Failed to restore the VF and cannot reset the VF "
6712d432f20SShradha Shah "- VF is not functional.\n");
6722d432f20SShradha Shah netif_err(efx, drv, efx->net_dev,
6732d432f20SShradha Shah "Please reload the driver attached to the VF.\n");
6742d432f20SShradha Shah }
6752d432f20SShradha Shah
6762d432f20SShradha Shah return rc ? rc : rc2;
6772d432f20SShradha Shah }
6782d432f20SShradha Shah
efx_ef10_sriov_set_privilege_mask(struct efx_nic * efx,int vf_i,u32 mask,u32 value)679085793f0SEdward Cree static int efx_ef10_sriov_set_privilege_mask(struct efx_nic *efx, int vf_i,
680085793f0SEdward Cree u32 mask, u32 value)
681860d2ffaSShradha Shah {
682085793f0SEdward Cree MCDI_DECLARE_BUF(pm_outbuf, MC_CMD_PRIVILEGE_MASK_OUT_LEN);
683085793f0SEdward Cree MCDI_DECLARE_BUF(pm_inbuf, MC_CMD_PRIVILEGE_MASK_IN_LEN);
684085793f0SEdward Cree struct efx_ef10_nic_data *nic_data = efx->nic_data;
685085793f0SEdward Cree u32 old_mask, new_mask;
686085793f0SEdward Cree size_t outlen;
687085793f0SEdward Cree int rc;
688085793f0SEdward Cree
689085793f0SEdward Cree EFX_WARN_ON_PARANOID((value & ~mask) != 0);
690085793f0SEdward Cree
691085793f0SEdward Cree /* Get privilege mask */
692085793f0SEdward Cree MCDI_POPULATE_DWORD_2(pm_inbuf, PRIVILEGE_MASK_IN_FUNCTION,
693085793f0SEdward Cree PRIVILEGE_MASK_IN_FUNCTION_PF, nic_data->pf_index,
694085793f0SEdward Cree PRIVILEGE_MASK_IN_FUNCTION_VF, vf_i);
695085793f0SEdward Cree
696085793f0SEdward Cree rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK,
697085793f0SEdward Cree pm_inbuf, sizeof(pm_inbuf),
698085793f0SEdward Cree pm_outbuf, sizeof(pm_outbuf), &outlen);
699085793f0SEdward Cree
700085793f0SEdward Cree if (rc != 0)
701085793f0SEdward Cree return rc;
702085793f0SEdward Cree if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN)
703085793f0SEdward Cree return -EIO;
704085793f0SEdward Cree
705085793f0SEdward Cree old_mask = MCDI_DWORD(pm_outbuf, PRIVILEGE_MASK_OUT_OLD_MASK);
706085793f0SEdward Cree
707085793f0SEdward Cree new_mask = old_mask & ~mask;
708085793f0SEdward Cree new_mask |= value;
709085793f0SEdward Cree
710085793f0SEdward Cree if (new_mask == old_mask)
711085793f0SEdward Cree return 0;
712085793f0SEdward Cree
713085793f0SEdward Cree new_mask |= MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE;
714085793f0SEdward Cree
715085793f0SEdward Cree /* Set privilege mask */
716085793f0SEdward Cree MCDI_SET_DWORD(pm_inbuf, PRIVILEGE_MASK_IN_NEW_MASK, new_mask);
717085793f0SEdward Cree
718085793f0SEdward Cree rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK,
719085793f0SEdward Cree pm_inbuf, sizeof(pm_inbuf),
720085793f0SEdward Cree pm_outbuf, sizeof(pm_outbuf), &outlen);
721085793f0SEdward Cree
722085793f0SEdward Cree if (rc != 0)
723085793f0SEdward Cree return rc;
724085793f0SEdward Cree if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN)
725085793f0SEdward Cree return -EIO;
726085793f0SEdward Cree
727085793f0SEdward Cree return 0;
728085793f0SEdward Cree }
729085793f0SEdward Cree
efx_ef10_sriov_set_vf_spoofchk(struct efx_nic * efx,int vf_i,bool spoofchk)730085793f0SEdward Cree int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk)
731085793f0SEdward Cree {
732085793f0SEdward Cree struct efx_ef10_nic_data *nic_data = efx->nic_data;
733085793f0SEdward Cree
734085793f0SEdward Cree /* Can't enable spoofchk if firmware doesn't support it. */
735085793f0SEdward Cree if (!(nic_data->datapath_caps &
736085793f0SEdward Cree BIT(MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_LBN)) &&
737085793f0SEdward Cree spoofchk)
738085793f0SEdward Cree return -EOPNOTSUPP;
739085793f0SEdward Cree
740085793f0SEdward Cree return efx_ef10_sriov_set_privilege_mask(efx, vf_i,
741085793f0SEdward Cree MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX,
742085793f0SEdward Cree spoofchk ? 0 : MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX);
743860d2ffaSShradha Shah }
744860d2ffaSShradha Shah
efx_ef10_sriov_set_vf_link_state(struct efx_nic * efx,int vf_i,int link_state)7454392dc69SEdward Cree int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i,
7464392dc69SEdward Cree int link_state)
7474392dc69SEdward Cree {
7484392dc69SEdward Cree MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN);
7494392dc69SEdward Cree struct efx_ef10_nic_data *nic_data = efx->nic_data;
7504392dc69SEdward Cree
7514392dc69SEdward Cree BUILD_BUG_ON(IFLA_VF_LINK_STATE_AUTO !=
7524392dc69SEdward Cree MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO);
7534392dc69SEdward Cree BUILD_BUG_ON(IFLA_VF_LINK_STATE_ENABLE !=
7544392dc69SEdward Cree MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP);
7554392dc69SEdward Cree BUILD_BUG_ON(IFLA_VF_LINK_STATE_DISABLE !=
7564392dc69SEdward Cree MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN);
7574392dc69SEdward Cree MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION,
7584392dc69SEdward Cree LINK_STATE_MODE_IN_FUNCTION_PF,
7594392dc69SEdward Cree nic_data->pf_index,
7604392dc69SEdward Cree LINK_STATE_MODE_IN_FUNCTION_VF, vf_i);
7614392dc69SEdward Cree MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, link_state);
7624392dc69SEdward Cree return efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf),
7634392dc69SEdward Cree NULL, 0, NULL); /* don't care what old mode was */
7644392dc69SEdward Cree }
7654392dc69SEdward Cree
efx_ef10_sriov_get_vf_config(struct efx_nic * efx,int vf_i,struct ifla_vf_info * ivf)766b9af9049SShradha Shah int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i,
767b9af9049SShradha Shah struct ifla_vf_info *ivf)
768b9af9049SShradha Shah {
7694392dc69SEdward Cree MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN);
7704392dc69SEdward Cree MCDI_DECLARE_BUF(outbuf, MC_CMD_LINK_STATE_MODE_OUT_LEN);
7714392dc69SEdward Cree
772b9af9049SShradha Shah struct efx_ef10_nic_data *nic_data = efx->nic_data;
773b9af9049SShradha Shah struct ef10_vf *vf;
7744392dc69SEdward Cree size_t outlen;
7754392dc69SEdward Cree int rc;
776b9af9049SShradha Shah
777b9af9049SShradha Shah if (vf_i >= efx->vf_count)
778b9af9049SShradha Shah return -EINVAL;
779b9af9049SShradha Shah
780b9af9049SShradha Shah if (!nic_data->vf)
781b9af9049SShradha Shah return -EOPNOTSUPP;
782b9af9049SShradha Shah
783b9af9049SShradha Shah vf = nic_data->vf + vf_i;
784b9af9049SShradha Shah
785b9af9049SShradha Shah ivf->vf = vf_i;
786b9af9049SShradha Shah ivf->min_tx_rate = 0;
787b9af9049SShradha Shah ivf->max_tx_rate = 0;
788b9af9049SShradha Shah ether_addr_copy(ivf->mac, vf->mac);
7892d432f20SShradha Shah ivf->vlan = (vf->vlan == EFX_EF10_NO_VLAN) ? 0 : vf->vlan;
790b9af9049SShradha Shah ivf->qos = 0;
791b9af9049SShradha Shah
7924392dc69SEdward Cree MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION,
7934392dc69SEdward Cree LINK_STATE_MODE_IN_FUNCTION_PF,
7944392dc69SEdward Cree nic_data->pf_index,
7954392dc69SEdward Cree LINK_STATE_MODE_IN_FUNCTION_VF, vf_i);
7964392dc69SEdward Cree MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE,
7974392dc69SEdward Cree MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE);
7984392dc69SEdward Cree rc = efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf),
7994392dc69SEdward Cree outbuf, sizeof(outbuf), &outlen);
8004392dc69SEdward Cree if (rc)
8014392dc69SEdward Cree return rc;
8024392dc69SEdward Cree if (outlen < MC_CMD_LINK_STATE_MODE_OUT_LEN)
8034392dc69SEdward Cree return -EIO;
8044392dc69SEdward Cree ivf->linkstate = MCDI_DWORD(outbuf, LINK_STATE_MODE_OUT_OLD_MODE);
8054392dc69SEdward Cree
806b9af9049SShradha Shah return 0;
807b9af9049SShradha Shah }
808