Skip to content

Commit 3c5eb87

Browse files
sshah-solarflaredavem330
authored andcommitted
sfc: create vports for VFs and assign random MAC addresses
The parent PF creates vports for all its child VFs and adds MAC addresses to these. When the VF driver loads, it can make an MCDI call to get the MAC address that the parent PF assigned it. The parent PF also assigns a mac address to its own vport because implicit creation of a vAdaptor will only work on evb ports with MAC addresses assigned. The vport MAC address needs to be stored in the PF's nic_data struct as it can later be changed on the vadaptor (and its net_dev struct). When removing a vport the original MAC address must be deleted. A new flag is needed in the VF data structure to identify whether a vport has been assigned to the VF. This is to determine whether it needs to be un-assigned before freeing the vport. Also, attempting to un-assign a vport which is not assigned will result in an EALREADY error. Signed-off-by: Shradha Shah <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 02246a7 commit 3c5eb87

File tree

3 files changed

+244
-37
lines changed

3 files changed

+244
-37
lines changed

drivers/net/ethernet/sfc/ef10_sriov.c

Lines changed: 225 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,43 @@
1414
#include "nic.h"
1515
#include "mcdi_pcol.h"
1616

17-
static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs)
17+
static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id,
18+
unsigned int vf_fn)
1819
{
19-
int rc = 0;
20-
struct pci_dev *dev = efx->pci_dev;
20+
MCDI_DECLARE_BUF(inbuf, MC_CMD_EVB_PORT_ASSIGN_IN_LEN);
21+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
2122

22-
efx->vf_count = num_vfs;
23-
rc = pci_enable_sriov(dev, num_vfs);
24-
if (rc) {
25-
efx->vf_count = 0;
26-
netif_err(efx, probe, efx->net_dev,
27-
"Failed to enable SRIOV VFs\n");
28-
}
29-
return rc;
23+
MCDI_SET_DWORD(inbuf, EVB_PORT_ASSIGN_IN_PORT_ID, port_id);
24+
MCDI_POPULATE_DWORD_2(inbuf, EVB_PORT_ASSIGN_IN_FUNCTION,
25+
EVB_PORT_ASSIGN_IN_PF, nic_data->pf_index,
26+
EVB_PORT_ASSIGN_IN_VF, vf_fn);
27+
28+
return efx_mcdi_rpc(efx, MC_CMD_EVB_PORT_ASSIGN, inbuf, sizeof(inbuf),
29+
NULL, 0, NULL);
3030
}
3131

32-
static int efx_ef10_pci_sriov_disable(struct efx_nic *efx)
32+
static int efx_ef10_vport_add_mac(struct efx_nic *efx,
33+
unsigned int port_id, u8 *mac)
3334
{
34-
struct pci_dev *dev = efx->pci_dev;
35+
MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN);
3536

36-
efx->vf_count = 0;
37-
pci_disable_sriov(dev);
38-
return 0;
39-
}
37+
MCDI_SET_DWORD(inbuf, VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID, port_id);
38+
ether_addr_copy(MCDI_PTR(inbuf, VPORT_ADD_MAC_ADDRESS_IN_MACADDR), mac);
4039

41-
int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
42-
{
43-
if (num_vfs == 0)
44-
return efx_ef10_pci_sriov_disable(efx);
45-
else
46-
return efx_ef10_pci_sriov_enable(efx, num_vfs);
40+
return efx_mcdi_rpc(efx, MC_CMD_VPORT_ADD_MAC_ADDRESS, inbuf,
41+
sizeof(inbuf), NULL, 0, NULL);
4742
}
4843

49-
int efx_ef10_sriov_init(struct efx_nic *efx)
44+
static int efx_ef10_vport_del_mac(struct efx_nic *efx,
45+
unsigned int port_id, u8 *mac)
5046
{
51-
return 0;
52-
}
47+
MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN);
5348

54-
void efx_ef10_sriov_fini(struct efx_nic *efx)
55-
{
56-
int rc;
49+
MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id);
50+
ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac);
5751

58-
rc = efx_ef10_pci_sriov_disable(efx);
59-
if (rc)
60-
netif_dbg(efx, drv, efx->net_dev,
61-
"Disabling SRIOV was not successful rc=%d\n", rc);
62-
else
63-
netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n");
52+
return efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf,
53+
sizeof(inbuf), NULL, 0, NULL);
6454
}
6555

6656
static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id,
@@ -127,12 +117,124 @@ static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id)
127117
NULL, 0, NULL);
128118
}
129119

