xref: /openbmc/linux/drivers/net/ethernet/sfc/ef10_sriov.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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