1 /****************************************************************************
2 * Driver for Solarflare network controllers and boards
3 * Copyright 2015 Solarflare Communications Inc.
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.
10 #include <linux/module.h>
11 #include "net_driver.h"
12 #include "ef10_sriov.h"
15 #include "mcdi_pcol.h"
17 static int efx_ef10_pci_sriov_enable(struct efx_nic
*efx
, int num_vfs
)
20 struct pci_dev
*dev
= efx
->pci_dev
;
22 efx
->vf_count
= num_vfs
;
23 rc
= pci_enable_sriov(dev
, num_vfs
);
26 netif_err(efx
, probe
, efx
->net_dev
,
27 "Failed to enable SRIOV VFs\n");
32 static int efx_ef10_pci_sriov_disable(struct efx_nic
*efx
)
34 struct pci_dev
*dev
= efx
->pci_dev
;
37 pci_disable_sriov(dev
);
41 int efx_ef10_sriov_configure(struct efx_nic
*efx
, int num_vfs
)
44 return efx_ef10_pci_sriov_disable(efx
);
46 return efx_ef10_pci_sriov_enable(efx
, num_vfs
);
49 int efx_ef10_sriov_init(struct efx_nic
*efx
)
54 void efx_ef10_sriov_fini(struct efx_nic
*efx
)
58 rc
= efx_ef10_pci_sriov_disable(efx
);
60 netif_dbg(efx
, drv
, efx
->net_dev
,
61 "Disabling SRIOV was not successful rc=%d\n", rc
);
63 netif_dbg(efx
, drv
, efx
->net_dev
, "SRIOV disabled\n");
66 static int efx_ef10_vswitch_alloc(struct efx_nic
*efx
, unsigned int port_id
,
67 unsigned int vswitch_type
)
69 MCDI_DECLARE_BUF(inbuf
, MC_CMD_VSWITCH_ALLOC_IN_LEN
);
71 MCDI_SET_DWORD(inbuf
, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID
, port_id
);
72 MCDI_SET_DWORD(inbuf
, VSWITCH_ALLOC_IN_TYPE
, vswitch_type
);
73 MCDI_SET_DWORD(inbuf
, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS
, 0);
74 MCDI_POPULATE_DWORD_1(inbuf
, VSWITCH_ALLOC_IN_FLAGS
,
75 VSWITCH_ALLOC_IN_FLAG_AUTO_PORT
, 0);
77 return efx_mcdi_rpc(efx
, MC_CMD_VSWITCH_ALLOC
, inbuf
, sizeof(inbuf
),
81 static int efx_ef10_vswitch_free(struct efx_nic
*efx
, unsigned int port_id
)
83 MCDI_DECLARE_BUF(inbuf
, MC_CMD_VSWITCH_FREE_IN_LEN
);
85 MCDI_SET_DWORD(inbuf
, VSWITCH_FREE_IN_UPSTREAM_PORT_ID
, port_id
);
87 return efx_mcdi_rpc(efx
, MC_CMD_VSWITCH_FREE
, inbuf
, sizeof(inbuf
),
91 static int efx_ef10_vport_alloc(struct efx_nic
*efx
,
92 unsigned int port_id_in
,
93 unsigned int vport_type
,
94 unsigned int *port_id_out
)
96 MCDI_DECLARE_BUF(inbuf
, MC_CMD_VPORT_ALLOC_IN_LEN
);
97 MCDI_DECLARE_BUF(outbuf
, MC_CMD_VPORT_ALLOC_OUT_LEN
);
101 EFX_WARN_ON_PARANOID(!port_id_out
);
103 MCDI_SET_DWORD(inbuf
, VPORT_ALLOC_IN_UPSTREAM_PORT_ID
, port_id_in
);
104 MCDI_SET_DWORD(inbuf
, VPORT_ALLOC_IN_TYPE
, vport_type
);
105 MCDI_SET_DWORD(inbuf
, VPORT_ALLOC_IN_NUM_VLAN_TAGS
, 0);
106 MCDI_POPULATE_DWORD_1(inbuf
, VPORT_ALLOC_IN_FLAGS
,
107 VPORT_ALLOC_IN_FLAG_AUTO_PORT
, 0);
109 rc
= efx_mcdi_rpc(efx
, MC_CMD_VPORT_ALLOC
, inbuf
, sizeof(inbuf
),
110 outbuf
, sizeof(outbuf
), &outlen
);
113 if (outlen
< MC_CMD_VPORT_ALLOC_OUT_LEN
)
116 *port_id_out
= MCDI_DWORD(outbuf
, VPORT_ALLOC_OUT_VPORT_ID
);
120 static int efx_ef10_vport_free(struct efx_nic
*efx
, unsigned int port_id
)
122 MCDI_DECLARE_BUF(inbuf
, MC_CMD_VPORT_FREE_IN_LEN
);
124 MCDI_SET_DWORD(inbuf
, VPORT_FREE_IN_VPORT_ID
, port_id
);
126 return efx_mcdi_rpc(efx
, MC_CMD_VPORT_FREE
, inbuf
, sizeof(inbuf
),
130 /* On top of the default firmware vswitch setup, create a VEB vswitch and
131 * expansion vport for use by this function.
133 int efx_ef10_vswitching_probe(struct efx_nic
*efx
)
135 struct efx_ef10_nic_data
*nic_data
= efx
->nic_data
;
138 if (pci_sriov_get_totalvfs(efx
->pci_dev
) <= 0)
139 return 0; /* vswitch not needed as we have no VFs */
141 rc
= efx_ef10_vswitch_alloc(efx
, EVB_PORT_ID_ASSIGNED
,
142 MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB
);
146 rc
= efx_ef10_vport_alloc(efx
, EVB_PORT_ID_ASSIGNED
,
147 MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL
,
148 &nic_data
->vport_id
);
154 efx_ef10_vswitch_free(efx
, EVB_PORT_ID_ASSIGNED
);
159 int efx_ef10_vswitching_restore(struct efx_nic
*efx
)
161 struct efx_ef10_nic_data
*nic_data
= efx
->nic_data
;
164 if (!nic_data
->must_probe_vswitching
)
167 rc
= efx_ef10_vswitching_probe(efx
);
170 nic_data
->must_probe_vswitching
= false;
174 void efx_ef10_vswitching_remove(struct efx_nic
*efx
)
176 struct efx_ef10_nic_data
*nic_data
= efx
->nic_data
;
178 if (nic_data
->vport_id
== EVB_PORT_ID_ASSIGNED
)
179 return; /* No vswitch was ever created */
181 efx_ef10_vport_free(efx
, nic_data
->vport_id
);
182 nic_data
->vport_id
= EVB_PORT_ID_ASSIGNED
;
184 efx_ef10_vswitch_free(efx
, nic_data
->vport_id
);