120+
static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx)
121+
{
122+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
123+
int i;
124+
125+
if (!nic_data->vf)
126+
return;
127+
128+
for (i = 0; i < efx->vf_count; i++) {
129+
struct ef10_vf *vf = nic_data->vf + i;
130+
131+
if (vf->vport_assigned) {
132+
efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, i);
133+
vf->vport_assigned = 0;
134+
}
135+
136+
if (!is_zero_ether_addr(vf->mac)) {
137+
efx_ef10_vport_del_mac(efx, vf->vport_id, vf->mac);
138+
eth_zero_addr(vf->mac);
139+
}
140+
141+
if (vf->vport_id) {
142+
efx_ef10_vport_free(efx, vf->vport_id);
143+
vf->vport_id = 0;
144+
}
145+
}
146+
}
147+
148+
static void efx_ef10_sriov_free_vf_vswitching(struct efx_nic *efx)
149+
{
150+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
151+
152+
efx_ef10_sriov_free_vf_vports(efx);
153+
kfree(nic_data->vf);
154+
nic_data->vf = NULL;
155+
}
156+
157+
static int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx,
158+
unsigned int vf_i)
159+
{
160+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
161+
struct ef10_vf *vf = nic_data->vf + vf_i;
162+
int rc;
163+
164+
if (WARN_ON_ONCE(!nic_data->vf))
165+
return -EOPNOTSUPP;
166+
167+
rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED,
168+
MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL,
169+
&vf->vport_id);
170+
if (rc)
171+
return rc;
172+
173+
rc = efx_ef10_vport_add_mac(efx, vf->vport_id, vf->mac);
174+
if (rc) {
175+
eth_zero_addr(vf->mac);
176+
return rc;
177+
}
178+
179+
rc = efx_ef10_evb_port_assign(efx, vf->vport_id, vf_i);
180+
if (rc)
181+
return rc;
182+
183+
vf->vport_assigned = 1;
184+
return 0;
185+
}
186+
187+
static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx)
188+
{
189+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
190+
unsigned int i;
191+
int rc;
192+
193+
nic_data->vf = kcalloc(efx->vf_count, sizeof(struct ef10_vf),
194+
GFP_KERNEL);
195+
if (!nic_data->vf)
196+
return -ENOMEM;
197+
198+
for (i = 0; i < efx->vf_count; i++) {
199+
random_ether_addr(nic_data->vf[i].mac);
200+
201+
rc = efx_ef10_sriov_assign_vf_vport(efx, i);
202+
if (rc)
203+
goto fail;
204+
}
205+
206+
return 0;
207+
fail:
208+
efx_ef10_sriov_free_vf_vports(efx);
209+
kfree(nic_data->vf);
210+
nic_data->vf = NULL;
211+
return rc;
212+
}
213+
214+
static int efx_ef10_sriov_restore_vf_vswitching(struct efx_nic *efx)
215+
{
216+
unsigned int i;
217+
int rc;
218+
219+
for (i = 0; i < efx->vf_count; i++) {
220+
rc = efx_ef10_sriov_assign_vf_vport(efx, i);
221+
if (rc)
222+
goto fail;
223+
}
224+
225+
return 0;
226+
fail:
227+
efx_ef10_sriov_free_vf_vswitching(efx);
228+
return rc;
229+
}
230+
130231
/* On top of the default firmware vswitch setup, create a VEB vswitch and
131232
* expansion vport for use by this function.
132233
*/
133234
int efx_ef10_vswitching_probe(struct efx_nic *efx)
134235
{
135236
struct efx_ef10_nic_data *nic_data = efx->nic_data;
237+
struct net_device *net_dev = efx->net_dev;
136238
int rc;
137239

138240
if (pci_sriov_get_totalvfs(efx->pci_dev) <= 0)
@@ -149,7 +251,16 @@ int efx_ef10_vswitching_probe(struct efx_nic *efx)
149251
if (rc)
150252
goto fail2;
151253

254+
rc = efx_ef10_vport_add_mac(efx, nic_data->vport_id, net_dev->dev_addr);
255+
if (rc)
256+
goto fail3;
257+
258+
ether_addr_copy(nic_data->vport_mac, net_dev->dev_addr);
259+
152260
return 0;
261+
fail3:
262+
efx_ef10_vport_free(efx, nic_data->vport_id);
263+
nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
153264
fail2:
154265
efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED);
155266
fail1:
@@ -165,21 +276,98 @@ int efx_ef10_vswitching_restore(struct efx_nic *efx)
165276
return 0;
166277

167278
rc = efx_ef10_vswitching_probe(efx);
279+
if (rc)
280+
goto fail;
281+
282+
rc = efx_ef10_sriov_restore_vf_vswitching(efx);
283+
if (rc)
284+
goto fail;
168285

