1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /**************************************************************************** |
3 | * Driver for Solarflare network controllers and boards |
4 | * Copyright 2015 Solarflare Communications Inc. |
5 | */ |
6 | #include <linux/etherdevice.h> |
7 | #include <linux/pci.h> |
8 | #include <linux/module.h> |
9 | #include "net_driver.h" |
10 | #include "ef10_sriov.h" |
11 | #include "efx.h" |
12 | #include "nic.h" |
13 | #include "mcdi_pcol.h" |
14 | |
15 | static int efx_ef10_evb_port_assign(struct efx_nic *efx, unsigned int port_id, |
16 | unsigned int vf_fn) |
17 | { |
18 | MCDI_DECLARE_BUF(inbuf, MC_CMD_EVB_PORT_ASSIGN_IN_LEN); |
19 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
20 | |
21 | MCDI_SET_DWORD(inbuf, EVB_PORT_ASSIGN_IN_PORT_ID, port_id); |
22 | MCDI_POPULATE_DWORD_2(inbuf, EVB_PORT_ASSIGN_IN_FUNCTION, |
23 | EVB_PORT_ASSIGN_IN_PF, nic_data->pf_index, |
24 | EVB_PORT_ASSIGN_IN_VF, vf_fn); |
25 | |
26 | return efx_mcdi_rpc(efx, MC_CMD_EVB_PORT_ASSIGN, inbuf, inlen: sizeof(inbuf), |
27 | NULL, outlen: 0, NULL); |
28 | } |
29 | |
30 | static int efx_ef10_vswitch_alloc(struct efx_nic *efx, unsigned int port_id, |
31 | unsigned int vswitch_type) |
32 | { |
33 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_ALLOC_IN_LEN); |
34 | int rc; |
35 | |
36 | MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_UPSTREAM_PORT_ID, port_id); |
37 | MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_TYPE, vswitch_type); |
38 | MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 2); |
39 | MCDI_POPULATE_DWORD_1(inbuf, VSWITCH_ALLOC_IN_FLAGS, |
40 | VSWITCH_ALLOC_IN_FLAG_AUTO_PORT, 0); |
41 | |
42 | /* Quietly try to allocate 2 VLAN tags */ |
43 | rc = efx_mcdi_rpc_quiet(efx, MC_CMD_VSWITCH_ALLOC, inbuf, inlen: sizeof(inbuf), |
44 | NULL, outlen: 0, NULL); |
45 | |
46 | /* If 2 VLAN tags is too many, revert to trying with 1 VLAN tags */ |
47 | if (rc == -EPROTO) { |
48 | MCDI_SET_DWORD(inbuf, VSWITCH_ALLOC_IN_NUM_VLAN_TAGS, 1); |
49 | rc = efx_mcdi_rpc(efx, MC_CMD_VSWITCH_ALLOC, inbuf, |
50 | inlen: sizeof(inbuf), NULL, outlen: 0, NULL); |
51 | } else if (rc) { |
52 | efx_mcdi_display_error(efx, MC_CMD_VSWITCH_ALLOC, |
53 | MC_CMD_VSWITCH_ALLOC_IN_LEN, |
54 | NULL, outlen: 0, rc); |
55 | } |
56 | return rc; |
57 | } |
58 | |
59 | static int efx_ef10_vswitch_free(struct efx_nic *efx, unsigned int port_id) |
60 | { |
61 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VSWITCH_FREE_IN_LEN); |
62 | |
63 | MCDI_SET_DWORD(inbuf, VSWITCH_FREE_IN_UPSTREAM_PORT_ID, port_id); |
64 | |
65 | return efx_mcdi_rpc(efx, MC_CMD_VSWITCH_FREE, inbuf, inlen: sizeof(inbuf), |
66 | NULL, outlen: 0, NULL); |
67 | } |
68 | |
69 | static int efx_ef10_vport_alloc(struct efx_nic *efx, |
70 | unsigned int port_id_in, |
71 | unsigned int vport_type, |
72 | u16 vlan, |
73 | unsigned int *port_id_out) |
74 | { |
75 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_ALLOC_IN_LEN); |
76 | MCDI_DECLARE_BUF(outbuf, MC_CMD_VPORT_ALLOC_OUT_LEN); |
77 | size_t outlen; |
78 | int rc; |
79 | |
80 | EFX_WARN_ON_PARANOID(!port_id_out); |
81 | |
82 | MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_UPSTREAM_PORT_ID, port_id_in); |
83 | MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_TYPE, vport_type); |
84 | MCDI_SET_DWORD(inbuf, VPORT_ALLOC_IN_NUM_VLAN_TAGS, |
85 | (vlan != EFX_EF10_NO_VLAN)); |
86 | MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_FLAGS, |
87 | VPORT_ALLOC_IN_FLAG_AUTO_PORT, 0); |
88 | if (vlan != EFX_EF10_NO_VLAN) |
89 | MCDI_POPULATE_DWORD_1(inbuf, VPORT_ALLOC_IN_VLAN_TAGS, |
90 | VPORT_ALLOC_IN_VLAN_TAG_0, vlan); |
91 | |
92 | rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_ALLOC, inbuf, inlen: sizeof(inbuf), |
93 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
94 | if (rc) |
95 | return rc; |
96 | if (outlen < MC_CMD_VPORT_ALLOC_OUT_LEN) |
97 | return -EIO; |
98 | |
99 | *port_id_out = MCDI_DWORD(outbuf, VPORT_ALLOC_OUT_VPORT_ID); |
100 | return 0; |
101 | } |
102 | |
103 | static int efx_ef10_vport_free(struct efx_nic *efx, unsigned int port_id) |
104 | { |
105 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_FREE_IN_LEN); |
106 | |
107 | MCDI_SET_DWORD(inbuf, VPORT_FREE_IN_VPORT_ID, port_id); |
108 | |
109 | return efx_mcdi_rpc(efx, MC_CMD_VPORT_FREE, inbuf, inlen: sizeof(inbuf), |
110 | NULL, outlen: 0, NULL); |
111 | } |
112 | |
113 | static void efx_ef10_sriov_free_vf_vports(struct efx_nic *efx) |
114 | { |
115 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
116 | int i; |
117 | |
118 | if (!nic_data->vf) |
119 | return; |
120 | |
121 | for (i = 0; i < efx->vf_count; i++) { |
122 | struct ef10_vf *vf = nic_data->vf + i; |
123 | |
124 | /* If VF is assigned, do not free the vport */ |
125 | if (vf->pci_dev && pci_is_dev_assigned(pdev: vf->pci_dev)) |
126 | continue; |
127 | |
128 | if (vf->vport_assigned) { |
129 | efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_fn: i); |
130 | vf->vport_assigned = 0; |
131 | } |
132 | |
133 | if (!is_zero_ether_addr(addr: vf->mac)) { |
134 | efx_ef10_vport_del_mac(efx, port_id: vf->vport_id, mac: vf->mac); |
135 | eth_zero_addr(addr: vf->mac); |
136 | } |
137 | |
138 | if (vf->vport_id) { |
139 | efx_ef10_vport_free(efx, port_id: vf->vport_id); |
140 | vf->vport_id = 0; |
141 | } |
142 | |
143 | vf->efx = NULL; |
144 | } |
145 | } |
146 | |
147 | static void efx_ef10_sriov_free_vf_vswitching(struct efx_nic *efx) |
148 | { |
149 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
150 | |
151 | efx_ef10_sriov_free_vf_vports(efx); |
152 | kfree(objp: nic_data->vf); |
153 | nic_data->vf = NULL; |
154 | } |
155 | |
156 | static int efx_ef10_sriov_assign_vf_vport(struct efx_nic *efx, |
157 | unsigned int vf_i) |
158 | { |
159 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
160 | struct ef10_vf *vf = nic_data->vf + vf_i; |
161 | int rc; |
162 | |
163 | if (WARN_ON_ONCE(!nic_data->vf)) |
164 | return -EOPNOTSUPP; |
165 | |
166 | rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, |
167 | MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, |
168 | vlan: vf->vlan, port_id_out: &vf->vport_id); |
169 | if (rc) |
170 | return rc; |
171 | |
172 | rc = efx_ef10_vport_add_mac(efx, port_id: vf->vport_id, mac: vf->mac); |
173 | if (rc) { |
174 | eth_zero_addr(addr: vf->mac); |
175 | return rc; |
176 | } |
177 | |
178 | rc = efx_ef10_evb_port_assign(efx, port_id: vf->vport_id, vf_fn: vf_i); |
179 | if (rc) |
180 | return rc; |
181 | |
182 | vf->vport_assigned = 1; |
183 | return 0; |
184 | } |
185 | |
186 | static int efx_ef10_sriov_alloc_vf_vswitching(struct efx_nic *efx) |
187 | { |
188 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
189 | unsigned int i; |
190 | int rc; |
191 | |
192 | nic_data->vf = kcalloc(n: efx->vf_count, size: sizeof(struct ef10_vf), |
193 | GFP_KERNEL); |
194 | if (!nic_data->vf) |
195 | return -ENOMEM; |
196 | |
197 | for (i = 0; i < efx->vf_count; i++) { |
198 | eth_random_addr(addr: nic_data->vf[i].mac); |
199 | nic_data->vf[i].efx = NULL; |
200 | nic_data->vf[i].vlan = EFX_EF10_NO_VLAN; |
201 | |
202 | rc = efx_ef10_sriov_assign_vf_vport(efx, vf_i: i); |
203 | if (rc) |
204 | goto fail; |
205 | } |
206 | |
207 | return 0; |
208 | fail: |
209 | efx_ef10_sriov_free_vf_vswitching(efx); |
210 | return rc; |
211 | } |
212 | |
213 | static int efx_ef10_sriov_restore_vf_vswitching(struct efx_nic *efx) |
214 | { |
215 | unsigned int i; |
216 | int rc; |
217 | |
218 | for (i = 0; i < efx->vf_count; i++) { |
219 | rc = efx_ef10_sriov_assign_vf_vport(efx, vf_i: i); |
220 | if (rc) |
221 | goto fail; |
222 | } |
223 | |
224 | return 0; |
225 | fail: |
226 | efx_ef10_sriov_free_vf_vswitching(efx); |
227 | return rc; |
228 | } |
229 | |
230 | static int efx_ef10_vadaptor_alloc_set_features(struct efx_nic *efx) |
231 | { |
232 | u32 port_flags; |
233 | int rc; |
234 | |
235 | rc = efx_ef10_vadaptor_alloc(efx, port_id: efx->vport_id); |
236 | if (rc) |
237 | goto fail_vadaptor_alloc; |
238 | |
239 | rc = efx_ef10_vadaptor_query(efx, port_id: efx->vport_id, |
240 | port_flags: &port_flags, NULL, NULL); |
241 | if (rc) |
242 | goto fail_vadaptor_query; |
243 | |
244 | if (port_flags & |
245 | (1 << MC_CMD_VPORT_ALLOC_IN_FLAG_VLAN_RESTRICT_LBN)) |
246 | efx->fixed_features |= NETIF_F_HW_VLAN_CTAG_FILTER; |
247 | else |
248 | efx->fixed_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; |
249 | |
250 | return 0; |
251 | |
252 | fail_vadaptor_query: |
253 | efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); |
254 | fail_vadaptor_alloc: |
255 | return rc; |
256 | } |
257 | |
258 | /* On top of the default firmware vswitch setup, create a VEB vswitch and |
259 | * expansion vport for use by this function. |
260 | */ |
261 | int efx_ef10_vswitching_probe_pf(struct efx_nic *efx) |
262 | { |
263 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
264 | struct net_device *net_dev = efx->net_dev; |
265 | int rc; |
266 | |
267 | if (pci_sriov_get_totalvfs(dev: efx->pci_dev) <= 0) { |
268 | /* vswitch not needed as we have no VFs */ |
269 | efx_ef10_vadaptor_alloc_set_features(efx); |
270 | return 0; |
271 | } |
272 | |
273 | rc = efx_ef10_vswitch_alloc(efx, EVB_PORT_ID_ASSIGNED, |
274 | MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB); |
275 | if (rc) |
276 | goto fail1; |
277 | |
278 | rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, |
279 | MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, |
280 | EFX_EF10_NO_VLAN, port_id_out: &efx->vport_id); |
281 | if (rc) |
282 | goto fail2; |
283 | |
284 | rc = efx_ef10_vport_add_mac(efx, port_id: efx->vport_id, mac: net_dev->dev_addr); |
285 | if (rc) |
286 | goto fail3; |
287 | ether_addr_copy(dst: nic_data->vport_mac, src: net_dev->dev_addr); |
288 | |
289 | rc = efx_ef10_vadaptor_alloc_set_features(efx); |
290 | if (rc) |
291 | goto fail4; |
292 | |
293 | return 0; |
294 | fail4: |
295 | efx_ef10_vport_del_mac(efx, port_id: efx->vport_id, mac: nic_data->vport_mac); |
296 | eth_zero_addr(addr: nic_data->vport_mac); |
297 | fail3: |
298 | efx_ef10_vport_free(efx, port_id: efx->vport_id); |
299 | efx->vport_id = EVB_PORT_ID_ASSIGNED; |
300 | fail2: |
301 | efx_ef10_vswitch_free(efx, EVB_PORT_ID_ASSIGNED); |
302 | fail1: |
303 | return rc; |
304 | } |
305 | |
306 | int efx_ef10_vswitching_probe_vf(struct efx_nic *efx) |
307 | { |
308 | return efx_ef10_vadaptor_alloc_set_features(efx); |
309 | } |
310 | |
311 | int efx_ef10_vswitching_restore_pf(struct efx_nic *efx) |
312 | { |
313 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
314 | int rc; |
315 | |
316 | if (!nic_data->must_probe_vswitching) |
317 | return 0; |
318 | |
319 | rc = efx_ef10_vswitching_probe_pf(efx); |
320 | if (rc) |
321 | goto fail; |
322 | |
323 | rc = efx_ef10_sriov_restore_vf_vswitching(efx); |
324 | if (rc) |
325 | goto fail; |
326 | |
327 | nic_data->must_probe_vswitching = false; |
328 | fail: |
329 | return rc; |
330 | } |
331 | |
332 | int efx_ef10_vswitching_restore_vf(struct efx_nic *efx) |
333 | { |
334 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
335 | int rc; |
336 | |
337 | if (!nic_data->must_probe_vswitching) |
338 | return 0; |
339 | |
340 | rc = efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); |
341 | if (rc) |
342 | return rc; |
343 | |
344 | nic_data->must_probe_vswitching = false; |
345 | return 0; |
346 | } |
347 | |
348 | void efx_ef10_vswitching_remove_pf(struct efx_nic *efx) |
349 | { |
350 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
351 | |
352 | efx_ef10_sriov_free_vf_vswitching(efx); |
353 | |
354 | efx_ef10_vadaptor_free(efx, port_id: efx->vport_id); |
355 | |
356 | if (efx->vport_id == EVB_PORT_ID_ASSIGNED) |
357 | return; /* No vswitch was ever created */ |
358 | |
359 | if (!is_zero_ether_addr(addr: nic_data->vport_mac)) { |
360 | efx_ef10_vport_del_mac(efx, port_id: efx->vport_id, |
361 | mac: efx->net_dev->dev_addr); |
362 | eth_zero_addr(addr: nic_data->vport_mac); |
363 | } |
364 | efx_ef10_vport_free(efx, port_id: efx->vport_id); |
365 | efx->vport_id = EVB_PORT_ID_ASSIGNED; |
366 | |
367 | /* Only free the vswitch if no VFs are assigned */ |
368 | if (!pci_vfs_assigned(dev: efx->pci_dev)) |
369 | efx_ef10_vswitch_free(efx, port_id: efx->vport_id); |
370 | } |
371 | |
372 | void efx_ef10_vswitching_remove_vf(struct efx_nic *efx) |
373 | { |
374 | efx_ef10_vadaptor_free(efx, EVB_PORT_ID_ASSIGNED); |
375 | } |
376 | |
377 | static int efx_ef10_pci_sriov_enable(struct efx_nic *efx, int num_vfs) |
378 | { |
379 | int rc = 0; |
380 | struct pci_dev *dev = efx->pci_dev; |
381 | |
382 | efx->vf_count = num_vfs; |
383 | |
384 | rc = efx_ef10_sriov_alloc_vf_vswitching(efx); |
385 | if (rc) |
386 | goto fail1; |
387 | |
388 | rc = pci_enable_sriov(dev, nr_virtfn: num_vfs); |
389 | if (rc) |
390 | goto fail2; |
391 | |
392 | return 0; |
393 | fail2: |
394 | efx_ef10_sriov_free_vf_vswitching(efx); |
395 | fail1: |
396 | efx->vf_count = 0; |
397 | netif_err(efx, probe, efx->net_dev, |
398 | "Failed to enable SRIOV VFs\n" ); |
399 | return rc; |
400 | } |
401 | |
402 | /* Disable SRIOV and remove VFs |
403 | * If some VFs are attached to a guest (using Xen, only) nothing is |
404 | * done if force=false, and vports are freed if force=true (for the non |
405 | * attachedc ones, only) but SRIOV is not disabled and VFs are not |
406 | * removed in either case. |
407 | */ |
408 | static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force) |
409 | { |
410 | struct pci_dev *dev = efx->pci_dev; |
411 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
412 | unsigned int vfs_assigned = pci_vfs_assigned(dev); |
413 | int i, rc = 0; |
414 | |
415 | if (vfs_assigned && !force) { |
416 | netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; " |
417 | "please detach them before disabling SR-IOV\n" ); |
418 | return -EBUSY; |
419 | } |
420 | |
421 | if (!vfs_assigned) { |
422 | for (i = 0; i < efx->vf_count; i++) |
423 | nic_data->vf[i].pci_dev = NULL; |
424 | pci_disable_sriov(dev); |
425 | } else { |
426 | rc = -EBUSY; |
427 | } |
428 | |
429 | efx_ef10_sriov_free_vf_vswitching(efx); |
430 | efx->vf_count = 0; |
431 | return rc; |
432 | } |
433 | |
434 | int efx_ef10_sriov_configure(struct efx_nic *efx, int num_vfs) |
435 | { |
436 | if (num_vfs == 0) |
437 | return efx_ef10_pci_sriov_disable(efx, force: false); |
438 | else |
439 | return efx_ef10_pci_sriov_enable(efx, num_vfs); |
440 | } |
441 | |
442 | int efx_ef10_sriov_init(struct efx_nic *efx) |
443 | { |
444 | return 0; |
445 | } |
446 | |
447 | void efx_ef10_sriov_fini(struct efx_nic *efx) |
448 | { |
449 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
450 | int rc; |
451 | |
452 | if (!nic_data->vf) { |
453 | /* Remove any un-assigned orphaned VFs. This can happen if the PF driver |
454 | * was unloaded while any VF was assigned to a guest (using Xen, only). |
455 | */ |
456 | if (pci_num_vf(dev: efx->pci_dev) && !pci_vfs_assigned(dev: efx->pci_dev)) |
457 | pci_disable_sriov(dev: efx->pci_dev); |
458 | return; |
459 | } |
460 | |
461 | /* Disable SRIOV and remove any VFs in the host */ |
462 | rc = efx_ef10_pci_sriov_disable(efx, force: true); |
463 | if (rc) |
464 | netif_dbg(efx, drv, efx->net_dev, |
465 | "Disabling SRIOV was not successful rc=%d\n" , rc); |
466 | else |
467 | netif_dbg(efx, drv, efx->net_dev, "SRIOV disabled\n" ); |
468 | } |
469 | |
470 | static int efx_ef10_vport_del_vf_mac(struct efx_nic *efx, unsigned int port_id, |
471 | u8 *mac) |
472 | { |
473 | MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); |
474 | MCDI_DECLARE_BUF_ERR(outbuf); |
475 | size_t outlen; |
476 | int rc; |
477 | |
478 | MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); |
479 | ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), src: mac); |
480 | |
481 | rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, |
482 | inlen: sizeof(inbuf), outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
483 | |
484 | return rc; |
485 | } |
486 | |
487 | int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac) |
488 | { |
489 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
490 | struct ef10_vf *vf; |
491 | int rc; |
492 | |
493 | if (!nic_data->vf) |
494 | return -EOPNOTSUPP; |
495 | |
496 | if (vf_i >= efx->vf_count) |
497 | return -EINVAL; |
498 | vf = nic_data->vf + vf_i; |
499 | |
500 | if (vf->efx) { |
501 | efx_device_detach_sync(efx: vf->efx); |
502 | efx_net_stop(net_dev: vf->efx->net_dev); |
503 | |
504 | vf->efx->type->filter_table_remove(vf->efx); |
505 | |
506 | rc = efx_ef10_vadaptor_free(efx: vf->efx, EVB_PORT_ID_ASSIGNED); |
507 | if (rc) |
508 | return rc; |
509 | } |
510 | |
511 | rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_fn: vf_i); |
512 | if (rc) |
513 | return rc; |
514 | |
515 | if (!is_zero_ether_addr(addr: vf->mac)) { |
516 | rc = efx_ef10_vport_del_vf_mac(efx, port_id: vf->vport_id, mac: vf->mac); |
517 | if (rc) |
518 | return rc; |
519 | } |
520 | |
521 | if (!is_zero_ether_addr(addr: mac)) { |
522 | rc = efx_ef10_vport_add_mac(efx, port_id: vf->vport_id, mac); |
523 | if (rc) |
524 | goto fail; |
525 | |
526 | if (vf->efx) |
527 | eth_hw_addr_set(dev: vf->efx->net_dev, addr: mac); |
528 | } |
529 | |
530 | ether_addr_copy(dst: vf->mac, src: mac); |
531 | |
532 | rc = efx_ef10_evb_port_assign(efx, port_id: vf->vport_id, vf_fn: vf_i); |
533 | if (rc) |
534 | goto fail; |
535 | |
536 | if (vf->efx) { |
537 | /* VF cannot use the vport_id that the PF created */ |
538 | rc = efx_ef10_vadaptor_alloc(efx: vf->efx, EVB_PORT_ID_ASSIGNED); |
539 | if (rc) |
540 | return rc; |
541 | vf->efx->type->filter_table_probe(vf->efx); |
542 | efx_net_open(net_dev: vf->efx->net_dev); |
543 | efx_device_attach_if_not_resetting(efx: vf->efx); |
544 | } |
545 | |
546 | return 0; |
547 | |
548 | fail: |
549 | eth_zero_addr(addr: vf->mac); |
550 | return rc; |
551 | } |
552 | |
553 | int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan, |
554 | u8 qos) |
555 | { |
556 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
557 | struct ef10_vf *vf; |
558 | u16 new_vlan; |
559 | int rc = 0, rc2 = 0; |
560 | |
561 | if (vf_i >= efx->vf_count) |
562 | return -EINVAL; |
563 | if (qos != 0) |
564 | return -EINVAL; |
565 | |
566 | vf = nic_data->vf + vf_i; |
567 | |
568 | new_vlan = (vlan == 0) ? EFX_EF10_NO_VLAN : vlan; |
569 | if (new_vlan == vf->vlan) |
570 | return 0; |
571 | |
572 | if (vf->efx) { |
573 | efx_device_detach_sync(efx: vf->efx); |
574 | efx_net_stop(net_dev: vf->efx->net_dev); |
575 | |
576 | mutex_lock(&vf->efx->mac_lock); |
577 | vf->efx->type->filter_table_remove(vf->efx); |
578 | |
579 | rc = efx_ef10_vadaptor_free(efx: vf->efx, EVB_PORT_ID_ASSIGNED); |
580 | if (rc) |
581 | goto restore_filters; |
582 | } |
583 | |
584 | if (vf->vport_assigned) { |
585 | rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_fn: vf_i); |
586 | if (rc) { |
587 | netif_warn(efx, drv, efx->net_dev, |
588 | "Failed to change vlan on VF %d.\n" , vf_i); |
589 | netif_warn(efx, drv, efx->net_dev, |
590 | "This is likely because the VF is bound to a driver in a VM.\n" ); |
591 | netif_warn(efx, drv, efx->net_dev, |
592 | "Please unload the driver in the VM.\n" ); |
593 | goto restore_vadaptor; |
594 | } |
595 | vf->vport_assigned = 0; |
596 | } |
597 | |
598 | if (!is_zero_ether_addr(addr: vf->mac)) { |
599 | rc = efx_ef10_vport_del_mac(efx, port_id: vf->vport_id, mac: vf->mac); |
600 | if (rc) |
601 | goto restore_evb_port; |
602 | } |
603 | |
604 | if (vf->vport_id) { |
605 | rc = efx_ef10_vport_free(efx, port_id: vf->vport_id); |
606 | if (rc) |
607 | goto restore_mac; |
608 | vf->vport_id = 0; |
609 | } |
610 | |
611 | /* Do the actual vlan change */ |
612 | vf->vlan = new_vlan; |
613 | |
614 | /* Restore everything in reverse order */ |
615 | rc = efx_ef10_vport_alloc(efx, EVB_PORT_ID_ASSIGNED, |
616 | MC_CMD_VPORT_ALLOC_IN_VPORT_TYPE_NORMAL, |
617 | vlan: vf->vlan, port_id_out: &vf->vport_id); |
618 | if (rc) |
619 | goto reset_nic_up_write; |
620 | |
621 | restore_mac: |
622 | if (!is_zero_ether_addr(addr: vf->mac)) { |
623 | rc2 = efx_ef10_vport_add_mac(efx, port_id: vf->vport_id, mac: vf->mac); |
624 | if (rc2) { |
625 | eth_zero_addr(addr: vf->mac); |
626 | goto reset_nic_up_write; |
627 | } |
628 | } |
629 | |
630 | restore_evb_port: |
631 | rc2 = efx_ef10_evb_port_assign(efx, port_id: vf->vport_id, vf_fn: vf_i); |
632 | if (rc2) |
633 | goto reset_nic_up_write; |
634 | else |
635 | vf->vport_assigned = 1; |
636 | |
637 | restore_vadaptor: |
638 | if (vf->efx) { |
639 | rc2 = efx_ef10_vadaptor_alloc(efx: vf->efx, EVB_PORT_ID_ASSIGNED); |
640 | if (rc2) |
641 | goto reset_nic_up_write; |
642 | } |
643 | |
644 | restore_filters: |
645 | if (vf->efx) { |
646 | rc2 = vf->efx->type->filter_table_probe(vf->efx); |
647 | if (rc2) |
648 | goto reset_nic_up_write; |
649 | |
650 | mutex_unlock(lock: &vf->efx->mac_lock); |
651 | |
652 | rc2 = efx_net_open(net_dev: vf->efx->net_dev); |
653 | if (rc2) |
654 | goto reset_nic; |
655 | |
656 | efx_device_attach_if_not_resetting(efx: vf->efx); |
657 | } |
658 | return rc; |
659 | |
660 | reset_nic_up_write: |
661 | if (vf->efx) |
662 | mutex_unlock(lock: &vf->efx->mac_lock); |
663 | reset_nic: |
664 | if (vf->efx) { |
665 | netif_err(efx, drv, efx->net_dev, |
666 | "Failed to restore VF - scheduling reset.\n" ); |
667 | efx_schedule_reset(efx: vf->efx, type: RESET_TYPE_DATAPATH); |
668 | } else { |
669 | netif_err(efx, drv, efx->net_dev, |
670 | "Failed to restore the VF and cannot reset the VF " |
671 | "- VF is not functional.\n" ); |
672 | netif_err(efx, drv, efx->net_dev, |
673 | "Please reload the driver attached to the VF.\n" ); |
674 | } |
675 | |
676 | return rc ? rc : rc2; |
677 | } |
678 | |
679 | static int efx_ef10_sriov_set_privilege_mask(struct efx_nic *efx, int vf_i, |
680 | u32 mask, u32 value) |
681 | { |
682 | MCDI_DECLARE_BUF(pm_outbuf, MC_CMD_PRIVILEGE_MASK_OUT_LEN); |
683 | MCDI_DECLARE_BUF(pm_inbuf, MC_CMD_PRIVILEGE_MASK_IN_LEN); |
684 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
685 | u32 old_mask, new_mask; |
686 | size_t outlen; |
687 | int rc; |
688 | |
689 | EFX_WARN_ON_PARANOID((value & ~mask) != 0); |
690 | |
691 | /* Get privilege mask */ |
692 | MCDI_POPULATE_DWORD_2(pm_inbuf, PRIVILEGE_MASK_IN_FUNCTION, |
693 | PRIVILEGE_MASK_IN_FUNCTION_PF, nic_data->pf_index, |
694 | PRIVILEGE_MASK_IN_FUNCTION_VF, vf_i); |
695 | |
696 | rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK, |
697 | inbuf: pm_inbuf, inlen: sizeof(pm_inbuf), |
698 | outbuf: pm_outbuf, outlen: sizeof(pm_outbuf), outlen_actual: &outlen); |
699 | |
700 | if (rc != 0) |
701 | return rc; |
702 | if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN) |
703 | return -EIO; |
704 | |
705 | old_mask = MCDI_DWORD(pm_outbuf, PRIVILEGE_MASK_OUT_OLD_MASK); |
706 | |
707 | new_mask = old_mask & ~mask; |
708 | new_mask |= value; |
709 | |
710 | if (new_mask == old_mask) |
711 | return 0; |
712 | |
713 | new_mask |= MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE; |
714 | |
715 | /* Set privilege mask */ |
716 | MCDI_SET_DWORD(pm_inbuf, PRIVILEGE_MASK_IN_NEW_MASK, new_mask); |
717 | |
718 | rc = efx_mcdi_rpc(efx, MC_CMD_PRIVILEGE_MASK, |
719 | inbuf: pm_inbuf, inlen: sizeof(pm_inbuf), |
720 | outbuf: pm_outbuf, outlen: sizeof(pm_outbuf), outlen_actual: &outlen); |
721 | |
722 | if (rc != 0) |
723 | return rc; |
724 | if (outlen != MC_CMD_PRIVILEGE_MASK_OUT_LEN) |
725 | return -EIO; |
726 | |
727 | return 0; |
728 | } |
729 | |
730 | int efx_ef10_sriov_set_vf_spoofchk(struct efx_nic *efx, int vf_i, bool spoofchk) |
731 | { |
732 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
733 | |
734 | /* Can't enable spoofchk if firmware doesn't support it. */ |
735 | if (!(nic_data->datapath_caps & |
736 | BIT(MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_LBN)) && |
737 | spoofchk) |
738 | return -EOPNOTSUPP; |
739 | |
740 | return efx_ef10_sriov_set_privilege_mask(efx, vf_i, |
741 | MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX, |
742 | value: spoofchk ? 0 : MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING_TX); |
743 | } |
744 | |
745 | int efx_ef10_sriov_set_vf_link_state(struct efx_nic *efx, int vf_i, |
746 | int link_state) |
747 | { |
748 | MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN); |
749 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
750 | |
751 | BUILD_BUG_ON(IFLA_VF_LINK_STATE_AUTO != |
752 | MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO); |
753 | BUILD_BUG_ON(IFLA_VF_LINK_STATE_ENABLE != |
754 | MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP); |
755 | BUILD_BUG_ON(IFLA_VF_LINK_STATE_DISABLE != |
756 | MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN); |
757 | MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION, |
758 | LINK_STATE_MODE_IN_FUNCTION_PF, |
759 | nic_data->pf_index, |
760 | LINK_STATE_MODE_IN_FUNCTION_VF, vf_i); |
761 | MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, link_state); |
762 | return efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, inlen: sizeof(inbuf), |
763 | NULL, outlen: 0, NULL); /* don't care what old mode was */ |
764 | } |
765 | |
766 | int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i, |
767 | struct ifla_vf_info *ivf) |
768 | { |
769 | MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN); |
770 | MCDI_DECLARE_BUF(outbuf, MC_CMD_LINK_STATE_MODE_OUT_LEN); |
771 | |
772 | struct efx_ef10_nic_data *nic_data = efx->nic_data; |
773 | struct ef10_vf *vf; |
774 | size_t outlen; |
775 | int rc; |
776 | |
777 | if (vf_i >= efx->vf_count) |
778 | return -EINVAL; |
779 | |
780 | if (!nic_data->vf) |
781 | return -EOPNOTSUPP; |
782 | |
783 | vf = nic_data->vf + vf_i; |
784 | |
785 | ivf->vf = vf_i; |
786 | ivf->min_tx_rate = 0; |
787 | ivf->max_tx_rate = 0; |
788 | ether_addr_copy(dst: ivf->mac, src: vf->mac); |
789 | ivf->vlan = (vf->vlan == EFX_EF10_NO_VLAN) ? 0 : vf->vlan; |
790 | ivf->qos = 0; |
791 | |
792 | MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION, |
793 | LINK_STATE_MODE_IN_FUNCTION_PF, |
794 | nic_data->pf_index, |
795 | LINK_STATE_MODE_IN_FUNCTION_VF, vf_i); |
796 | MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, |
797 | MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE); |
798 | rc = efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, inlen: sizeof(inbuf), |
799 | outbuf, outlen: sizeof(outbuf), outlen_actual: &outlen); |
800 | if (rc) |
801 | return rc; |
802 | if (outlen < MC_CMD_LINK_STATE_MODE_OUT_LEN) |
803 | return -EIO; |
804 | ivf->linkstate = MCDI_DWORD(outbuf, LINK_STATE_MODE_OUT_OLD_MODE); |
805 | |
806 | return 0; |
807 | } |
808 | |