sfc: create VEB vswitch and vport above default firmware setup
authorDaniel Pieczko <dpieczko@solarflare.com>
Tue, 5 May 2015 23:57:34 +0000 (00:57 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sat, 9 May 2015 20:16:47 +0000 (16:16 -0400)
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>
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef10_sriov.c
drivers/net/ethernet/sfc/ef10_sriov.h
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/nic.h
drivers/net/ethernet/sfc/siena.c

index 8db717e..91a5896 100644 (file)
@@ -1133,6 +1133,10 @@ static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx)
        /* All our allocations have been reset */
        efx_ef10_reset_mc_allocations(efx);
 
+       /* Driver-created vswitches and vports must be re-created */
+       nic_data->must_probe_vswitching = true;
+       nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
+
        /* The datapath firmware might have been changed */
        nic_data->must_check_datapath_caps = true;
 
@@ -3715,6 +3719,9 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
        .sriov_set_vf_vlan = efx_ef10_sriov_set_vf_vlan,
        .sriov_set_vf_spoofchk = efx_ef10_sriov_set_vf_spoofchk,
        .sriov_get_vf_config = efx_ef10_sriov_get_vf_config,
+       .vswitching_probe = efx_ef10_vswitching_probe,
+       .vswitching_restore = efx_ef10_vswitching_restore,
+       .vswitching_remove = efx_ef10_vswitching_remove,
 #endif
 
        .revision = EFX_REV_HUNT_A0,
index 63d7b0d..2aba7b7 100644 (file)
@@ -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);
+}
index 5f26d1b..676b00c 100644 (file)
@@ -53,4 +53,8 @@ static inline int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf,
        return -EOPNOTSUPP;
 }
 
+int efx_ef10_vswitching_probe(struct efx_nic *efx);
+int efx_ef10_vswitching_restore(struct efx_nic *efx);
+void efx_ef10_vswitching_remove(struct efx_nic *efx);
+
 #endif /* EF10_SRIOV_H */
Simple merge
Simple merge
Simple merge
Simple merge