169-
if (!rc)
170-
nic_data->must_probe_vswitching = false;
286+
nic_data->must_probe_vswitching = false;
287+
fail:
171288
return rc;
172289
}
173290

174291
void efx_ef10_vswitching_remove(struct efx_nic *efx)
175292
{
176293
struct efx_ef10_nic_data *nic_data = efx->nic_data;
177294

295+
efx_ef10_sriov_free_vf_vswitching(efx);
296+
178297
if (nic_data->vport_id == EVB_PORT_ID_ASSIGNED)
179298
return; /* No vswitch was ever created */
180299

300+
if (!is_zero_ether_addr(nic_data->vport_mac)) {
301+
efx_ef10_vport_del_mac(efx, nic_data->vport_id,
302+
efx->net_dev->dev_addr);
303+
eth_zero_addr(nic_data->vport_mac);
304+
}
181305
efx_ef10_vport_free(efx, nic_data->vport_id);
182306
nic_data->vport_id = EVB_PORT_ID_ASSIGNED;
183307

184308
efx_ef10_vswitch_free(efx, nic_data->vport_id);
185309
}
310+
311+
static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs)
312+
{
313+
int rc = 0;
314+
struct pci_dev *dev = efx->pci_dev;
315+
316+
efx->vf_count = num_vfs;
317+
318+
rc = efx_ef10_sriov_alloc_vf_vswitching(efx);
319+
if (rc)
320+
goto fail1;
321+
322+
rc = pci_enable_sriov(dev, num_vfs);
323+
if (rc)
324+
goto fail2;
325+
326+
return 0;
327+
fail2:
328+
efx_ef10_sriov_free_vf_vswitching(efx);
329+
fail1:
330+
efx->vf_count = 0;
331+
netif_err(efx, probe, efx->net_dev,
332+
"Failed to enable SRIOV VFs\n");
333+
return rc;
334+
}
335+
336+
static int efx_ef10_pci_sriov_disable(struct efx_nic *efx)
337+
{
338+
struct pci_dev *dev = efx->pci_dev;
339+
340+
pci_disable_sriov(dev);
341+
efx_ef10_sriov_free_vf_vswitching(efx);
342+
efx->vf_count = 0;
343+
return 0;
344+
}
345+
346+
int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs)
347+
{
348+
if (num_vfs == 0)
349+
return efx_ef10_pci_sriov_disable(efx);
350+
else
351+
return efx_ef10_pci_sriov_enable(efx, num_vfs);
352+
}
353+
354+
int efx_ef10_sriov_init(struct efx_nic *efx)
355+
{
356+
return 0;
357+
}
358+
359+
void efx_ef10_sriov_fini(struct efx_nic *efx)
360+
{
361+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
362+
int rc;
363+
364+
if (!nic_data->vf)
365+
return;
366+
367+
rc = efx_ef10_pci_sriov_disable(efx);
368+
if (rc)
369+
netif_dbg(efx, drv, efx->net_dev,
370+
"Disabling SRIOV was not successful rc=%d\n", rc);
371+
else
372+
netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n");
373+
}

drivers/net/ethernet/sfc/ef10_sriov.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@
1212

1313
#include "net_driver.h"
1414

15+
/**
16+
* struct ef10_vf - PF's store of VF data
17+
* @vport_id: vport ID for the VF
18+
* @vport_assigned: record whether the vport is currently assigned to the VF
19+
* @mac: MAC address for the VF, zero when address is removed from the vport
20+
*/
21+
struct ef10_vf {
22+
unsigned int vport_id;
23+
unsigned int vport_assigned;
24+
u8 mac[ETH_ALEN];
25+
};
26+
1527
static inline bool efx_ef10_sriov_wanted(struct efx_nic *efx)
1628
{
1729
return false;

drivers/net/ethernet/sfc/nic.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@ enum {
496496
* @vport_id: The function's vport ID, only relevant for PFs
497497
* @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot
498498
* @pf_index: The number for this PF, or the parent PF if this is a VF
499+
#ifdef CONFIG_SFC_SRIOV
500+
* @vf: Pointer to VF data structure
501+
#endif
499502
*/
500503
struct efx_ef10_nic_data {
501504
struct efx_buffer mcdi_buf;
@@ -519,6 +522,10 @@ struct efx_ef10_nic_data {
519522
unsigned int vport_id;
520523
bool must_probe_vswitching;
521524
unsigned int pf_index;
525+
#ifdef CONFIG_SFC_SRIOV
526+
struct ef10_vf *vf;
527+
#endif
528+
u8 vport_mac[ETH_ALEN];
522529
};
523530

524531
int efx_init_sriov(void);

0 commit comments

Comments
 (0)