| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /**************************************************************************** |
|---|
| 2 | 3 | * Driver for Solarflare network controllers and boards |
|---|
| 3 | 4 | * Copyright 2015 Solarflare Communications Inc. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms of the GNU General Public License version 2 as published |
|---|
| 7 | | - * by the Free Software Foundation, incorporated herein by reference. |
|---|
| 8 | 5 | */ |
|---|
| 9 | 6 | #include <linux/etherdevice.h> |
|---|
| 10 | 7 | #include <linux/pci.h> |
|---|
| .. | .. |
|---|
| 235 | 232 | |
|---|
| 236 | 233 | static int efx_ef10_vadaptor_alloc_set_features(struct efx_nic *efx) |
|---|
| 237 | 234 | { |
|---|
| 238 | | - struct efx_ef10_nic_data *nic_data = efx->nic_data; |
|---|
| 239 | 235 | u32 port_flags; |
|---|
| 240 | 236 | int rc; |
|---|
| 241 | 237 | |
|---|
| 242 | | - rc = efx_ef10_vadaptor_alloc(efx, nic_data->vport_id); |
|---|
| 238 | + rc = efx_ef10_vadaptor_alloc(efx, efx->vport_id); |
|---|
| 243 | 239 | if (rc) |
|---|
| 244 | 240 | goto fail_vadaptor_alloc; |
|---|
| 245 | 241 | |
|---|
| 246 | | - rc = efx_ef10_vadaptor_query(efx, nic_data->vport_id, |
|---|
| 242 | + rc = efx_ef10_vadaptor_query(efx, efx->vport_id, |
|---|
| 247 | 243 | &port_flags, NULL, NULL); |
|---|
| 248 | 244 | if (rc) |
|---|
| 249 | 245 | goto fail_vadaptor_query; |
|---|
| .. | .. |
|---|
| 284 | 280 | |
|---|
| 285 | 281 | rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, |
|---|
| 286 | 282 | MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, |
|---|
| 287 | | - EFX_EF10_NO_VLAN, &nic_data->vport_id); |
|---|
| 283 | + EFX_EF10_NO_VLAN, &efx->vport_id); |
|---|
| 288 | 284 | if (rc) |
|---|
| 289 | 285 | goto fail2; |
|---|
| 290 | 286 | |
|---|
| 291 | | - rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, net_dev->dev_addr); |
|---|
| 287 | + rc = efx_ef10_vport_add_mac(efx, efx->vport_id, net_dev->dev_addr); |
|---|
| 292 | 288 | if (rc) |
|---|
| 293 | 289 | goto fail3; |
|---|
| 294 | 290 | ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr); |
|---|
| .. | .. |
|---|
| 299 | 295 | |
|---|
| 300 | 296 | return 0; |
|---|
| 301 | 297 | fail4: |
|---|
| 302 | | - efx_ef10_vport_del_mac(efx, nic_data->vport_id, nic_data->vport_mac); |
|---|
| 298 | + efx_ef10_vport_del_mac(efx, efx->vport_id, nic_data->vport_mac); |
|---|
| 303 | 299 | eth_zero_addr(nic_data->vport_mac); |
|---|
| 304 | 300 | fail3: |
|---|
| 305 | | - efx_ef10_vport_free(efx, nic_data->vport_id); |
|---|
| 306 | | - nic_data->vport_id = EVB_PORT_ID_ASSIGNED; |
|---|
| 301 | + efx_ef10_vport_free(efx, efx->vport_id); |
|---|
| 302 | + efx->vport_id = EVB_PORT_ID_ASSIGNED; |
|---|
| 307 | 303 | fail2: |
|---|
| 308 | 304 | efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED); |
|---|
| 309 | 305 | fail1: |
|---|
| .. | .. |
|---|
| 358 | 354 | |
|---|
| 359 | 355 | efx_ef10_sriov_free_vf_vswitching(efx); |
|---|
| 360 | 356 | |
|---|
| 361 | | - efx_ef10_vadaptor_free(efx, nic_data->vport_id); |
|---|
| 357 | + efx_ef10_vadaptor_free(efx, efx->vport_id); |
|---|
| 362 | 358 | |
|---|
| 363 | | - if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED) |
|---|
| 359 | + if (efx->vport_id == EVB_PORT_ID_ASSIGNED) |
|---|
| 364 | 360 | return; /* No vswitch was ever created */ |
|---|
| 365 | 361 | |
|---|
| 366 | 362 | if (!is_zero_ether_addr(nic_data->vport_mac)) { |
|---|
| 367 | | - efx_ef10_vport_del_mac(efx, nic_data->vport_id, |
|---|
| 363 | + efx_ef10_vport_del_mac(efx, efx->vport_id, |
|---|
| 368 | 364 | efx->net_dev->dev_addr); |
|---|
| 369 | 365 | eth_zero_addr(nic_data->vport_mac); |
|---|
| 370 | 366 | } |
|---|
| 371 | | - efx_ef10_vport_free(efx, nic_data->vport_id); |
|---|
| 372 | | - nic_data->vport_id = EVB_PORT_ID_ASSIGNED; |
|---|
| 367 | + efx_ef10_vport_free(efx, efx->vport_id); |
|---|
| 368 | + efx->vport_id = EVB_PORT_ID_ASSIGNED; |
|---|
| 373 | 369 | |
|---|
| 374 | 370 | /* Only free the vswitch if no VFs are assigned */ |
|---|
| 375 | 371 | if (!pci_vfs_assigned(efx->pci_dev)) |
|---|
| 376 | | - efx_ef10_vswitch_free(efx, nic_data->vport_id); |
|---|
| 372 | + efx_ef10_vswitch_free(efx, efx->vport_id); |
|---|
| 377 | 373 | } |
|---|
| 378 | 374 | |
|---|
| 379 | 375 | void efx_ef10_vswitching_remove_vf(struct efx_nic *efx) |
|---|
| .. | .. |
|---|
| 415 | 411 | static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force) |
|---|
| 416 | 412 | { |
|---|
| 417 | 413 | struct pci_dev *dev = efx->pci_dev; |
|---|
| 414 | + struct efx_ef10_nic_data *nic_data = efx->nic_data; |
|---|
| 418 | 415 | unsigned int vfs_assigned = pci_vfs_assigned(dev); |
|---|
| 419 | | - int rc = 0; |
|---|
| 416 | + int i, rc = 0; |
|---|
| 420 | 417 | |
|---|
| 421 | 418 | if (vfs_assigned && !force) { |
|---|
| 422 | 419 | netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; " |
|---|
| .. | .. |
|---|
| 424 | 421 | return -EBUSY; |
|---|
| 425 | 422 | } |
|---|
| 426 | 423 | |
|---|
| 427 | | - if (!vfs_assigned) |
|---|
| 424 | + if (!vfs_assigned) { |
|---|
| 425 | + for (i = 0; i < efx->vf_count; i++) |
|---|
| 426 | + nic_data->vf[i].pci_dev = NULL; |
|---|
| 428 | 427 | pci_disable_sriov(dev); |
|---|
| 429 | | - else |
|---|
| 428 | + } else { |
|---|
| 430 | 429 | rc = -EBUSY; |
|---|
| 430 | + } |
|---|
| 431 | 431 | |
|---|
| 432 | 432 | efx_ef10_sriov_free_vf_vswitching(efx); |
|---|
| 433 | 433 | efx->vf_count = 0; |
|---|
| .. | .. |
|---|
| 524 | 524 | |
|---|
| 525 | 525 | if (!is_zero_ether_addr(mac)) { |
|---|
| 526 | 526 | rc = efx_ef10_vport_add_mac(efx, vf->vport_id, mac); |
|---|
| 527 | | - if (rc) { |
|---|
| 528 | | - eth_zero_addr(vf->mac); |
|---|
| 527 | + if (rc) |
|---|
| 529 | 528 | goto fail; |
|---|
| 530 | | - } |
|---|
| 529 | + |
|---|
| 531 | 530 | if (vf->efx) |
|---|
| 532 | 531 | ether_addr_copy(vf->efx->net_dev->dev_addr, mac); |
|---|
| 533 | 532 | } |
|---|
| .. | .. |
|---|
| 688 | 687 | return rc ? rc : rc2; |
|---|
| 689 | 688 | } |
|---|
| 690 | 689 | |
|---|
| 691 | | -int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, |
|---|
| 692 | | - bool spoofchk) |
|---|
| 690 | +static int efx_ef10_sriov_set_privilege_mask(struct efx_nic *efx, int vf_i, |
|---|
| 691 | + u32 mask, u32 value) |
|---|
| 693 | 692 | { |
|---|
| 694 | | - return spoofchk ? -EOPNOTSUPP : 0; |
|---|
| 693 | + MCDI_DECLARE_BUF(pm_outbuf, MC_CMD_PRIVILEGE_MASK_OUT_LEN); |
|---|
| 694 | + MCDI_DECLARE_BUF(pm_inbuf, MC_CMD_PRIVILEGE_MASK_IN_LEN); |
|---|
| 695 | + struct efx_ef10_nic_data *nic_data = efx->nic_data; |
|---|
| 696 | + u32 old_mask, new_mask; |
|---|
| 697 | + size_t outlen; |
|---|
| 698 | + int rc; |
|---|
| 699 | + |
|---|
| 700 | + EFX_WARN_ON_PARANOID((value & ~mask) != 0); |
|---|
| 701 | + |
|---|
| 702 | + /* Get privilege mask */ |
|---|
| 703 | + MCDI_POPULATE_DWORD_2(pm_inbuf, PRIVILEGE_MASK_IN_FUNCTION, |
|---|
| 704 | + PRIVILEGE_MASK_IN_FUNCTION_PF, nic_data->pf_index, |
|---|
| 705 | + PRIVILEGE_MASK_IN_FUNCTION_VF, vf_i); |
|---|
| 706 | + |
|---|
| 707 | + rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK, |
|---|
| 708 | + pm_inbuf, sizeof(pm_inbuf), |
|---|
| 709 | + pm_outbuf, sizeof(pm_outbuf), &outlen); |
|---|
| 710 | + |
|---|
| 711 | + if (rc != 0) |
|---|
| 712 | + return rc; |
|---|
| 713 | + if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN) |
|---|
| 714 | + return -EIO; |
|---|
| 715 | + |
|---|
| 716 | + old_mask = MCDI_DWORD(pm_outbuf, PRIVILEGE_MASK_OUT_OLD_MASK); |
|---|
| 717 | + |
|---|
| 718 | + new_mask = old_mask & ~mask; |
|---|
| 719 | + new_mask |= value; |
|---|
| 720 | + |
|---|
| 721 | + if (new_mask == old_mask) |
|---|
| 722 | + return 0; |
|---|
| 723 | + |
|---|
| 724 | + new_mask |= MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE; |
|---|
| 725 | + |
|---|
| 726 | + /* Set privilege mask */ |
|---|
| 727 | + MCDI_SET_DWORD(pm_inbuf, PRIVILEGE_MASK_IN_NEW_MASK, new_mask); |
|---|
| 728 | + |
|---|
| 729 | + rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK, |
|---|
| 730 | + pm_inbuf, sizeof(pm_inbuf), |
|---|
| 731 | + pm_outbuf, sizeof(pm_outbuf), &outlen); |
|---|
| 732 | + |
|---|
| 733 | + if (rc != 0) |
|---|
| 734 | + return rc; |
|---|
| 735 | + if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN) |
|---|
| 736 | + return -EIO; |
|---|
| 737 | + |
|---|
| 738 | + return 0; |
|---|
| 739 | +} |
|---|
| 740 | + |
|---|
| 741 | +int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk) |
|---|
| 742 | +{ |
|---|
| 743 | + struct efx_ef10_nic_data *nic_data = efx->nic_data; |
|---|
| 744 | + |
|---|
| 745 | + /* Can't enable spoofchk if firmware doesn't support it. */ |
|---|
| 746 | + if (!(nic_data->datapath_caps & |
|---|
| 747 | + BIT(MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_LBN)) && |
|---|
| 748 | + spoofchk) |
|---|
| 749 | + return -EOPNOTSUPP; |
|---|
| 750 | + |
|---|
| 751 | + return efx_ef10_sriov_set_privilege_mask(efx, vf_i, |
|---|
| 752 | + MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX, |
|---|
| 753 | + spoofchk ? 0 : MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX); |
|---|
| 695 | 754 | } |
|---|
| 696 | 755 | |
|---|
| 697 | 756 | int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i, |
|---|