Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bnxt/bnxt_en/bnxt_sriov.c
283101 views
1
#include <linux/delay.h>
2
#include <linux/etherdevice.h>
3
4
#include "opt_global.h"
5
#include "bnxt.h"
6
#include "hsi_struct_def.h"
7
#include "bnxt_hwrm.h"
8
#include "bnxt_sriov.h"
9
10
#ifdef PCI_IOV
11
12
static int
13
bnxt_set_vf_admin_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
14
const uint8_t *mac)
15
{
16
struct hwrm_func_cfg_input req = {0};
17
int rc;
18
19
if (!BNXT_PF(softc))
20
return (EOPNOTSUPP);
21
22
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
23
24
req.fid = htole16(vf->fw_fid);
25
req.enables = htole32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);
26
memcpy(req.dflt_mac_addr, mac, ETHER_ADDR_LEN);
27
28
BNXT_HWRM_LOCK(softc);
29
rc = _hwrm_send_message(softc, &req, sizeof(req));
30
BNXT_HWRM_UNLOCK(softc);
31
32
return (rc);
33
}
34
35
static bool
36
bnxt_vf_parse_schema(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
37
const nvlist_t *params)
38
{
39
const void *mac;
40
size_t maclen;
41
42
memset(vf->mac_addr, 0, ETHER_ADDR_LEN);
43
memset(vf->vf_mac_addr, 0, ETHER_ADDR_LEN);
44
45
if (params == NULL)
46
return (false);
47
48
if (nvlist_exists(params, "mac-anti-spoof"))
49
vf->spoofchk = nvlist_get_bool(params, "mac-anti-spoof");
50
if (nvlist_exists(params, "trust"))
51
vf->trusted = nvlist_get_bool(params, "trust");
52
53
if (!nvlist_exists(params, "mac-addr"))
54
return (false);
55
56
mac = nvlist_get_binary(params, "mac-addr", &maclen);
57
58
if (maclen != ETHER_ADDR_LEN)
59
return (false);
60
61
if (!is_valid_ether_addr(mac))
62
return (false);
63
64
memcpy(vf->mac_addr, mac, ETHER_ADDR_LEN);
65
return (true);
66
}
67
68
/* Add a Virtual Functions */
69
int
70
bnxt_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)
71
{
72
struct bnxt_softc *softc = iflib_get_softc(ctx);
73
struct bnxt_vf_info *vf = &softc->pf.vf[vfnum];
74
int rc;
75
76
vf->fw_fid = softc->pf.first_vf_id + vfnum;
77
vf->vfnum = vfnum;
78
79
/*
80
* If the schema provided a valid admin MAC, program it into firmware.
81
*/
82
if (bnxt_vf_parse_schema(softc, vf, params)) {
83
rc = bnxt_set_vf_admin_mac(softc, vf, vf->mac_addr);
84
if (rc)
85
device_printf(softc->dev,
86
"vf%u: PF-assigned MAC programming failed (rc=%d), falling back to firmware/default MAC\n",
87
vfnum, rc);
88
}
89
90
(void)bnxt_set_vf_trust(softc, vfnum, vf->trusted);
91
(void)bnxt_set_vf_spoofchk(softc, vfnum, vf->spoofchk);
92
93
return 0;
94
}
95
96
/* Free driver-side VF resources (called after hwrm_vf_resc_free) */
97
void bnxt_free_vf_resources(struct bnxt_softc *softc)
98
{
99
int i;
100
size_t page_size = 1UL << softc->pf.vf_hwrm_cmd_req_page_shift;
101
102
softc->pf.active_vfs = 0;
103
104
if (softc->pf.vf) {
105
kfree(softc->pf.vf);
106
softc->pf.vf = NULL;
107
}
108
if (softc->pf.vf_event_bmap) {
109
kfree(softc->pf.vf_event_bmap);
110
softc->pf.vf_event_bmap = NULL;
111
}
112
for (i = 0; i < softc->pf.hwrm_cmd_req_pages; i++) {
113
if (softc->pf.hwrm_cmd_req_addr[i]) {
114
dma_free_coherent(&softc->pdev->dev, page_size,
115
softc->pf.hwrm_cmd_req_addr[i],
116
softc->pf.hwrm_cmd_req_dma_addr[i]);
117
softc->pf.hwrm_cmd_req_addr[i] = NULL;
118
}
119
}
120
}
121
122
/* Free firmware-side VF resources */
123
int
124
bnxt_hwrm_func_vf_resource_free(struct bnxt_softc *softc, int num_vfs)
125
{
126
int i, rc;
127
int first_vf_id, last_vf_id;
128
struct hwrm_func_vf_resc_free_input req;
129
130
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_RESC_FREE);
131
132
first_vf_id = softc->pf.first_vf_id;
133
last_vf_id = first_vf_id + num_vfs - 1;
134
135
BNXT_HWRM_LOCK(softc);
136
for (i = first_vf_id; i <= last_vf_id; i++) {
137
req.vf_id = cpu_to_le16(i);
138
rc = _hwrm_send_message(softc, &req, sizeof(req));
139
if (rc)
140
break;
141
}
142
BNXT_HWRM_UNLOCK(softc);
143
144
return rc;
145
}
146
147
/* Free all VF resources */
148
void bnxt_iov_uninit(if_ctx_t ctx)
149
{
150
int rc;
151
struct bnxt_softc *softc = iflib_get_softc(ctx);
152
int num_vfs = softc->pf.num_vfs;
153
154
if (!num_vfs)
155
return;
156
157
BNXT_SRIOV_LOCK(softc);
158
softc->pf.num_vfs = 0;
159
BNXT_SRIOV_UNLOCK(softc);
160
161
rc = bnxt_hwrm_func_vf_resource_free(softc, num_vfs);
162
if (rc)
163
device_printf(softc->dev, "VF resource free HWRM failed: %d\n", rc);
164
165
bnxt_destroy_trusted_vf_sysctls(softc);
166
bnxt_free_vf_resources(softc);
167
BNXT_SRIOV_LOCK_DESTROY(softc);
168
}
169
170
static inline int
171
bnxt_set_vf_resc_field(uint16_t *min_field, uint16_t *max_field,
172
uint16_t hw_max, uint16_t pf_alloc, int num_vfs)
173
{
174
uint16_t val = 0;
175
176
if (num_vfs <= 0)
177
return -EINVAL;
178
179
if (hw_max > pf_alloc)
180
val = (hw_max - pf_alloc) / num_vfs;
181
182
*min_field = *max_field = cpu_to_le16(val);
183
184
return 0;
185
}
186
187
static int bnxt_set_vf_params(struct bnxt_softc *softc, int vf_id)
188
{
189
struct hwrm_func_cfg_input req = {0};
190
struct bnxt_vf_info *vf;
191
int rc;
192
193
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
194
195
vf = &softc->pf.vf[vf_id];
196
req.fid = cpu_to_le16(vf->fw_fid);
197
198
199
if (is_valid_ether_addr(vf->mac_addr)) {
200
req.enables |= cpu_to_le32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);
201
memcpy(req.dflt_mac_addr, vf->mac_addr, ETHER_ADDR_LEN);
202
}
203
204
if (vf->vlan) {
205
req.enables |= cpu_to_le32(HWRM_FUNC_CFG_INPUT_ENABLES_DFLT_VLAN);
206
req.dflt_vlan = cpu_to_le16(vf->vlan);
207
}
208
209
if (vf->flags & BNXT_VF_TRUST)
210
req.flags = cpu_to_le32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE);
211
212
BNXT_HWRM_LOCK(softc);
213
rc = _hwrm_send_message(softc, &req, sizeof(req));
214
BNXT_HWRM_UNLOCK(softc);
215
if (rc)
216
device_printf(softc->dev, "hwrm_func_cfg failed (error:%d)\n", rc);
217
218
return rc;
219
}
220
221
int bnxt_approve_mac(struct bnxt_softc *sc)
222
{
223
224
struct hwrm_func_vf_cfg_input req = (struct hwrm_func_vf_cfg_input){0};
225
struct bnxt_vf_info *vf = &sc->vf;
226
u8 *mac = vf->mac_addr;
227
int rc = 0;
228
229
if (!BNXT_VF(sc))
230
return EOPNOTSUPP;
231
232
bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_VF_CFG);
233
req.enables = htole32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_DFLT_MAC_ADDR);
234
memcpy(req.dflt_mac_addr, mac, ETHER_ADDR_LEN);
235
236
BNXT_HWRM_LOCK(sc);
237
rc = _hwrm_send_message(sc, &req, sizeof(req));
238
BNXT_HWRM_UNLOCK(sc);
239
240
if (rc) {
241
device_printf(sc->dev,
242
"VF MAC %02x:%02x:%02x:%02x:%02x:%02x not approved by PF (rc=%d)\n",
243
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], rc);
244
return EADDRNOTAVAIL;
245
}
246
return rc;
247
}
248
249
void
250
bnxt_update_vf_mac(struct bnxt_softc *sc)
251
{
252
int rc = 0;
253
struct hwrm_func_qcaps_input req = {0};
254
struct hwrm_func_qcaps_output *resp =
255
(void *)sc->hwrm_cmd_resp.idi_vaddr;
256
bool inform_pf = false;
257
258
bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_QCAPS);
259
req.fid = htole16(0xffff);
260
261
BNXT_HWRM_LOCK(sc);
262
rc = _hwrm_send_message(sc, &req, sizeof(req));
263
if (rc)
264
goto update_vf_mac_exit;
265
266
if (!ether_addr_equal(resp->mac_address, sc->vf.mac_addr)) {
267
memcpy(sc->vf.mac_addr, resp->mac_address, ETHER_ADDR_LEN);
268
if (!is_valid_ether_addr(sc->vf.mac_addr))
269
inform_pf = true;
270
}
271
272
if (is_valid_ether_addr(sc->vf.mac_addr)) {
273
iflib_set_mac(sc->ctx, sc->vf.mac_addr);
274
memcpy(sc->func.mac_addr, sc->vf.mac_addr, ETHER_ADDR_LEN);
275
}
276
277
update_vf_mac_exit:
278
BNXT_HWRM_UNLOCK(sc);
279
if (inform_pf)
280
bnxt_approve_mac(sc);
281
}
282
283
static int
284
bnxt_hwrm_fwd_err_resp(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
285
u32 msg_size)
286
{
287
struct hwrm_reject_fwd_resp_input req;
288
289
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_REJECT_FWD_RESP);
290
291
if (msg_size > sizeof(req.encap_request))
292
msg_size = sizeof(req.encap_request);
293
294
req.target_id = cpu_to_le16(vf->fw_fid);
295
req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
296
memcpy(&req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
297
298
BNXT_HWRM_LOCK(softc);
299
int rc = _hwrm_send_message(softc, &req, sizeof(req));
300
BNXT_HWRM_UNLOCK(softc);
301
if (rc)
302
device_printf(softc->dev, "hwrm_fwd_err_resp failed (error=%d)\n", rc);
303
304
return rc;
305
}
306
307
static int
308
bnxt_hwrm_exec_fwd_resp(struct bnxt_softc *softc, struct bnxt_vf_info *vf,
309
u32 msg_size)
310
{
311
struct hwrm_exec_fwd_resp_input req;
312
313
if (BNXT_EXEC_FWD_RESP_SIZE_ERR(msg_size))
314
return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
315
316
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_EXEC_FWD_RESP);
317
318
req.target_id = cpu_to_le16(vf->fw_fid);
319
req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
320
memcpy(&req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
321
322
BNXT_HWRM_LOCK(softc);
323
int rc = _hwrm_send_message(softc, &req, sizeof(req));
324
BNXT_HWRM_UNLOCK(softc);
325
if (rc)
326
device_printf(softc->dev, "hwrm_exec_fw_resp failed (error=%d)\n", rc);
327
328
return rc;
329
}
330
331
static int
332
bnxt_hwrm_func_qcfg_flags(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
333
{
334
struct hwrm_func_qcfg_input req;
335
struct hwrm_func_qcfg_output *resp =
336
(void *)softc->hwrm_cmd_resp.idi_vaddr;
337
338
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);
339
340
req.fid = cpu_to_le16(BNXT_PF(softc) ? vf->fw_fid : 0xffff);
341
342
BNXT_HWRM_LOCK(softc);
343
int rc = _hwrm_send_message(softc, &req, sizeof(req));
344
BNXT_HWRM_UNLOCK(softc);
345
if (!rc)
346
vf->func_qcfg_flags = cpu_to_le16(resp->flags);
347
348
return rc;
349
}
350
351
bool
352
bnxt_is_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
353
{
354
bnxt_hwrm_func_qcfg_flags(softc, vf);
355
return !!(vf->func_qcfg_flags & HWRM_FUNC_QCFG_OUTPUT_FLAGS_TRUSTED_VF);
356
}
357
358
bool bnxt_promisc_ok(struct bnxt_softc *softc)
359
{
360
if (BNXT_VF(softc) && !bnxt_is_trusted_vf(softc, &softc->vf))
361
return false;
362
return true;
363
}
364
365
static int
366
bnxt_hwrm_set_trusted_vf(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
367
{
368
struct hwrm_func_cfg_input req = {0};
369
int rc;
370
371
if (!(softc->fw_cap & BNXT_FW_CAP_TRUSTED_VF))
372
return (EOPNOTSUPP);
373
374
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
375
376
req.fid = htole16(vf->fw_fid);
377
378
if (vf->flags & BNXT_VF_TRUST)
379
req.flags = cpu_to_le32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_ENABLE);
380
else
381
req.flags = cpu_to_le32(HWRM_FUNC_CFG_INPUT_FLAGS_TRUSTED_VF_DISABLE);
382
383
BNXT_HWRM_LOCK(softc);
384
rc = _hwrm_send_message(softc, &req, sizeof(req));
385
BNXT_HWRM_UNLOCK(softc);
386
if (rc)
387
device_printf(softc->dev, "bnxt_hwrm_set_trusted_vf failed. rc:%d\n", rc);
388
389
return rc;
390
}
391
392
int
393
bnxt_set_vf_trust(struct bnxt_softc *softc, int vf_id, bool trusted)
394
{
395
int rc;
396
struct bnxt_vf_info *vf = NULL;
397
398
BNXT_SRIOV_LOCK(softc);
399
if (softc->pf.num_vfs == 0 || vf_id >= softc->pf.num_vfs) {
400
BNXT_SRIOV_UNLOCK(softc);
401
return (ENOENT);
402
}
403
vf = &softc->pf.vf[vf_id];
404
405
if (trusted)
406
vf->flags |= BNXT_VF_TRUST;
407
else
408
vf->flags &= ~BNXT_VF_TRUST;
409
410
BNXT_SRIOV_UNLOCK(softc);
411
412
rc = bnxt_hwrm_set_trusted_vf(softc, vf);
413
if (rc == 0) {
414
BNXT_SRIOV_LOCK(softc);
415
if (softc->pf.num_vfs != 0 && vf_id < softc->pf.num_vfs) {
416
vf = &softc->pf.vf[vf_id];
417
if (trusted)
418
vf->flags |= BNXT_VF_TRUST;
419
else
420
vf->flags &= ~BNXT_VF_TRUST;
421
}
422
BNXT_SRIOV_UNLOCK(softc);
423
}
424
return rc;
425
}
426
427
static int
428
bnxt_vf_configure_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
429
{
430
u32 msg_size = sizeof(struct hwrm_func_vf_cfg_input);
431
struct hwrm_func_vf_cfg_input *req =
432
(struct hwrm_func_vf_cfg_input *)vf->hwrm_cmd_req_addr;
433
434
/* Allow VF to set a valid MAC address, if trust is set to on or
435
* if the PF assigned MAC address is zero
436
*/
437
if (req->enables &
438
cpu_to_le32(HWRM_FUNC_VF_CFG_INPUT_ENABLES_DFLT_MAC_ADDR)) {
439
bool trust = bnxt_is_trusted_vf(softc, vf);
440
441
if (is_valid_ether_addr(req->dflt_mac_addr) &&
442
(trust || !is_valid_ether_addr(vf->mac_addr) ||
443
ether_addr_equal(req->dflt_mac_addr, vf->mac_addr))) {
444
ether_addr_copy(vf->vf_mac_addr, req->dflt_mac_addr);
445
return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
446
}
447
return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
448
}
449
return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
450
}
451
452
static int bnxt_vf_validate_set_mac(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
453
{
454
u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input);
455
struct hwrm_cfa_l2_filter_alloc_input *req =
456
(struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr;
457
bool mac_ok = false;
458
459
if (!is_valid_ether_addr((const u8 *)req->l2_addr))
460
return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
461
462
/* Allow VF to set a valid MAC address, if trust is set to on.
463
* Or VF MAC address must first match MAC address in PF's context.
464
* Otherwise, it must match the VF MAC address if firmware spec >=
465
* 1.2.2
466
*/
467
if (bnxt_is_trusted_vf(softc, vf)) {
468
mac_ok = true;
469
} else if (is_valid_ether_addr(vf->mac_addr)) {
470
if (ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))
471
mac_ok = true;
472
} else if (is_valid_ether_addr(vf->vf_mac_addr)) {
473
if (ether_addr_equal((const u8 *)req->l2_addr, vf->vf_mac_addr))
474
mac_ok = true;
475
} else {
476
mac_ok = true;
477
}
478
if (mac_ok)
479
return bnxt_hwrm_exec_fwd_resp(softc, vf, msg_size);
480
481
return bnxt_hwrm_fwd_err_resp(softc, vf, msg_size);
482
}
483
484
static int bnxt_vf_req_validate_snd(struct bnxt_softc *softc, struct bnxt_vf_info *vf)
485
{
486
int rc = 0;
487
struct input *encap_req = vf->hwrm_cmd_req_addr;
488
u32 req_type = le16_to_cpu(encap_req->req_type);
489
490
switch (req_type) {
491
case HWRM_FUNC_VF_CFG:
492
rc = bnxt_vf_configure_mac(softc, vf);
493
break;
494
case HWRM_CFA_L2_FILTER_ALLOC:
495
rc = bnxt_vf_validate_set_mac(softc, vf);
496
break;
497
case HWRM_FUNC_CFG:
498
rc = bnxt_hwrm_exec_fwd_resp(
499
softc, vf, sizeof(struct hwrm_func_cfg_input));
500
break;
501
case HWRM_PORT_PHY_QCFG:
502
/* ckp todo: Disable set VF link command now, enable it later
503
* Auto neg works as of now.
504
* rc = bnxt_vf_set_link(softc, vf);
505
*/
506
break;
507
default:
508
rc = bnxt_hwrm_fwd_err_resp(softc, vf, softc->hwrm_max_req_len);
509
break;
510
}
511
return rc;
512
}
513
514
void bnxt_hwrm_exec_fwd_req(struct bnxt_softc *softc)
515
{
516
u32 i = 0, active_vfs = softc->pf.active_vfs, vf_id;
517
518
/* Scan through VF's and process commands */
519
while (1) {
520
vf_id = find_next_bit(softc->pf.vf_event_bmap, active_vfs, i);
521
if (vf_id >= active_vfs)
522
break;
523
524
clear_bit(vf_id, softc->pf.vf_event_bmap);
525
bnxt_vf_req_validate_snd(softc, &softc->pf.vf[vf_id]);
526
i = vf_id + 1;
527
}
528
}
529
530
/* destroy VF sysctls when VFs are removed / PF detaches. */
531
void
532
bnxt_destroy_trusted_vf_sysctls(struct bnxt_softc *softc)
533
{
534
sysctl_ctx_free(&softc->pf.sysctl_ctx);
535
}
536
537
/* Handler for: dev.bnxt.<unit>.vf<N>.trusted (0/1) */
538
static int
539
bnxt_sysctl_vf_trusted(SYSCTL_HANDLER_ARGS)
540
{
541
struct bnxt_softc *softc = (struct bnxt_softc *)arg1;
542
int vf_id = (int)arg2;
543
int val, rc;
544
545
BNXT_SRIOV_LOCK(softc);
546
if (softc->pf.num_vfs == 0 || vf_id < 0 || vf_id >= softc->pf.num_vfs) {
547
BNXT_SRIOV_UNLOCK(softc);
548
return (ENOENT);
549
}
550
val = (softc->pf.vf[vf_id].flags & BNXT_VF_TRUST) ? 1 : 0;
551
BNXT_SRIOV_UNLOCK(softc);
552
553
rc = sysctl_handle_int(oidp, &val, 0, req);
554
if (rc)
555
return rc;
556
557
/* If no new value supplied, it was a READ */
558
if (req->newptr == NULL)
559
return 0;
560
561
/* WRITE path: 'val' now holds the user's 0/1 */
562
rc = bnxt_set_vf_trust(softc, vf_id, (val != 0));
563
564
return rc;
565
}
566
567
/*
568
* Create per-VF sysctls:
569
* dev.bnxt.<unit>.vf0.trusted
570
* dev.bnxt.<unit>.vf1.trusted
571
* ..
572
*/
573
int
574
bnxt_create_trusted_vf_sysctls(struct bnxt_softc *softc, uint16_t num_vfs)
575
{
576
struct sysctl_oid_list *root_list;
577
struct sysctl_oid *vf_node;
578
char node_name[16];
579
580
/* use the device's sysctl tree as root: dev.bnxt.<unit>. */
581
sysctl_ctx_init(&softc->pf.sysctl_ctx);
582
root_list = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));
583
584
for (int i = 0; i < num_vfs; i++) {
585
snprintf(node_name, sizeof(node_name), "vf%d", i);
586
587
/* dev.bnxt.<unit>.vfN */
588
vf_node = SYSCTL_ADD_NODE(&softc->pf.sysctl_ctx,
589
root_list, OID_AUTO,
590
node_name, CTLFLAG_RW, 0, "VF node");
591
592
/* dev.bnxt.<unit>.vfN.trusted */
593
SYSCTL_ADD_PROC(&softc->pf.sysctl_ctx,
594
SYSCTL_CHILDREN(vf_node),
595
OID_AUTO, "trusted",
596
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
597
softc, i, bnxt_sysctl_vf_trusted, "I",
598
"0=untrusted (default), 1=trusted");
599
}
600
return 0;
601
}
602
603
static int
604
bnxt_hwrm_set_vf_spoofchk(struct bnxt_softc *sc, struct bnxt_vf_info *vf,
605
bool enable)
606
{
607
struct hwrm_func_cfg_input req = {0};
608
int rc = 0;
609
610
bnxt_hwrm_cmd_hdr_init(sc, &req, HWRM_FUNC_CFG);
611
612
req.fid = htole16(vf->fw_fid);
613
req.flags = htole32(enable ?
614
HWRM_FUNC_CFG_INPUT_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE :
615
HWRM_FUNC_CFG_INPUT_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE);
616
617
BNXT_HWRM_LOCK(sc);
618
rc = _hwrm_send_message(sc, &req, sizeof(req));
619
BNXT_HWRM_UNLOCK(sc);
620
if (rc)
621
device_printf(sc->dev, "bnxt_hwrm_set_vf_spoofchk failed. rc:%d\n", rc);
622
623
return rc;
624
}
625
626
int
627
bnxt_set_vf_spoofchk(struct bnxt_softc *sc, int vf_id, bool enable)
628
{
629
struct bnxt_vf_info *vf;
630
int rc;
631
632
BNXT_SRIOV_LOCK(sc);
633
if (sc->pf.num_vfs == 0 || vf_id >= sc->pf.num_vfs) {
634
BNXT_SRIOV_UNLOCK(sc);
635
return (ENOENT);
636
}
637
vf = &sc->pf.vf[vf_id];
638
BNXT_SRIOV_UNLOCK(sc);
639
640
rc = bnxt_hwrm_set_vf_spoofchk(sc, vf, enable);
641
if (rc == 0) {
642
BNXT_SRIOV_LOCK(sc);
643
if (sc->pf.num_vfs != 0 && vf_id < sc->pf.num_vfs) {
644
vf = &sc->pf.vf[vf_id];
645
if (enable)
646
vf->flags |= BNXT_VF_SPOOFCHK;
647
else
648
vf->flags &= ~BNXT_VF_SPOOFCHK;
649
}
650
BNXT_SRIOV_UNLOCK(sc);
651
}
652
return rc;
653
}
654
655
static int
656
bnxt_sysctl_vf_spoofchk(SYSCTL_HANDLER_ARGS)
657
{
658
struct bnxt_softc *sc = (struct bnxt_softc *)arg1;
659
int vf_id = (int)arg2;
660
int val, rc;
661
662
BNXT_SRIOV_LOCK(sc);
663
if (sc->pf.num_vfs == 0 || vf_id >= sc->pf.num_vfs) {
664
BNXT_SRIOV_UNLOCK(sc);
665
return (ENOENT);
666
}
667
val = (sc->pf.vf[vf_id].flags & BNXT_VF_SPOOFCHK) ? 1 : 0;
668
BNXT_SRIOV_UNLOCK(sc);
669
670
rc = sysctl_handle_int(oidp, &val, 0, req);
671
if (rc || req->newptr == NULL)
672
return rc;
673
674
return bnxt_set_vf_spoofchk(sc, vf_id, val != 0);
675
}
676
677
/*
678
* Create per-VF spoofchk:
679
* dev.bnxt.<unit>.vf0.spoofchk
680
* dev.bnxt.<unit>.vf1.spoofchk
681
* ..
682
*/
683
int
684
bnxt_create_spoofchk_vf_sysctls(struct bnxt_softc *softc, uint16_t num_vfs)
685
{
686
struct sysctl_oid_list *root_list;
687
struct sysctl_oid *vf_node;
688
char node_name[16];
689
690
/* Reuse the same ctx & root tree as trusted vf */
691
root_list = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));
692
693
for (int i = 0; i < num_vfs; i++) {
694
snprintf(node_name, sizeof(node_name), "vf%d", i);
695
696
vf_node = SYSCTL_ADD_NODE(&softc->pf.sysctl_ctx,
697
root_list, OID_AUTO,
698
node_name, CTLFLAG_RW, 0, "VF node");
699
700
SYSCTL_ADD_PROC(&softc->pf.sysctl_ctx,
701
SYSCTL_CHILDREN(vf_node),
702
OID_AUTO, "spoofchk",
703
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
704
softc, i, bnxt_sysctl_vf_spoofchk, "I",
705
"0=spoofchk off, 1=spoofchk on");
706
}
707
return 0;
708
}
709
710
static int
711
bnxt_hwrm_func_vf_resc_cfg(struct bnxt_softc *softc, int num_vfs, bool reset)
712
{
713
struct hwrm_func_vf_resource_cfg_input req = {0};
714
struct bnxt_pf_info *pf = &softc->pf;
715
struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg;
716
struct bnxt_hw_resc *hw_resc = &softc->hw_resc;
717
int i, rc;
718
uint16_t msix_val = 0;
719
720
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_VF_RESOURCE_CFG);
721
struct bnxt_resc_map resc_table[] = {
722
{ &req.min_tx_rings, &req.max_tx_rings, hw_resc->max_tx_rings, fn_qcfg->alloc_tx_rings },
723
{ &req.min_rx_rings, &req.max_rx_rings, hw_resc->max_rx_rings, fn_qcfg->alloc_rx_rings },
724
{ &req.min_cmpl_rings, &req.max_cmpl_rings, hw_resc->max_cp_rings, fn_qcfg->alloc_completion_rings },
725
{ &req.min_stat_ctx, &req.max_stat_ctx, hw_resc->max_stat_ctxs, fn_qcfg->alloc_stat_ctx },
726
{ &req.min_vnics, &req.max_vnics, hw_resc->max_vnics, fn_qcfg->alloc_vnics },
727
{ &req.min_hw_ring_grps, &req.max_hw_ring_grps, hw_resc->max_hw_ring_grps, fn_qcfg->alloc_hw_ring_grps },
728
{ &req.min_rsscos_ctx, &req.max_rsscos_ctx, hw_resc->max_rsscos_ctxs, fn_qcfg->alloc_rss_ctx },
729
{ &req.min_l2_ctxs, &req.max_l2_ctxs, hw_resc->max_l2_ctxs, fn_qcfg->alloc_l2_ctx },
730
};
731
732
for (i = 0; i < sizeof(resc_table) / sizeof(resc_table[0]); i++) {
733
rc = bnxt_set_vf_resc_field(resc_table[i].min_field,
734
resc_table[i].max_field,
735
resc_table[i].hw_max,
736
resc_table[i].pf_alloc,
737
num_vfs);
738
if (rc)
739
return rc;
740
}
741
742
if (hw_resc->max_irqs > fn_qcfg->alloc_msix && num_vfs > 0)
743
msix_val = (hw_resc->max_irqs - fn_qcfg->alloc_msix) / num_vfs;
744
745
req.max_msix = cpu_to_le16(msix_val);
746
747
for (i = 0; i < num_vfs; i++) {
748
struct bnxt_vf_info *vf = &pf->vf[i];
749
750
vf->fw_fid = pf->first_vf_id + i;
751
if (reset) {
752
rc = bnxt_set_vf_params(softc, i);
753
if (rc)
754
break;
755
}
756
757
req.vf_id = cpu_to_le16(vf->fw_fid);
758
759
BNXT_HWRM_LOCK(softc);
760
rc = _hwrm_send_message(softc, &req, sizeof(req));
761
BNXT_HWRM_UNLOCK(softc);
762
763
if (rc) {
764
device_printf(softc->dev, "HWRM_FUNC_VF_RESOURCE_CFG req dump:\n");
765
break;
766
}
767
768
pf->active_vfs = i + 1;
769
770
vf->min_tx_rings = le16_to_cpu(req.min_tx_rings);
771
vf->min_rx_rings = le16_to_cpu(req.min_rx_rings);
772
vf->min_cp_rings = le16_to_cpu(req.min_cmpl_rings);
773
vf->min_stat_ctxs = le16_to_cpu(req.min_stat_ctx);
774
vf->min_ring_grps = le16_to_cpu(req.min_hw_ring_grps);
775
vf->min_vnics = le16_to_cpu(req.min_vnics);
776
}
777
778
if (pf->active_vfs)
779
memcpy(&softc->vf_resc_cfg_input, &req,
780
sizeof(struct hwrm_func_vf_resource_cfg_input));
781
782
return rc;
783
}
784
785
static int
786
bnxt_hwrm_func_buf_rgtr(struct bnxt_softc *softc)
787
{
788
int rc;
789
struct hwrm_func_buf_rgtr_input req;
790
791
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_BUF_RGTR);
792
793
req.req_buf_num_pages = cpu_to_le16(softc->pf.hwrm_cmd_req_pages);
794
req.req_buf_page_size = cpu_to_le16(softc->pf.vf_hwrm_cmd_req_page_shift);
795
req.req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE);
796
req.req_buf_page_addr0 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[0]);
797
req.req_buf_page_addr1 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[1]);
798
req.req_buf_page_addr2 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[2]);
799
req.req_buf_page_addr3 = cpu_to_le64(softc->pf.hwrm_cmd_req_dma_addr[3]);
800
801
BNXT_HWRM_LOCK(softc);
802
rc = _hwrm_send_message(softc, &req, sizeof(req));
803
BNXT_HWRM_UNLOCK(softc);
804
805
return rc;
806
}
807
808
static void
809
bnxt_set_vf_attr(struct bnxt_softc *softc, int num_vfs)
810
{
811
int i;
812
struct bnxt_vf_info *vf;
813
814
for (i = 0; i < num_vfs; i++) {
815
vf = &softc->pf.vf[i];
816
memset(vf, 0, sizeof(*vf));
817
}
818
}
819
820
static int
821
bnxt_alloc_vf_resources(struct bnxt_softc *softc, int num_vfs)
822
{
823
struct pci_dev *pdev = softc->pdev;
824
u32 nr_pages, size, i, j, k = 0;
825
u32 page_size, reqs_per_page;
826
void *p;
827
828
p = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL);
829
if (!p)
830
return ENOMEM;
831
832
rcu_assign_pointer(softc->pf.vf, p);
833
bnxt_set_vf_attr(softc, num_vfs);
834
835
size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE;
836
page_size = BNXT_PAGE_SIZE;
837
softc->pf.vf_hwrm_cmd_req_page_shift = BNXT_PAGE_SHIFT;
838
while (size > page_size * BNXT_MAX_VF_CMD_FWD_PAGES) {
839
page_size *= 2;
840
softc->pf.vf_hwrm_cmd_req_page_shift++;
841
}
842
nr_pages = DIV_ROUND_UP(size, page_size);
843
reqs_per_page = page_size / BNXT_HWRM_REQ_MAX_SIZE;
844
845
for (i = 0; i < nr_pages; i++) {
846
softc->pf.hwrm_cmd_req_addr[i] =
847
dma_alloc_coherent(&pdev->dev, page_size,
848
&softc->pf.hwrm_cmd_req_dma_addr[i],
849
GFP_ATOMIC);
850
851
if (!softc->pf.hwrm_cmd_req_addr[i])
852
return ENOMEM;
853
854
for (j = 0; j < reqs_per_page && k < num_vfs; j++) {
855
struct bnxt_vf_info *vf = &softc->pf.vf[k];
856
857
vf->hwrm_cmd_req_addr = (char *)softc->pf.hwrm_cmd_req_addr[i] +
858
j * BNXT_HWRM_REQ_MAX_SIZE;
859
vf->hwrm_cmd_req_dma_addr =
860
softc->pf.hwrm_cmd_req_dma_addr[i] + j *
861
BNXT_HWRM_REQ_MAX_SIZE;
862
k++;
863
}
864
}
865
866
softc->pf.vf_event_bmap = kzalloc(ALIGN(DIV_ROUND_UP(num_vfs, 8),
867
sizeof(long)), GFP_ATOMIC);
868
if (!softc->pf.vf_event_bmap)
869
return ENOMEM;
870
871
softc->pf.hwrm_cmd_req_pages = nr_pages;
872
873
return 0;
874
}
875
876
int bnxt_cfg_hw_sriov(struct bnxt_softc *softc, uint16_t *num_vfs, bool reset)
877
{
878
int rc;
879
880
rc = bnxt_hwrm_func_buf_rgtr(softc);
881
if (rc) {
882
device_printf(softc->dev, "hwrm func buf rgtr failed (error=%d)\n", rc);
883
return (EIO);
884
}
885
886
rc = bnxt_hwrm_func_vf_resc_cfg(softc, *num_vfs, reset);
887
if (rc) {
888
device_printf(softc->dev, "hwrm func VF resc config failed (error=%d)\n", rc);
889
return (EIO);
890
}
891
892
return (0);
893
}
894
895
int
896
bnxt_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
897
{
898
int rc;
899
if_t ifp = iflib_get_ifp(ctx);
900
struct bnxt_softc *softc = iflib_get_softc(ctx);
901
bool admin_up = !!(if_getflags(ifp) & IFF_UP);
902
bool running = !!(if_getdrvflags(ifp) & IFF_DRV_RUNNING);
903
904
if (!admin_up || !running) {
905
device_printf(softc->dev, "PF is down, rejecting VF creation\n");
906
return ENETDOWN;
907
}
908
909
if (num_vfs > BNXT_MAX_VFS) {
910
device_printf(softc->dev, "Requested %u VFs exceeds maximum supported (%u)\n",
911
num_vfs, BNXT_MAX_VFS);
912
return ERANGE;
913
}
914
915
/*
916
* Initialize SR-IOV lock before creating any SR-IOV state, so sysctl/VF
917
* paths can safely synchronize and error paths can always destroy it.
918
*/
919
BNXT_SRIOV_LOCK_INIT(softc, device_get_nameunit(softc->dev));
920
921
rc = bnxt_alloc_vf_resources(softc, num_vfs);
922
if (rc) {
923
device_printf(softc->dev, "VF resource alloc failed (error=%d)\n", rc);
924
goto fail_lock;
925
}
926
927
rc = bnxt_cfg_hw_sriov(softc, &num_vfs, false);
928
if (rc)
929
goto fail_free_vf_resc;
930
931
rc = bnxt_create_trusted_vf_sysctls(softc, num_vfs);
932
if (rc) {
933
device_printf(softc->dev, "trusted VF sysctl creation failed (error=%d)\n", rc);
934
goto fail_free_hwrm_vf_resc;
935
}
936
937
rc = bnxt_create_spoofchk_vf_sysctls(softc, num_vfs);
938
if (rc) {
939
device_printf(softc->dev, "spoof check VF sysctl creation failed (error=%d)\n", rc);
940
goto fail_free_hwrm_vf_resc;
941
}
942
943
BNXT_SRIOV_LOCK(softc);
944
softc->pf.num_vfs = num_vfs;
945
BNXT_SRIOV_UNLOCK(softc);
946
947
return 0;
948
949
fail_free_hwrm_vf_resc:
950
bnxt_hwrm_func_vf_resource_free(softc, num_vfs);
951
fail_free_vf_resc:
952
bnxt_free_vf_resources(softc);
953
fail_lock:
954
BNXT_SRIOV_LOCK_DESTROY(softc);
955
return rc;
956
}
957
958
void bnxt_sriov_attach(struct bnxt_softc *softc)
959
{
960
int rc;
961
device_t dev = softc->dev;
962
nvlist_t *pf_schema, *vf_schema;
963
964
pf_schema = pci_iov_schema_alloc_node();
965
vf_schema = pci_iov_schema_alloc_node();
966
967
/* Optionally add VF-specific attributes to the VF schema */
968
pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
969
pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", IOV_SCHEMA_HASDEFAULT, FALSE);
970
pci_iov_schema_add_bool(vf_schema, "trust", IOV_SCHEMA_HASDEFAULT, FALSE);
971
972
/* Attach SR-IOV schemas to the device */
973
rc = pci_iov_attach(dev, pf_schema, vf_schema);
974
if (rc)
975
device_printf(dev, "Failed to initialize SR-IOV (error=%d)\n", rc);
976
}
977
978
#else
979
980
void
981
bnxt_sriov_attach(struct bnxt_softc *softc __unused)
982
{
983
}
984
985
int
986
bnxt_cfg_hw_sriov(struct bnxt_softc *softc __unused,
987
uint16_t *num_vfs __unused, bool reset __unused)
988
{
989
return (0);
990
}
991
992
int
993
bnxt_approve_mac(struct bnxt_softc *sc __unused)
994
{
995
return (0);
996
}
997
998
void
999
bnxt_hwrm_exec_fwd_req(struct bnxt_softc *softc __unused)
1000
{
1001
}
1002
1003
bool
1004
bnxt_promisc_ok(struct bnxt_softc *softc __unused)
1005
{
1006
return (true);
1007
}
1008
1009
void
1010
bnxt_update_vf_mac(struct bnxt_softc *sc __unused)
1011
{
1012
}
1013
#endif
1014
1015
void bnxt_reenable_sriov(struct bnxt_softc *bp)
1016
{
1017
if (BNXT_PF(bp)) {
1018
struct bnxt_pf_info *pf = &bp->pf;
1019
uint16_t n = pf->active_vfs;
1020
1021
if (n)
1022
bnxt_cfg_hw_sriov(bp, &n, true);
1023
}
1024
}
1025
1026