18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2015 Solarflare Communications Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 78c2ecf20Sopenharmony_ci#include <linux/pci.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include "net_driver.h" 108c2ecf20Sopenharmony_ci#include "ef10_sriov.h" 118c2ecf20Sopenharmony_ci#include "efx.h" 128c2ecf20Sopenharmony_ci#include "nic.h" 138c2ecf20Sopenharmony_ci#include "mcdi_pcol.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id, 168c2ecf20Sopenharmony_ci unsigned int vf_fn) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_EVB_PORT_ASSIGN_IN_LEN); 198c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, EVB_PORT_ASSIGN_IN_PORT_ID, port_id); 228c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_2(inbuf, EVB_PORT_ASSIGN_IN_FUNCTION, 238c2ecf20Sopenharmony_ci EVB_PORT_ASSIGN_IN_PF, nic_data->pf_index, 248c2ecf20Sopenharmony_ci EVB_PORT_ASSIGN_IN_VF, vf_fn); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return efx_mcdi_rpc(efx, MC_CMD_EVB_PORT_ASSIGN, inbuf, sizeof(inbuf), 278c2ecf20Sopenharmony_ci NULL, 0, NULL); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, 318c2ecf20Sopenharmony_ci unsigned int vswitch_type) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN); 348c2ecf20Sopenharmony_ci int rc; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id); 378c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type); 388c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 2); 398c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS, 408c2ecf20Sopenharmony_ci VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* Quietly try to allocate 2 VLAN tags */ 438c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf), 448c2ecf20Sopenharmony_ci NULL, 0, NULL); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* If 2 VLAN tags is too many, revert to trying with 1 VLAN tags */ 478c2ecf20Sopenharmony_ci if (rc == -EPROTO) { 488c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 1); 498c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf, 508c2ecf20Sopenharmony_ci sizeof(inbuf), NULL, 0, NULL); 518c2ecf20Sopenharmony_ci } else if (rc) { 528c2ecf20Sopenharmony_ci efx_mcdi_display_error(efx, MC_CMD_VSWITCH_ALLOC, 538c2ecf20Sopenharmony_ci MC_CMD_VSWITCH_ALLOC_IN_LEN, 548c2ecf20Sopenharmony_ci NULL, 0, rc); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci return rc; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_FREE_IN_LEN); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VSWITCH_FREE_IN_UPSTREAM_PORT_ID, port_id); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_FREE, inbuf, sizeof(inbuf), 668c2ecf20Sopenharmony_ci NULL, 0, NULL); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int efx_ef10_vport_alloc(struct efx_nic *efx, 708c2ecf20Sopenharmony_ci unsigned int port_id_in, 718c2ecf20Sopenharmony_ci unsigned int vport_type, 728c2ecf20Sopenharmony_ci u16 vlan, 738c2ecf20Sopenharmony_ci unsigned int *port_id_out) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN); 768c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_ALLOC_OUT_LEN); 778c2ecf20Sopenharmony_ci size_t outlen; 788c2ecf20Sopenharmony_ci int rc; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci EFX_WARN_ON_PARANOID(!port_id_out); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in); 838c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type); 848c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS, 858c2ecf20Sopenharmony_ci (vlan != EFX_EF10_NO_VLAN)); 868c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS, 878c2ecf20Sopenharmony_ci VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0); 888c2ecf20Sopenharmony_ci if (vlan != EFX_EF10_NO_VLAN) 898c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_VLAN_TAGS, 908c2ecf20Sopenharmony_ci VPORT_ALLOC_IN_VLAN_TAG_0, vlan); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, sizeof(inbuf), 938c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlen); 948c2ecf20Sopenharmony_ci if (rc) 958c2ecf20Sopenharmony_ci return rc; 968c2ecf20Sopenharmony_ci if (outlen < MC_CMD_VPORT_ALLOC_OUT_LEN) 978c2ecf20Sopenharmony_ci return -EIO; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci *port_id_out = MCDI_DWORD(outbuf, VPORT_ALLOC_OUT_VPORT_ID); 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_FREE_IN_LEN); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VPORT_FREE_IN_VPORT_ID, port_id); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return efx_mcdi_rpc(efx, MC_CMD_VPORT_FREE, inbuf, sizeof(inbuf), 1108c2ecf20Sopenharmony_ci NULL, 0, NULL); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 1168c2ecf20Sopenharmony_ci int i; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (!nic_data->vf) 1198c2ecf20Sopenharmony_ci return; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci for (i = 0; i < efx->vf_count; i++) { 1228c2ecf20Sopenharmony_ci struct ef10_vf *vf = nic_data->vf + i; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* If VF is assigned, do not free the vport */ 1258c2ecf20Sopenharmony_ci if (vf->pci_dev && 1268c2ecf20Sopenharmony_ci vf->pci_dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) 1278c2ecf20Sopenharmony_ci continue; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (vf->vport_assigned) { 1308c2ecf20Sopenharmony_ci efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i); 1318c2ecf20Sopenharmony_ci vf->vport_assigned = 0; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(vf->mac)) { 1358c2ecf20Sopenharmony_ci efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac); 1368c2ecf20Sopenharmony_ci eth_zero_addr(vf->mac); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (vf->vport_id) { 1408c2ecf20Sopenharmony_ci efx_ef10_vport_free(efx, vf->vport_id); 1418c2ecf20Sopenharmony_ci vf->vport_id = 0; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci vf->efx = NULL; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void efx_ef10_sriov_free_vf_vswitching(struct efx_nic *efx) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci efx_ef10_sriov_free_vf_vports(efx); 1538c2ecf20Sopenharmony_ci kfree(nic_data->vf); 1548c2ecf20Sopenharmony_ci nic_data->vf = NULL; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx, 1588c2ecf20Sopenharmony_ci unsigned int vf_i) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 1618c2ecf20Sopenharmony_ci struct ef10_vf *vf = nic_data->vf + vf_i; 1628c2ecf20Sopenharmony_ci int rc; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!nic_data->vf)) 1658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, 1688c2ecf20Sopenharmony_ci MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, 1698c2ecf20Sopenharmony_ci vf->vlan, &vf->vport_id); 1708c2ecf20Sopenharmony_ci if (rc) 1718c2ecf20Sopenharmony_ci return rc; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci rc = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac); 1748c2ecf20Sopenharmony_ci if (rc) { 1758c2ecf20Sopenharmony_ci eth_zero_addr(vf->mac); 1768c2ecf20Sopenharmony_ci return rc; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i); 1808c2ecf20Sopenharmony_ci if (rc) 1818c2ecf20Sopenharmony_ci return rc; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci vf->vport_assigned = 1; 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 1908c2ecf20Sopenharmony_ci unsigned int i; 1918c2ecf20Sopenharmony_ci int rc; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci nic_data->vf = kcalloc(efx->vf_count, sizeof(struct ef10_vf), 1948c2ecf20Sopenharmony_ci GFP_KERNEL); 1958c2ecf20Sopenharmony_ci if (!nic_data->vf) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci for (i = 0; i < efx->vf_count; i++) { 1998c2ecf20Sopenharmony_ci eth_random_addr(nic_data->vf[i].mac); 2008c2ecf20Sopenharmony_ci nic_data->vf[i].efx = NULL; 2018c2ecf20Sopenharmony_ci nic_data->vf[i].vlan = EFX_EF10_NO_VLAN; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci rc = efx_ef10_sriov_assign_vf_vport(efx, i); 2048c2ecf20Sopenharmony_ci if (rc) 2058c2ecf20Sopenharmony_ci goto fail; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_cifail: 2108c2ecf20Sopenharmony_ci efx_ef10_sriov_free_vf_vports(efx); 2118c2ecf20Sopenharmony_ci kfree(nic_data->vf); 2128c2ecf20Sopenharmony_ci nic_data->vf = NULL; 2138c2ecf20Sopenharmony_ci return rc; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int efx_ef10_sriov_restore_vf_vswitching(struct efx_nic *efx) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci unsigned int i; 2198c2ecf20Sopenharmony_ci int rc; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci for (i = 0; i < efx->vf_count; i++) { 2228c2ecf20Sopenharmony_ci rc = efx_ef10_sriov_assign_vf_vport(efx, i); 2238c2ecf20Sopenharmony_ci if (rc) 2248c2ecf20Sopenharmony_ci goto fail; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_cifail: 2298c2ecf20Sopenharmony_ci efx_ef10_sriov_free_vf_vswitching(efx); 2308c2ecf20Sopenharmony_ci return rc; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int efx_ef10_vadaptor_alloc_set_features(struct efx_nic *efx) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci u32 port_flags; 2368c2ecf20Sopenharmony_ci int rc; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_alloc(efx, efx->vport_id); 2398c2ecf20Sopenharmony_ci if (rc) 2408c2ecf20Sopenharmony_ci goto fail_vadaptor_alloc; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_query(efx, efx->vport_id, 2438c2ecf20Sopenharmony_ci &port_flags, NULL, NULL); 2448c2ecf20Sopenharmony_ci if (rc) 2458c2ecf20Sopenharmony_ci goto fail_vadaptor_query; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (port_flags & 2488c2ecf20Sopenharmony_ci (1 << MC_CMD_VPORT_ALLOC_IN_FLAG_VLAN_RESTRICT_LBN)) 2498c2ecf20Sopenharmony_ci efx->fixed_features |= NETIF_F_HW_VLAN_CTAG_FILTER; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci efx->fixed_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cifail_vadaptor_query: 2568c2ecf20Sopenharmony_ci efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); 2578c2ecf20Sopenharmony_cifail_vadaptor_alloc: 2588c2ecf20Sopenharmony_ci return rc; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* On top of the default firmware vswitch setup, create a VEB vswitch and 2628c2ecf20Sopenharmony_ci * expansion vport for use by this function. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ciint efx_ef10_vswitching_probe_pf(struct efx_nic *efx) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 2678c2ecf20Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 2688c2ecf20Sopenharmony_ci int rc; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) { 2718c2ecf20Sopenharmony_ci /* vswitch not needed as we have no VFs */ 2728c2ecf20Sopenharmony_ci efx_ef10_vadaptor_alloc_set_features(efx); 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED, 2778c2ecf20Sopenharmony_ci MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB); 2788c2ecf20Sopenharmony_ci if (rc) 2798c2ecf20Sopenharmony_ci goto fail1; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, 2828c2ecf20Sopenharmony_ci MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, 2838c2ecf20Sopenharmony_ci EFX_EF10_NO_VLAN, &efx->vport_id); 2848c2ecf20Sopenharmony_ci if (rc) 2858c2ecf20Sopenharmony_ci goto fail2; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci rc = efx_ef10_vport_add_mac(efx, efx->vport_id, net_dev->dev_addr); 2888c2ecf20Sopenharmony_ci if (rc) 2898c2ecf20Sopenharmony_ci goto fail3; 2908c2ecf20Sopenharmony_ci ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_alloc_set_features(efx); 2938c2ecf20Sopenharmony_ci if (rc) 2948c2ecf20Sopenharmony_ci goto fail4; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_cifail4: 2988c2ecf20Sopenharmony_ci efx_ef10_vport_del_mac(efx, efx->vport_id, nic_data->vport_mac); 2998c2ecf20Sopenharmony_ci eth_zero_addr(nic_data->vport_mac); 3008c2ecf20Sopenharmony_cifail3: 3018c2ecf20Sopenharmony_ci efx_ef10_vport_free(efx, efx->vport_id); 3028c2ecf20Sopenharmony_ci efx->vport_id = EVB_PORT_ID_ASSIGNED; 3038c2ecf20Sopenharmony_cifail2: 3048c2ecf20Sopenharmony_ci efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED); 3058c2ecf20Sopenharmony_cifail1: 3068c2ecf20Sopenharmony_ci return rc; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciint efx_ef10_vswitching_probe_vf(struct efx_nic *efx) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci return efx_ef10_vadaptor_alloc_set_features(efx); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ciint efx_ef10_vswitching_restore_pf(struct efx_nic *efx) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 3178c2ecf20Sopenharmony_ci int rc; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!nic_data->must_probe_vswitching) 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci rc = efx_ef10_vswitching_probe_pf(efx); 3238c2ecf20Sopenharmony_ci if (rc) 3248c2ecf20Sopenharmony_ci goto fail; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci rc = efx_ef10_sriov_restore_vf_vswitching(efx); 3278c2ecf20Sopenharmony_ci if (rc) 3288c2ecf20Sopenharmony_ci goto fail; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci nic_data->must_probe_vswitching = false; 3318c2ecf20Sopenharmony_cifail: 3328c2ecf20Sopenharmony_ci return rc; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ciint efx_ef10_vswitching_restore_vf(struct efx_nic *efx) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 3388c2ecf20Sopenharmony_ci int rc; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!nic_data->must_probe_vswitching) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); 3448c2ecf20Sopenharmony_ci if (rc) 3458c2ecf20Sopenharmony_ci return rc; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci nic_data->must_probe_vswitching = false; 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_civoid efx_ef10_vswitching_remove_pf(struct efx_nic *efx) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci efx_ef10_sriov_free_vf_vswitching(efx); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci efx_ef10_vadaptor_free(efx, efx->vport_id); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (efx->vport_id == EVB_PORT_ID_ASSIGNED) 3608c2ecf20Sopenharmony_ci return; /* No vswitch was ever created */ 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(nic_data->vport_mac)) { 3638c2ecf20Sopenharmony_ci efx_ef10_vport_del_mac(efx, efx->vport_id, 3648c2ecf20Sopenharmony_ci efx->net_dev->dev_addr); 3658c2ecf20Sopenharmony_ci eth_zero_addr(nic_data->vport_mac); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci efx_ef10_vport_free(efx, efx->vport_id); 3688c2ecf20Sopenharmony_ci efx->vport_id = EVB_PORT_ID_ASSIGNED; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Only free the vswitch if no VFs are assigned */ 3718c2ecf20Sopenharmony_ci if (!pci_vfs_assigned(efx->pci_dev)) 3728c2ecf20Sopenharmony_ci efx_ef10_vswitch_free(efx, efx->vport_id); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_civoid efx_ef10_vswitching_remove_vf(struct efx_nic *efx) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int rc = 0; 3838c2ecf20Sopenharmony_ci struct pci_dev *dev = efx->pci_dev; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci efx->vf_count = num_vfs; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci rc = efx_ef10_sriov_alloc_vf_vswitching(efx); 3888c2ecf20Sopenharmony_ci if (rc) 3898c2ecf20Sopenharmony_ci goto fail1; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci rc = pci_enable_sriov(dev, num_vfs); 3928c2ecf20Sopenharmony_ci if (rc) 3938c2ecf20Sopenharmony_ci goto fail2; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_cifail2: 3978c2ecf20Sopenharmony_ci efx_ef10_sriov_free_vf_vswitching(efx); 3988c2ecf20Sopenharmony_cifail1: 3998c2ecf20Sopenharmony_ci efx->vf_count = 0; 4008c2ecf20Sopenharmony_ci netif_err(efx, probe, efx->net_dev, 4018c2ecf20Sopenharmony_ci "Failed to enable SRIOV VFs\n"); 4028c2ecf20Sopenharmony_ci return rc; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* Disable SRIOV and remove VFs 4068c2ecf20Sopenharmony_ci * If some VFs are attached to a guest (using Xen, only) nothing is 4078c2ecf20Sopenharmony_ci * done if force=false, and vports are freed if force=true (for the non 4088c2ecf20Sopenharmony_ci * attachedc ones, only) but SRIOV is not disabled and VFs are not 4098c2ecf20Sopenharmony_ci * removed in either case. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_cistatic int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct pci_dev *dev = efx->pci_dev; 4148c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 4158c2ecf20Sopenharmony_ci unsigned int vfs_assigned = pci_vfs_assigned(dev); 4168c2ecf20Sopenharmony_ci int i, rc = 0; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (vfs_assigned && !force) { 4198c2ecf20Sopenharmony_ci netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; " 4208c2ecf20Sopenharmony_ci "please detach them before disabling SR-IOV\n"); 4218c2ecf20Sopenharmony_ci return -EBUSY; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (!vfs_assigned) { 4258c2ecf20Sopenharmony_ci for (i = 0; i < efx->vf_count; i++) 4268c2ecf20Sopenharmony_ci nic_data->vf[i].pci_dev = NULL; 4278c2ecf20Sopenharmony_ci pci_disable_sriov(dev); 4288c2ecf20Sopenharmony_ci } else { 4298c2ecf20Sopenharmony_ci rc = -EBUSY; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci efx_ef10_sriov_free_vf_vswitching(efx); 4338c2ecf20Sopenharmony_ci efx->vf_count = 0; 4348c2ecf20Sopenharmony_ci return rc; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ciint efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci if (num_vfs == 0) 4408c2ecf20Sopenharmony_ci return efx_ef10_pci_sriov_disable(efx, false); 4418c2ecf20Sopenharmony_ci else 4428c2ecf20Sopenharmony_ci return efx_ef10_pci_sriov_enable(efx, num_vfs); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciint efx_ef10_sriov_init(struct efx_nic *efx) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_civoid efx_ef10_sriov_fini(struct efx_nic *efx) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 4538c2ecf20Sopenharmony_ci int rc; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!nic_data->vf) { 4568c2ecf20Sopenharmony_ci /* Remove any un-assigned orphaned VFs */ 4578c2ecf20Sopenharmony_ci if (pci_num_vf(efx->pci_dev) && !pci_vfs_assigned(efx->pci_dev)) 4588c2ecf20Sopenharmony_ci pci_disable_sriov(efx->pci_dev); 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* Disable SRIOV and remove any VFs in the host */ 4638c2ecf20Sopenharmony_ci rc = efx_ef10_pci_sriov_disable(efx, true); 4648c2ecf20Sopenharmony_ci if (rc) 4658c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 4668c2ecf20Sopenharmony_ci "Disabling SRIOV was not successful rc=%d\n", rc); 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n"); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic int efx_ef10_vport_del_vf_mac(struct efx_nic *efx, unsigned int port_id, 4728c2ecf20Sopenharmony_ci u8 *mac) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); 4758c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF_ERR(outbuf); 4768c2ecf20Sopenharmony_ci size_t outlen; 4778c2ecf20Sopenharmony_ci int rc; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); 4808c2ecf20Sopenharmony_ci ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, 4838c2ecf20Sopenharmony_ci sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return rc; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciint efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, u8 *mac) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 4918c2ecf20Sopenharmony_ci struct ef10_vf *vf; 4928c2ecf20Sopenharmony_ci int rc; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (!nic_data->vf) 4958c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (vf_i >= efx->vf_count) 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci vf = nic_data->vf + vf_i; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (vf->efx) { 5028c2ecf20Sopenharmony_ci efx_device_detach_sync(vf->efx); 5038c2ecf20Sopenharmony_ci efx_net_stop(vf->efx->net_dev); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci down_write(&vf->efx->filter_sem); 5068c2ecf20Sopenharmony_ci vf->efx->type->filter_table_remove(vf->efx); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED); 5098c2ecf20Sopenharmony_ci if (rc) { 5108c2ecf20Sopenharmony_ci up_write(&vf->efx->filter_sem); 5118c2ecf20Sopenharmony_ci return rc; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i); 5168c2ecf20Sopenharmony_ci if (rc) 5178c2ecf20Sopenharmony_ci return rc; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(vf->mac)) { 5208c2ecf20Sopenharmony_ci rc = efx_ef10_vport_del_vf_mac(efx, vf->vport_id, vf->mac); 5218c2ecf20Sopenharmony_ci if (rc) 5228c2ecf20Sopenharmony_ci return rc; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(mac)) { 5268c2ecf20Sopenharmony_ci rc = efx_ef10_vport_add_mac(efx, vf->vport_id, mac); 5278c2ecf20Sopenharmony_ci if (rc) 5288c2ecf20Sopenharmony_ci goto fail; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (vf->efx) 5318c2ecf20Sopenharmony_ci ether_addr_copy(vf->efx->net_dev->dev_addr, mac); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci ether_addr_copy(vf->mac, mac); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i); 5378c2ecf20Sopenharmony_ci if (rc) 5388c2ecf20Sopenharmony_ci goto fail; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (vf->efx) { 5418c2ecf20Sopenharmony_ci /* VF cannot use the vport_id that the PF created */ 5428c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED); 5438c2ecf20Sopenharmony_ci if (rc) { 5448c2ecf20Sopenharmony_ci up_write(&vf->efx->filter_sem); 5458c2ecf20Sopenharmony_ci return rc; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci vf->efx->type->filter_table_probe(vf->efx); 5488c2ecf20Sopenharmony_ci up_write(&vf->efx->filter_sem); 5498c2ecf20Sopenharmony_ci efx_net_open(vf->efx->net_dev); 5508c2ecf20Sopenharmony_ci efx_device_attach_if_not_resetting(vf->efx); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cifail: 5568c2ecf20Sopenharmony_ci eth_zero_addr(vf->mac); 5578c2ecf20Sopenharmony_ci return rc; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ciint efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan, 5618c2ecf20Sopenharmony_ci u8 qos) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 5648c2ecf20Sopenharmony_ci struct ef10_vf *vf; 5658c2ecf20Sopenharmony_ci u16 new_vlan; 5668c2ecf20Sopenharmony_ci int rc = 0, rc2 = 0; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (vf_i >= efx->vf_count) 5698c2ecf20Sopenharmony_ci return -EINVAL; 5708c2ecf20Sopenharmony_ci if (qos != 0) 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci vf = nic_data->vf + vf_i; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci new_vlan = (vlan == 0) ? EFX_EF10_NO_VLAN : vlan; 5768c2ecf20Sopenharmony_ci if (new_vlan == vf->vlan) 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (vf->efx) { 5808c2ecf20Sopenharmony_ci efx_device_detach_sync(vf->efx); 5818c2ecf20Sopenharmony_ci efx_net_stop(vf->efx->net_dev); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci mutex_lock(&vf->efx->mac_lock); 5848c2ecf20Sopenharmony_ci down_write(&vf->efx->filter_sem); 5858c2ecf20Sopenharmony_ci vf->efx->type->filter_table_remove(vf->efx); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED); 5888c2ecf20Sopenharmony_ci if (rc) 5898c2ecf20Sopenharmony_ci goto restore_filters; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (vf->vport_assigned) { 5938c2ecf20Sopenharmony_ci rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i); 5948c2ecf20Sopenharmony_ci if (rc) { 5958c2ecf20Sopenharmony_ci netif_warn(efx, drv, efx->net_dev, 5968c2ecf20Sopenharmony_ci "Failed to change vlan on VF %d.\n", vf_i); 5978c2ecf20Sopenharmony_ci netif_warn(efx, drv, efx->net_dev, 5988c2ecf20Sopenharmony_ci "This is likely because the VF is bound to a driver in a VM.\n"); 5998c2ecf20Sopenharmony_ci netif_warn(efx, drv, efx->net_dev, 6008c2ecf20Sopenharmony_ci "Please unload the driver in the VM.\n"); 6018c2ecf20Sopenharmony_ci goto restore_vadaptor; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci vf->vport_assigned = 0; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(vf->mac)) { 6078c2ecf20Sopenharmony_ci rc = efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac); 6088c2ecf20Sopenharmony_ci if (rc) 6098c2ecf20Sopenharmony_ci goto restore_evb_port; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (vf->vport_id) { 6138c2ecf20Sopenharmony_ci rc = efx_ef10_vport_free(efx, vf->vport_id); 6148c2ecf20Sopenharmony_ci if (rc) 6158c2ecf20Sopenharmony_ci goto restore_mac; 6168c2ecf20Sopenharmony_ci vf->vport_id = 0; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Do the actual vlan change */ 6208c2ecf20Sopenharmony_ci vf->vlan = new_vlan; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* Restore everything in reverse order */ 6238c2ecf20Sopenharmony_ci rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, 6248c2ecf20Sopenharmony_ci MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, 6258c2ecf20Sopenharmony_ci vf->vlan, &vf->vport_id); 6268c2ecf20Sopenharmony_ci if (rc) 6278c2ecf20Sopenharmony_ci goto reset_nic_up_write; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cirestore_mac: 6308c2ecf20Sopenharmony_ci if (!is_zero_ether_addr(vf->mac)) { 6318c2ecf20Sopenharmony_ci rc2 = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac); 6328c2ecf20Sopenharmony_ci if (rc2) { 6338c2ecf20Sopenharmony_ci eth_zero_addr(vf->mac); 6348c2ecf20Sopenharmony_ci goto reset_nic_up_write; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cirestore_evb_port: 6398c2ecf20Sopenharmony_ci rc2 = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i); 6408c2ecf20Sopenharmony_ci if (rc2) 6418c2ecf20Sopenharmony_ci goto reset_nic_up_write; 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci vf->vport_assigned = 1; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cirestore_vadaptor: 6468c2ecf20Sopenharmony_ci if (vf->efx) { 6478c2ecf20Sopenharmony_ci rc2 = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED); 6488c2ecf20Sopenharmony_ci if (rc2) 6498c2ecf20Sopenharmony_ci goto reset_nic_up_write; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cirestore_filters: 6538c2ecf20Sopenharmony_ci if (vf->efx) { 6548c2ecf20Sopenharmony_ci rc2 = vf->efx->type->filter_table_probe(vf->efx); 6558c2ecf20Sopenharmony_ci if (rc2) 6568c2ecf20Sopenharmony_ci goto reset_nic_up_write; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci up_write(&vf->efx->filter_sem); 6598c2ecf20Sopenharmony_ci mutex_unlock(&vf->efx->mac_lock); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci rc2 = efx_net_open(vf->efx->net_dev); 6628c2ecf20Sopenharmony_ci if (rc2) 6638c2ecf20Sopenharmony_ci goto reset_nic; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci efx_device_attach_if_not_resetting(vf->efx); 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci return rc; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cireset_nic_up_write: 6708c2ecf20Sopenharmony_ci if (vf->efx) { 6718c2ecf20Sopenharmony_ci up_write(&vf->efx->filter_sem); 6728c2ecf20Sopenharmony_ci mutex_unlock(&vf->efx->mac_lock); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_cireset_nic: 6758c2ecf20Sopenharmony_ci if (vf->efx) { 6768c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 6778c2ecf20Sopenharmony_ci "Failed to restore VF - scheduling reset.\n"); 6788c2ecf20Sopenharmony_ci efx_schedule_reset(vf->efx, RESET_TYPE_DATAPATH); 6798c2ecf20Sopenharmony_ci } else { 6808c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 6818c2ecf20Sopenharmony_ci "Failed to restore the VF and cannot reset the VF " 6828c2ecf20Sopenharmony_ci "- VF is not functional.\n"); 6838c2ecf20Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 6848c2ecf20Sopenharmony_ci "Please reload the driver attached to the VF.\n"); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return rc ? rc : rc2; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic int efx_ef10_sriov_set_privilege_mask(struct efx_nic *efx, int vf_i, 6918c2ecf20Sopenharmony_ci u32 mask, u32 value) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(pm_outbuf, MC_CMD_PRIVILEGE_MASK_OUT_LEN); 6948c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(pm_inbuf, MC_CMD_PRIVILEGE_MASK_IN_LEN); 6958c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 6968c2ecf20Sopenharmony_ci u32 old_mask, new_mask; 6978c2ecf20Sopenharmony_ci size_t outlen; 6988c2ecf20Sopenharmony_ci int rc; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci EFX_WARN_ON_PARANOID((value & ~mask) != 0); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* Get privilege mask */ 7038c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_2(pm_inbuf, PRIVILEGE_MASK_IN_FUNCTION, 7048c2ecf20Sopenharmony_ci PRIVILEGE_MASK_IN_FUNCTION_PF, nic_data->pf_index, 7058c2ecf20Sopenharmony_ci PRIVILEGE_MASK_IN_FUNCTION_VF, vf_i); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK, 7088c2ecf20Sopenharmony_ci pm_inbuf, sizeof(pm_inbuf), 7098c2ecf20Sopenharmony_ci pm_outbuf, sizeof(pm_outbuf), &outlen); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (rc != 0) 7128c2ecf20Sopenharmony_ci return rc; 7138c2ecf20Sopenharmony_ci if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN) 7148c2ecf20Sopenharmony_ci return -EIO; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci old_mask = MCDI_DWORD(pm_outbuf, PRIVILEGE_MASK_OUT_OLD_MASK); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci new_mask = old_mask & ~mask; 7198c2ecf20Sopenharmony_ci new_mask |= value; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (new_mask == old_mask) 7228c2ecf20Sopenharmony_ci return 0; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci new_mask |= MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Set privilege mask */ 7278c2ecf20Sopenharmony_ci MCDI_SET_DWORD(pm_inbuf, PRIVILEGE_MASK_IN_NEW_MASK, new_mask); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK, 7308c2ecf20Sopenharmony_ci pm_inbuf, sizeof(pm_inbuf), 7318c2ecf20Sopenharmony_ci pm_outbuf, sizeof(pm_outbuf), &outlen); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (rc != 0) 7348c2ecf20Sopenharmony_ci return rc; 7358c2ecf20Sopenharmony_ci if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN) 7368c2ecf20Sopenharmony_ci return -EIO; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciint efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Can't enable spoofchk if firmware doesn't support it. */ 7468c2ecf20Sopenharmony_ci if (!(nic_data->datapath_caps & 7478c2ecf20Sopenharmony_ci BIT(MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_LBN)) && 7488c2ecf20Sopenharmony_ci spoofchk) 7498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return efx_ef10_sriov_set_privilege_mask(efx, vf_i, 7528c2ecf20Sopenharmony_ci MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX, 7538c2ecf20Sopenharmony_ci spoofchk ? 0 : MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ciint efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i, 7578c2ecf20Sopenharmony_ci int link_state) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN); 7608c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci BUILD_BUG_ON(IFLA_VF_LINK_STATE_AUTO != 7638c2ecf20Sopenharmony_ci MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO); 7648c2ecf20Sopenharmony_ci BUILD_BUG_ON(IFLA_VF_LINK_STATE_ENABLE != 7658c2ecf20Sopenharmony_ci MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP); 7668c2ecf20Sopenharmony_ci BUILD_BUG_ON(IFLA_VF_LINK_STATE_DISABLE != 7678c2ecf20Sopenharmony_ci MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN); 7688c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION, 7698c2ecf20Sopenharmony_ci LINK_STATE_MODE_IN_FUNCTION_PF, 7708c2ecf20Sopenharmony_ci nic_data->pf_index, 7718c2ecf20Sopenharmony_ci LINK_STATE_MODE_IN_FUNCTION_VF, vf_i); 7728c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, link_state); 7738c2ecf20Sopenharmony_ci return efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf), 7748c2ecf20Sopenharmony_ci NULL, 0, NULL); /* don't care what old mode was */ 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ciint efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i, 7788c2ecf20Sopenharmony_ci struct ifla_vf_info *ivf) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN); 7818c2ecf20Sopenharmony_ci MCDI_DECLARE_BUF(outbuf, MC_CMD_LINK_STATE_MODE_OUT_LEN); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci struct efx_ef10_nic_data *nic_data = efx->nic_data; 7848c2ecf20Sopenharmony_ci struct ef10_vf *vf; 7858c2ecf20Sopenharmony_ci size_t outlen; 7868c2ecf20Sopenharmony_ci int rc; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (vf_i >= efx->vf_count) 7898c2ecf20Sopenharmony_ci return -EINVAL; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (!nic_data->vf) 7928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci vf = nic_data->vf + vf_i; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci ivf->vf = vf_i; 7978c2ecf20Sopenharmony_ci ivf->min_tx_rate = 0; 7988c2ecf20Sopenharmony_ci ivf->max_tx_rate = 0; 7998c2ecf20Sopenharmony_ci ether_addr_copy(ivf->mac, vf->mac); 8008c2ecf20Sopenharmony_ci ivf->vlan = (vf->vlan == EFX_EF10_NO_VLAN) ? 0 : vf->vlan; 8018c2ecf20Sopenharmony_ci ivf->qos = 0; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION, 8048c2ecf20Sopenharmony_ci LINK_STATE_MODE_IN_FUNCTION_PF, 8058c2ecf20Sopenharmony_ci nic_data->pf_index, 8068c2ecf20Sopenharmony_ci LINK_STATE_MODE_IN_FUNCTION_VF, vf_i); 8078c2ecf20Sopenharmony_ci MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, 8088c2ecf20Sopenharmony_ci MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE); 8098c2ecf20Sopenharmony_ci rc = efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf), 8108c2ecf20Sopenharmony_ci outbuf, sizeof(outbuf), &outlen); 8118c2ecf20Sopenharmony_ci if (rc) 8128c2ecf20Sopenharmony_ci return rc; 8138c2ecf20Sopenharmony_ci if (outlen < MC_CMD_LINK_STATE_MODE_OUT_LEN) 8148c2ecf20Sopenharmony_ci return -EIO; 8158c2ecf20Sopenharmony_ci ivf->linkstate = MCDI_DWORD(outbuf, LINK_STATE_MODE_OUT_OLD_MODE); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return 0; 8188c2ecf20Sopenharmony_ci} 819