Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/bnxt/bnxt_en/bnxt_mgmt.c
39536 views
1
/*
2
* Broadcom NetXtreme-C/E network driver.
3
*
4
* Copyright (c) 2022 Broadcom, All Rights Reserved.
5
* The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26
* THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
#include "bnxt_mgmt.h"
30
#include "bnxt.h"
31
#include "bnxt_hwrm.h"
32
#include <dev/pci/pcireg.h>
33
#include <dev/pci/pcivar.h>
34
#include <sys/endian.h>
35
#include <sys/lock.h>
36
37
/* Function prototypes */
38
static d_open_t bnxt_mgmt_open;
39
static d_close_t bnxt_mgmt_close;
40
static d_ioctl_t bnxt_mgmt_ioctl;
41
42
/* Character device entry points */
43
static struct cdevsw bnxt_mgmt_cdevsw = {
44
.d_version = D_VERSION,
45
.d_open = bnxt_mgmt_open,
46
.d_close = bnxt_mgmt_close,
47
.d_ioctl = bnxt_mgmt_ioctl,
48
.d_name = "bnxt_mgmt",
49
};
50
51
/* Global vars */
52
static struct cdev *bnxt_mgmt_dev;
53
struct mtx mgmt_lock;
54
55
MALLOC_DEFINE(M_BNXT, "bnxt_mgmt_buffer", "buffer for bnxt_mgmt module");
56
57
/*
58
* This function is called by the kld[un]load(2) system calls to
59
* determine what actions to take when a module is loaded or unloaded.
60
*/
61
static int
62
bnxt_mgmt_loader(struct module *m, int what, void *arg)
63
{
64
int error = 0;
65
66
switch (what) {
67
case MOD_LOAD:
68
error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
69
&bnxt_mgmt_dev,
70
&bnxt_mgmt_cdevsw,
71
0,
72
UID_ROOT,
73
GID_WHEEL,
74
0600,
75
"bnxt_mgmt");
76
if (error != 0) {
77
printf("%s: %s:%s:%d Failed to create the"
78
"bnxt_mgmt device node\n", DRIVER_NAME,
79
__FILE__, __FUNCTION__, __LINE__);
80
return (error);
81
}
82
83
mtx_init(&mgmt_lock, "BNXT MGMT Lock", NULL, MTX_DEF);
84
85
break;
86
case MOD_UNLOAD:
87
mtx_destroy(&mgmt_lock);
88
destroy_dev(bnxt_mgmt_dev);
89
break;
90
default:
91
error = EOPNOTSUPP;
92
break;
93
}
94
95
return (error);
96
}
97
98
static int
99
bnxt_mgmt_process_dcb(struct cdev *dev, u_long cmd, caddr_t data,
100
int flag, struct thread *td)
101
{
102
struct bnxt_softc *softc = NULL;
103
struct bnxt_mgmt_dcb mgmt_dcb = {};
104
void *user_ptr;
105
int ret = 0;
106
107
memcpy(&user_ptr, data, sizeof(user_ptr));
108
if (copyin(user_ptr, &mgmt_dcb, sizeof(mgmt_dcb))) {
109
printf("%s: %s:%d Failed to copy data from user\n",
110
DRIVER_NAME, __FUNCTION__, __LINE__);
111
return -EFAULT;
112
}
113
softc = bnxt_find_dev(mgmt_dcb.hdr.domain, mgmt_dcb.hdr.bus,
114
mgmt_dcb.hdr.devfn, NULL);
115
if (!softc) {
116
printf("%s: %s:%d unable to find softc reference\n",
117
DRIVER_NAME, __FUNCTION__, __LINE__);
118
return -ENODEV;
119
}
120
121
switch (mgmt_dcb.op) {
122
case BNXT_MGMT_DCB_GET_ETS:
123
bnxt_dcb_ieee_getets(softc, &mgmt_dcb.req.ets);
124
break;
125
case BNXT_MGMT_DCB_SET_ETS:
126
bnxt_dcb_ieee_setets(softc, &mgmt_dcb.req.ets);
127
break;
128
case BNXT_MGMT_DCB_GET_PFC:
129
bnxt_dcb_ieee_getpfc(softc, &mgmt_dcb.req.pfc);
130
break;
131
case BNXT_MGMT_DCB_SET_PFC:
132
bnxt_dcb_ieee_setpfc(softc, &mgmt_dcb.req.pfc);
133
break;
134
case BNXT_MGMT_DCB_SET_APP:
135
bnxt_dcb_ieee_setapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
136
break;
137
case BNXT_MGMT_DCB_DEL_APP:
138
bnxt_dcb_ieee_delapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
139
break;
140
case BNXT_MGMT_DCB_LIST_APP:
141
bnxt_dcb_ieee_listapp(softc, &mgmt_dcb.req.app_tlv.app[0],
142
nitems(mgmt_dcb.req.app_tlv.app),
143
&mgmt_dcb.req.app_tlv.num_app);
144
break;
145
default:
146
device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
147
__FUNCTION__, __LINE__, mgmt_dcb.op);
148
ret = -EFAULT;
149
goto end;
150
}
151
152
if (copyout(&mgmt_dcb, user_ptr, sizeof(mgmt_dcb))) {
153
device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
154
__FUNCTION__, __LINE__);
155
ret = -EFAULT;
156
goto end;
157
}
158
159
end:
160
return ret;
161
}
162
163
static int
164
bnxt_mgmt_process_hwrm(struct cdev *dev, u_long cmd, caddr_t data,
165
int flag, struct thread *td)
166
{
167
struct bnxt_softc *softc = NULL;
168
struct bnxt_mgmt_req mgmt_req = {};
169
struct bnxt_mgmt_fw_msg msg_temp, *msg, *msg2 = NULL;
170
struct iflib_dma_info dma_data = {};
171
void *user_ptr, *req, *resp;
172
int ret = 0;
173
uint16_t num_ind = 0;
174
175
memcpy(&user_ptr, data, sizeof(user_ptr));
176
if (copyin(user_ptr, &mgmt_req, sizeof(struct bnxt_mgmt_req))) {
177
printf("%s: %s:%d Failed to copy data from user\n",
178
DRIVER_NAME, __FUNCTION__, __LINE__);
179
return -EFAULT;
180
}
181
softc = bnxt_find_dev(mgmt_req.hdr.domain, mgmt_req.hdr.bus,
182
mgmt_req.hdr.devfn, NULL);
183
if (!softc) {
184
printf("%s: %s:%d unable to find softc reference\n",
185
DRIVER_NAME, __FUNCTION__, __LINE__);
186
return -ENODEV;
187
}
188
189
if (copyin((void*)mgmt_req.req.hreq, &msg_temp, sizeof(msg_temp))) {
190
device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
191
__FUNCTION__, __LINE__);
192
return -EFAULT;
193
}
194
195
if (msg_temp.len_req > BNXT_MGMT_MAX_HWRM_REQ_LENGTH ||
196
msg_temp.len_resp > BNXT_MGMT_MAX_HWRM_RESP_LENGTH) {
197
device_printf(softc->dev, "%s:%d Invalid length\n",
198
__FUNCTION__, __LINE__);
199
return -EINVAL;
200
}
201
202
if (msg_temp.num_dma_indications > 1) {
203
device_printf(softc->dev, "%s:%d Max num_dma_indications "
204
"supported is 1 \n", __FUNCTION__, __LINE__);
205
return -EINVAL;
206
}
207
208
req = malloc(msg_temp.len_req, M_BNXT, M_WAITOK | M_ZERO);
209
resp = malloc(msg_temp.len_resp, M_BNXT, M_WAITOK | M_ZERO);
210
211
if (copyin((void *)msg_temp.usr_req, req, msg_temp.len_req)) {
212
device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
213
__FUNCTION__, __LINE__);
214
ret = -EFAULT;
215
goto end;
216
}
217
218
msg = &msg_temp;
219
num_ind = msg_temp.num_dma_indications;
220
if (num_ind) {
221
int size;
222
void *dma_ptr;
223
uint64_t *dmap;
224
225
size = sizeof(struct bnxt_mgmt_fw_msg) +
226
(num_ind * sizeof(struct dma_info));
227
228
msg2 = malloc(size, M_BNXT, M_WAITOK | M_ZERO);
229
230
if (copyin((void *)mgmt_req.req.hreq, msg2, size)) {
231
device_printf(softc->dev, "%s:%d Failed to copy"
232
"data from user\n", __FUNCTION__, __LINE__);
233
ret = -EFAULT;
234
goto end;
235
}
236
msg = msg2;
237
238
ret = iflib_dma_alloc(softc->ctx, msg->dma[0].length, &dma_data,
239
BUS_DMA_NOWAIT);
240
if (ret) {
241
device_printf(softc->dev, "%s:%d iflib_dma_alloc"
242
"failed with ret = 0x%x\n", __FUNCTION__,
243
__LINE__, ret);
244
ret = -ENOMEM;
245
goto end;
246
}
247
248
if (!(msg->dma[0].read_or_write)) {
249
if (copyin((void *)msg->dma[0].data,
250
dma_data.idi_vaddr,
251
msg->dma[0].length)) {
252
device_printf(softc->dev, "%s:%d Failed to copy"
253
"data from user\n", __FUNCTION__,
254
__LINE__);
255
ret = -EFAULT;
256
goto end;
257
}
258
}
259
dma_ptr = (void *) ((uint64_t) req + msg->dma[0].offset);
260
dmap = dma_ptr;
261
*dmap = htole64(dma_data.idi_paddr);
262
}
263
264
ret = bnxt_hwrm_passthrough(softc, req, msg->len_req, resp, msg->len_resp, msg->timeout);
265
if(ret)
266
goto end;
267
268
if (num_ind) {
269
if ((msg->dma[0].read_or_write)) {
270
if (copyout(dma_data.idi_vaddr,
271
(void *)msg->dma[0].data,
272
msg->dma[0].length)) {
273
device_printf(softc->dev, "%s:%d Failed to copy data"
274
"to user\n", __FUNCTION__, __LINE__);
275
ret = -EFAULT;
276
goto end;
277
}
278
}
279
}
280
281
if (copyout(resp, (void *) msg->usr_resp, msg->len_resp)) {
282
device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
283
__FUNCTION__, __LINE__);
284
ret = -EFAULT;
285
goto end;
286
}
287
288
end:
289
if (req)
290
free(req, M_BNXT);
291
if (resp)
292
free(resp, M_BNXT);
293
if (msg2)
294
free(msg2, M_BNXT);
295
if (dma_data.idi_paddr)
296
iflib_dma_free(&dma_data);
297
return ret;
298
}
299
300
static int
301
bnxt_mgmt_get_dev_info(struct cdev *dev, u_long cmd, caddr_t data,
302
int flag, struct thread *td)
303
{
304
struct bnxt_softc *softc = NULL;
305
struct bnxt_dev_info dev_info;
306
void *user_ptr;
307
uint32_t dev_sn_lo, dev_sn_hi;
308
int dev_sn_offset = 0;
309
char dsn[16];
310
uint16_t lnk;
311
int capreg;
312
313
memcpy(&user_ptr, data, sizeof(user_ptr));
314
if (copyin(user_ptr, &dev_info, sizeof(dev_info))) {
315
printf("%s: %s:%d Failed to copy data from user\n",
316
DRIVER_NAME, __FUNCTION__, __LINE__);
317
return -EFAULT;
318
}
319
320
softc = bnxt_find_dev(0, 0, 0, dev_info.nic_info.dev_name);
321
if (!softc) {
322
printf("%s: %s:%d unable to find softc reference\n",
323
DRIVER_NAME, __FUNCTION__, __LINE__);
324
return -ENODEV;
325
}
326
327
strncpy(dev_info.nic_info.driver_version, bnxt_driver_version, 64);
328
strncpy(dev_info.nic_info.driver_name, device_get_name(softc->dev), 64);
329
dev_info.pci_info.domain_no = softc->domain;
330
dev_info.pci_info.bus_no = softc->bus;
331
dev_info.pci_info.device_no = softc->slot;
332
dev_info.pci_info.function_no = softc->function;
333
dev_info.pci_info.vendor_id = pci_get_vendor(softc->dev);
334
dev_info.pci_info.device_id = pci_get_device(softc->dev);
335
dev_info.pci_info.sub_system_vendor_id = pci_get_subvendor(softc->dev);
336
dev_info.pci_info.sub_system_device_id = pci_get_subdevice(softc->dev);
337
dev_info.pci_info.revision = pci_read_config(softc->dev, PCIR_REVID, 1);
338
dev_info.pci_info.chip_rev_id = (dev_info.pci_info.device_id << 16);
339
dev_info.pci_info.chip_rev_id |= dev_info.pci_info.revision;
340
if (pci_find_extcap(softc->dev, PCIZ_SERNUM, &dev_sn_offset)) {
341
device_printf(softc->dev, "%s:%d device serial number is not found"
342
"or not supported\n", __FUNCTION__, __LINE__);
343
} else {
344
dev_sn_lo = pci_read_config(softc->dev, dev_sn_offset + 4, 4);
345
dev_sn_hi = pci_read_config(softc->dev, dev_sn_offset + 8, 4);
346
snprintf(dsn, sizeof(dsn), "%02x%02x%02x%02x%02x%02x%02x%02x",
347
(dev_sn_lo & 0x000000FF),
348
(dev_sn_lo >> 8) & 0x0000FF,
349
(dev_sn_lo >> 16) & 0x00FF,
350
(dev_sn_lo >> 24 ) & 0xFF,
351
(dev_sn_hi & 0x000000FF),
352
(dev_sn_hi >> 8) & 0x0000FF,
353
(dev_sn_hi >> 16) & 0x00FF,
354
(dev_sn_hi >> 24 ) & 0xFF);
355
strncpy(dev_info.nic_info.device_serial_number, dsn, sizeof(dsn));
356
}
357
358
if_t ifp = iflib_get_ifp(softc->ctx);
359
dev_info.nic_info.mtu = if_getmtu(ifp);
360
memcpy(dev_info.nic_info.mac, softc->func.mac_addr, ETHER_ADDR_LEN);
361
362
if (pci_find_cap(softc->dev, PCIY_EXPRESS, &capreg)) {
363
device_printf(softc->dev, "%s:%d pci link capability is not found"
364
"or not supported\n", __FUNCTION__, __LINE__);
365
} else {
366
lnk = pci_read_config(softc->dev, capreg + PCIER_LINK_STA, 2);
367
dev_info.nic_info.pci_link_speed = (lnk & PCIEM_LINK_STA_SPEED);
368
dev_info.nic_info.pci_link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
369
}
370
371
if (copyout(&dev_info, user_ptr, sizeof(dev_info))) {
372
device_printf(softc->dev, "%s:%d Failed to copy data to user\n",
373
__FUNCTION__, __LINE__);
374
return -EFAULT;
375
}
376
377
return 0;
378
}
379
380
/*
381
* IOCTL entry point.
382
*/
383
static int
384
bnxt_mgmt_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
385
struct thread *td)
386
{
387
int ret = 0;
388
389
switch(cmd) {
390
case BNXT_MGMT_OPCODE_GET_DEV_INFO:
391
ret = bnxt_mgmt_get_dev_info(dev, cmd, data, flag, td);
392
break;
393
case BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
394
mtx_lock(&mgmt_lock);
395
ret = bnxt_mgmt_process_hwrm(dev, cmd, data, flag, td);
396
mtx_unlock(&mgmt_lock);
397
break;
398
case BNXT_MGMT_OPCODE_DCB_OPS:
399
ret = bnxt_mgmt_process_dcb(dev, cmd, data, flag, td);
400
break;
401
default:
402
printf("%s: Unknown command 0x%lx\n", DRIVER_NAME, cmd);
403
ret = -EINVAL;
404
break;
405
}
406
407
return ret;
408
}
409
410
static int
411
bnxt_mgmt_close(struct cdev *dev, int flags, int devtype, struct thread *td)
412
{
413
return (0);
414
}
415
416
static int
417
bnxt_mgmt_open(struct cdev *dev, int flags, int devtype, struct thread *td)
418
{
419
return (0);
420
}
421
422
DEV_MODULE(bnxt_mgmt, bnxt_mgmt_loader, NULL);
423
424
425