diff options
author | Daniel Pieczko <dpieczko@solarflare.com> | 2015-05-06 02:57:34 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-09 23:16:47 +0300 |
commit | 6d8aaaf6f7980af1d228061ec08f6411e6bb2344 (patch) | |
tree | 28d09c82ceb3070be97aa71846313f9ba2644042 /drivers/net/ethernet/sfc/ef10_sriov.c | |
parent | 45b2449e3f7d870bdd06c6a8557e8d95d59f8737 (diff) | |
download | linux-6d8aaaf6f7980af1d228061ec08f6411e6bb2344.tar.xz |
sfc: create VEB vswitch and vport above default firmware setup
Adds functions to allocate and free vswitches and vports; vadaptors
are automatically allocated and freed when TX/RX queues are
initialised and finalised. This vswitching structure is only created
if the firmware supports it, so a check that full-featured firmware
is running is performed first.
If the MC resets, the vswitching infrastructure will need to be
recreated, so mark the "must_probe_vswitching" flag when an MC reboot
is detected.
Don't try to create a vswitch if vf-count=0
This allocation of vswitches and vports does not currently support
configuring VLAN tags, but that can be added in a future change.
Signed-off-by: Shradha Shah <sshah@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/sfc/ef10_sriov.c')
-rw-r--r-- | drivers/net/ethernet/sfc/ef10_sriov.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c index 63d7b0d9deb1..2aba7b7234ea 100644 --- a/drivers/net/ethernet/sfc/ef10_sriov.c +++ b/drivers/net/ethernet/sfc/ef10_sriov.c @@ -45,3 +45,124 @@ int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) else return efx_ef10_pci_sriov_enable(efx, num_vfs); } + +static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, + unsigned int vswitch_type) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN); + + MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id); + MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type); + MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 0); + MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS, + VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0); + + return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_FREE_IN_LEN); + + MCDI_SET_DWORD(inbuf, VSWITCH_FREE_IN_UPSTREAM_PORT_ID, port_id); + + return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_FREE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +static int efx_ef10_vport_alloc(struct efx_nic *efx, + unsigned int port_id_in, + unsigned int vport_type, + unsigned int *port_id_out) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_ALLOC_OUT_LEN); + size_t outlen; + int rc; + + EFX_WARN_ON_PARANOID(!port_id_out); + + MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in); + MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type); + MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS, 0); + MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS, + VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + if (outlen < MC_CMD_VPORT_ALLOC_OUT_LEN) + return -EIO; + + *port_id_out = MCDI_DWORD(outbuf, VPORT_ALLOC_OUT_VPORT_ID); + return 0; +} + +static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_FREE_IN_LEN); + + MCDI_SET_DWORD(inbuf, VPORT_FREE_IN_VPORT_ID, port_id); + + return efx_mcdi_rpc(efx, MC_CMD_VPORT_FREE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + +/* On top of the default firmware vswitch setup, create a VEB vswitch and + * expansion vport for use by this function. + */ +int efx_ef10_vswitching_probe(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc; + + if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0) + return 0; /* vswitch not needed as we have no VFs */ + + rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED, + MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB); + if (rc) + goto fail1; + + rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, + MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, + &nic_data->vport_id); + if (rc) + goto fail2; + + return 0; +fail2: + efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED); +fail1: + return rc; +} + +int efx_ef10_vswitching_restore(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + int rc; + + if (!nic_data->must_probe_vswitching) + return 0; + + rc = efx_ef10_vswitching_probe(efx); + + if (!rc) + nic_data->must_probe_vswitching = false; + return rc; +} + +void efx_ef10_vswitching_remove(struct efx_nic *efx) +{ + struct efx_ef10_nic_data *nic_data = efx->nic_data; + + if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED) + return; /* No vswitch was ever created */ + + efx_ef10_vport_free(efx, nic_data->vport_id); + nic_data->vport_id = EVB_PORT_ID_ASSIGNED; + + efx_ef10_vswitch_free(efx, nic_data->vport_id); +} |