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 "bnxt_coredump.h"
33 #include "bnxt_log.h"
34 #include <dev/pci/pcireg.h>
35 #include <dev/pci/pcivar.h>
36 #include <sys/endian.h>
37 #include <sys/lock.h>
38
39 /* Function prototypes */
40 static d_open_t bnxt_mgmt_open;
41 static d_close_t bnxt_mgmt_close;
42 static d_ioctl_t bnxt_mgmt_ioctl;
43
44 /* Character device entry points */
45 static struct cdevsw bnxt_mgmt_cdevsw = {
46 .d_version = D_VERSION,
47 .d_open = bnxt_mgmt_open,
48 .d_close = bnxt_mgmt_close,
49 .d_ioctl = bnxt_mgmt_ioctl,
50 .d_name = "bnxt_mgmt",
51 };
52
53 /* Global vars */
54 static struct cdev *bnxt_mgmt_dev;
55 struct sx mgmt_lock;
56
57 MALLOC_DEFINE(M_BNXT, "bnxt_mgmt_buffer", "buffer for bnxt_mgmt module");
58
59
60 static uint32_t
bnxt_get_driver_coredump_len(struct bnxt_softc * softc)61 bnxt_get_driver_coredump_len(struct bnxt_softc *softc)
62 {
63
64 uint32_t type, i, j, n;
65 uint32_t buf_size = 0;
66 int ctx_page_count = 0;
67 int segment_len = 0;
68 int driver_segment_record_len = 0;
69 uint32_t dump_len = 0;
70 int record_len = sizeof(struct bnxt_driver_segment_record);
71 struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
72
73 if (!ctx)
74 return (dump_len);
75
76 for (type = BNXT_CTX_SRT_TRACE; type <= BNXT_CTX_ROCE_HWRM_TRACE;
77 type++) {
78 struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
79 struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
80
81 if (!ctx_pg)
82 continue;
83
84 if (ctxm->instance_bmap)
85 n = bitcount32(ctxm->instance_bmap);
86 else
87 n = 1;
88
89 for (i = 0; i < n; i++) {
90 struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
91
92 if (ctx_pg->nr_pages > MAX_CTX_PAGES ||
93 ctx_pg->ctx_pg_tbl) {
94 int k = 0, nr_tbls = rmem->nr_pages;
95
96 for (k = 0; k < nr_tbls; k++) {
97 struct bnxt_ctx_pg_info *pg_tbl;
98 struct bnxt_ring_mem_info *rmem2;
99
100 pg_tbl = ctx_pg->ctx_pg_tbl[k];
101 if (!pg_tbl)
102 continue;
103 rmem2 = &pg_tbl->ring_mem;
104 for (j = 0; j < rmem2->nr_pages; j++) {
105 if (!rmem2->pg_arr[j].idi_vaddr)
106 continue;
107 ctx_page_count++;
108 }
109 }
110 } else {
111 struct bnxt_ring_mem_info *rmem2 = rmem;
112
113 for (j = 0; j < rmem2->nr_pages; j++) {
114 if (!rmem2->pg_arr[j].idi_vaddr)
115 continue;
116 ctx_page_count++;
117 }
118 }
119 }
120 segment_len += 64;
121 driver_segment_record_len += record_len;
122 }
123
124 buf_size = driver_segment_record_len + segment_len +
125 (ctx_page_count * 4096);
126
127 return (buf_size);
128 }
129
130 inline void
bnxt_bs_trace_check_wrapping(struct bnxt_bs_trace_info * bs_trace,u32 offset)131 bnxt_bs_trace_check_wrapping(struct bnxt_bs_trace_info *bs_trace,
132 u32 offset)
133 {
134 if (!bs_trace->wrapped &&
135 *bs_trace->magic_byte != BNXT_TRACE_BUF_MAGIC_BYTE)
136 bs_trace->wrapped = 1;
137 bs_trace->last_offset = offset;
138 }
139
140
141
142 static int
bnxt_hwrm_dbg_log_buffer_flush(struct bnxt_softc * bp,u16 type,u32 flags,u32 * offset)143 bnxt_hwrm_dbg_log_buffer_flush(struct bnxt_softc *bp, u16 type, u32 flags,
144 u32 *offset)
145 {
146 int status = 0;
147
148 hwrm_dbg_log_buffer_flush_input_t buff_flush_req;
149 hwrm_dbg_log_buffer_flush_output_t *buff_flush_resp =
150 (hwrm_dbg_log_buffer_flush_output_t *)(void *)
151 bp->hwrm_cmd_resp.idi_vaddr;
152 bnxt_hwrm_cmd_hdr_init(bp, &buff_flush_req, HWRM_DBG_LOG_BUFFER_FLUSH);
153 buff_flush_req.type = type;
154 buff_flush_req.flags = flags;
155
156 status = hwrm_send_message(bp, &buff_flush_req, sizeof(buff_flush_req));
157 if (!status)
158 *offset = buff_flush_resp->current_buffer_offset;
159 return (status);
160 }
161
162 static void
bnxt_fill_driver_segment_record(struct bnxt_softc * bp,struct bnxt_driver_segment_record * drv_seg_rec,struct bnxt_ctx_mem_type * ctxm,uint16_t type)163 bnxt_fill_driver_segment_record(struct bnxt_softc *bp,
164 struct bnxt_driver_segment_record *drv_seg_rec,
165 struct bnxt_ctx_mem_type *ctxm, uint16_t type)
166 {
167 struct bnxt_bs_trace_info *bs_trace = &bp->bs_trace[type];
168 uint32_t offset;
169
170 if (bnxt_hwrm_dbg_log_buffer_flush(bp, type, 0, &offset) == 0) {
171 bnxt_bs_trace_check_wrapping(bs_trace, offset);
172 }
173 drv_seg_rec->max_entries = ctxm->max_entries;
174 drv_seg_rec->entry_size = ctxm->entry_size;
175 drv_seg_rec->offset = bs_trace->last_offset;
176 drv_seg_rec->wrapped = bs_trace->wrapped;
177 }
178
179 static void
bnxt_retrieve_driver_coredump(struct bnxt_softc * softc,void * buf,uint16_t type,uint32_t * seg_len)180 bnxt_retrieve_driver_coredump(struct bnxt_softc *softc, void *buf,
181 uint16_t type, uint32_t *seg_len)
182 {
183 struct bnxt_driver_segment_record drv_seg_rec = {0};
184 struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
185 struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
186 struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
187 uint32_t dump_len, data_offset, record_len, seg_hdr_len;
188 uint32_t i, j, k, n = 1, nr_tbls;
189
190 dump_len = 0;
191
192 record_len = sizeof(struct bnxt_driver_segment_record);
193 seg_hdr_len = sizeof(struct bnxt_coredump_segment_hdr);
194 data_offset = seg_hdr_len + record_len;
195
196 bnxt_fill_driver_segment_record(softc, &drv_seg_rec, ctxm,
197 (type - BNXT_CTX_SRT_TRACE));
198
199 for (i = 0; i < n; i++) {
200 struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
201
202 if (ctx_pg->nr_pages > MAX_CTX_PAGES || ctx_pg->ctx_pg_tbl) {
203 nr_tbls = rmem->nr_pages;
204 for (j = 0; j < nr_tbls; j++) {
205 struct bnxt_ctx_pg_info *pg_tbl;
206 struct bnxt_ring_mem_info *rmem2;
207
208 pg_tbl = ctx_pg->ctx_pg_tbl[j];
209 if (!pg_tbl)
210 continue;
211 rmem2 = &pg_tbl->ring_mem;
212 for (k = 0; k < rmem2->nr_pages; k++) {
213 if (!rmem2->pg_arr[k].idi_vaddr)
214 continue;
215 memcpy((uint8_t *)buf + data_offset,
216 rmem2->pg_arr[k].idi_vaddr,
217 rmem2->page_size);
218 data_offset += rmem2->page_size;
219 dump_len += rmem2->page_size;
220 }
221 }
222 } else {
223 for (k = 0; k < rmem->nr_pages; k++) {
224 if (!rmem->pg_arr[k].idi_vaddr)
225 continue;
226 memcpy((uint8_t *)buf + data_offset,
227 rmem->pg_arr[k].idi_vaddr,
228 rmem->page_size);
229 data_offset += rmem->page_size;
230 dump_len += rmem->page_size;
231 }
232 }
233 }
234 memcpy((uint8_t *)buf + seg_hdr_len, &drv_seg_rec, record_len);
235 *seg_len = dump_len + record_len;
236 }
237
238 void
bnxt_get_ctx_coredump(struct bnxt_softc * softc,void * buf)239 bnxt_get_ctx_coredump(struct bnxt_softc *softc, void *buf)
240 {
241 struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
242 struct bnxt_coredump_segment_hdr seg_hdr;
243 uint32_t type = 0, i = 0;
244 uint32_t seg_hdr_len = 0;
245
246 seg_hdr_len = sizeof(seg_hdr);
247 for (type = BNXT_CTX_SRT_TRACE, i = DRV_SRT_TRACE_SEG_ID;
248 type <= BNXT_CTX_ROCE_HWRM_TRACE; type++, i++) {
249 struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
250 uint16_t comp_id = DRV_COREDUMP_COMP_ID;
251 uint16_t seg_id = i;
252 uint32_t seg_len = 0;
253
254 ctxm = &ctx->ctx_arr[type];
255
256 if (!(ctxm->flags & BNXT_CTX_MEM_TYPE_VALID) ||
257 !ctxm->mem_valid)
258 continue;
259
260 bnxt_retrieve_driver_coredump(softc, buf, type, &seg_len);
261
262 bnxt_fill_coredump_seg_hdr(softc, &seg_hdr, NULL, seg_len,
263 0, 0, 0, comp_id, seg_id);
264
265 memcpy((uint8_t *)buf, &seg_hdr, seg_hdr_len);
266 buf = (uint8_t *)buf + seg_hdr_len + seg_len;
267 }
268 }
269
270 /* DDR Crash Dump IOCTL handler */
271 static int
bnxt_mgmt_crash_dump(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)272 bnxt_mgmt_crash_dump(struct cdev *dev, u_long cmd, caddr_t data,
273 int flag, struct thread *td)
274 {
275 struct bnxt_softc *softc = NULL;
276 struct bnxt_mgmt_crash_dump mgmt_crash_dump = {0};
277 void *user_ptr;
278 int ret = 0;
279 void *dump_buf = NULL;
280 uint32_t dump_len;
281
282 memcpy(&user_ptr, data, sizeof(user_ptr));
283 if (copyin(user_ptr, &mgmt_crash_dump, sizeof(mgmt_crash_dump))) {
284 printf("%s: %s:%d Failed to copy data from user\n",
285 DRIVER_NAME, __func__, __LINE__);
286 return (-EFAULT);
287 }
288 softc = bnxt_find_dev(mgmt_crash_dump.hdr.domain,
289 mgmt_crash_dump.hdr.bus,
290 mgmt_crash_dump.hdr.devfn, NULL);
291 if (!softc) {
292 printf("%s: %s:%d unable to find softc reference\n",
293 DRIVER_NAME, __func__, __LINE__);
294 return (-ENODEV);
295 }
296
297 switch (mgmt_crash_dump.op) {
298 case BNXT_MGMT_SET_DUMP_FLAG:
299 if (mgmt_crash_dump.req.set_flag.dump_flag >
300 BNXT_DUMP_LIVE_WITH_CTX_L1_CACHE) {
301 device_printf(softc->dev,
302 "Supports only Live(0), Crash(1), Driver(2), "
303 "Live with cached context(3) dumps.\n");
304 ret = -EINVAL;
305 break;
306 }
307
308 if (mgmt_crash_dump.req.set_flag.dump_flag == BNXT_DUMP_CRASH) {
309 if (softc->fw_dbg_cap & BNXT_FW_DBG_CAP_CRASHDUMP_SOC) {
310 device_printf(softc->dev,
311 "Cannot collect crash dump as TEE is not supported.\n");
312 ret = -ENOTSUP;
313 break;
314 } else if (!(softc->fw_dbg_cap &
315 BNXT_FW_DBG_CAP_CRASHDUMP_HOST)) {
316 device_printf(softc->dev,
317 "FW does not support crash dump collection.\n");
318 ret = -ENOTSUP;
319 break;
320 }
321 }
322
323 softc->dump_flag = mgmt_crash_dump.req.set_flag.dump_flag;
324 break;
325
326 case BNXT_MGMT_GET_DUMP_FLAG:
327 if (softc->hwrm_spec_code < 0x10801) {
328 ret = -ENOTSUP;
329 break;
330 }
331
332 /* Build FW version - same as Linux bnxt_get_dump_flag() */
333 mgmt_crash_dump.req.get_flag.version =
334 (softc->ver_resp.hwrm_fw_maj_8b << 24) |
335 (softc->ver_resp.hwrm_fw_min_8b << 16) |
336 (softc->ver_resp.hwrm_fw_bld_8b << 8) |
337 (softc->ver_resp.hwrm_fw_rsvd_8b);
338
339 mgmt_crash_dump.req.get_flag.dump_flag = softc->dump_flag;
340 mgmt_crash_dump.req.get_flag.dump_len =
341 bnxt_get_coredump_length(softc, softc->dump_flag);
342 break;
343
344 case BNXT_MGMT_GET_DUMP_DATA:
345 if (softc->hwrm_spec_code < 0x10801) {
346 ret = -ENOTSUP;
347 break;
348 }
349
350 dump_len = bnxt_get_coredump_length(softc,
351 mgmt_crash_dump.req.get_data.dump_flag);
352 if (dump_len == 0) {
353 device_printf(softc->dev, "No dump data available\n");
354 ret = -ENOENT;
355 break;
356 }
357
358 if (mgmt_crash_dump.req.get_data.buffer_size < dump_len) {
359 device_printf(softc->dev,
360 "Buffer too small: need %u bytes, got %zu bytes\n",
361 dump_len, mgmt_crash_dump.req.get_data.buffer_size);
362 mgmt_crash_dump.req.get_data.dump_len = dump_len;
363 ret = -ENOSPC;
364 break;
365 }
366
367 dump_buf = malloc(dump_len, M_BNXT, M_WAITOK);
368 if (!dump_buf) {
369 ret = -ENOMEM;
370 break;
371 }
372
373 ret = bnxt_get_coredump(softc,
374 mgmt_crash_dump.req.get_data.dump_flag,
375 dump_buf, &dump_len);
376 if (ret) {
377 device_printf(softc->dev,
378 "Failed to get coredump: %d\n", ret);
379 free(dump_buf, M_BNXT);
380 break;
381 }
382
383 if (copyout(dump_buf,
384 mgmt_crash_dump.req.get_data.dump_buffer, dump_len)) {
385 device_printf(softc->dev,
386 "%s:%d Failed to copy dump data to user\n",
387 __func__, __LINE__);
388 ret = -EFAULT;
389 free(dump_buf, M_BNXT);
390 break;
391 }
392
393 mgmt_crash_dump.req.get_data.dump_len = dump_len;
394 mgmt_crash_dump.req.get_data.dump_flag = softc->dump_flag;
395 free(dump_buf, M_BNXT);
396 break;
397
398 default:
399 device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
400 __func__, __LINE__, mgmt_crash_dump.op);
401 ret = -EFAULT;
402 break;
403 }
404
405 if (!ret && copyout(&mgmt_crash_dump, user_ptr,
406 sizeof(mgmt_crash_dump))) {
407 device_printf(softc->dev,
408 "%s:%d Failed to copy response to user\n",
409 __func__, __LINE__);
410 ret = -EFAULT;
411 }
412
413 return (ret);
414 }
415
416 /*
417 * This function is called by the kld[un]load(2) system calls to
418 * determine what actions to take when a module is loaded or unloaded.
419 */
420 static int
bnxt_mgmt_loader(struct module * m,int what,void * arg)421 bnxt_mgmt_loader(struct module *m, int what, void *arg)
422 {
423 int error = 0;
424
425 switch (what) {
426 case MOD_LOAD:
427 error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
428 &bnxt_mgmt_dev,
429 &bnxt_mgmt_cdevsw,
430 0,
431 UID_ROOT,
432 GID_WHEEL,
433 0600,
434 "bnxt_mgmt");
435 if (error != 0) {
436 printf("%s: %s:%s:%d Failed to create the"
437 "bnxt_mgmt device node\n", DRIVER_NAME,
438 __FILE__, __func__, __LINE__);
439 return (error);
440 }
441
442 sx_init(&mgmt_lock, "BNXT MGMT Lock");
443
444 break;
445 case MOD_UNLOAD:
446 sx_destroy(&mgmt_lock);
447 destroy_dev(bnxt_mgmt_dev);
448 break;
449 default:
450 error = EOPNOTSUPP;
451 break;
452 }
453
454 return (error);
455 }
456
457 static int
bnxt_mgmt_process_dcb(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)458 bnxt_mgmt_process_dcb(struct cdev *dev, u_long cmd, caddr_t data,
459 int flag, struct thread *td)
460 {
461 struct bnxt_softc *softc = NULL;
462 struct bnxt_mgmt_dcb mgmt_dcb = {};
463 void *user_ptr;
464 int ret = 0;
465
466 memcpy(&user_ptr, data, sizeof(user_ptr));
467 if (copyin(user_ptr, &mgmt_dcb, sizeof(mgmt_dcb))) {
468 printf("%s: %s:%d Failed to copy data from user\n",
469 DRIVER_NAME, __func__, __LINE__);
470 return -EFAULT;
471 }
472 softc = bnxt_find_dev(mgmt_dcb.hdr.domain, mgmt_dcb.hdr.bus,
473 mgmt_dcb.hdr.devfn, NULL);
474 if (!softc) {
475 printf("%s: %s:%d unable to find softc reference\n",
476 DRIVER_NAME, __func__, __LINE__);
477 return -ENODEV;
478 }
479
480 switch (mgmt_dcb.op) {
481 case BNXT_MGMT_DCB_GET_ETS:
482 bnxt_dcb_ieee_getets(softc, &mgmt_dcb.req.ets);
483 break;
484 case BNXT_MGMT_DCB_SET_ETS:
485 bnxt_dcb_ieee_setets(softc, &mgmt_dcb.req.ets);
486 break;
487 case BNXT_MGMT_DCB_GET_PFC:
488 bnxt_dcb_ieee_getpfc(softc, &mgmt_dcb.req.pfc);
489 break;
490 case BNXT_MGMT_DCB_SET_PFC:
491 bnxt_dcb_ieee_setpfc(softc, &mgmt_dcb.req.pfc);
492 break;
493 case BNXT_MGMT_DCB_SET_APP:
494 bnxt_dcb_ieee_setapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
495 break;
496 case BNXT_MGMT_DCB_DEL_APP:
497 bnxt_dcb_ieee_delapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
498 break;
499 case BNXT_MGMT_DCB_LIST_APP:
500 bnxt_dcb_ieee_listapp(softc, &mgmt_dcb.req.app_tlv.app[0],
501 nitems(mgmt_dcb.req.app_tlv.app),
502 &mgmt_dcb.req.app_tlv.num_app);
503 break;
504 default:
505 device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
506 __func__, __LINE__, mgmt_dcb.op);
507 ret = -EFAULT;
508 goto end;
509 }
510
511 if (copyout(&mgmt_dcb, user_ptr, sizeof(mgmt_dcb))) {
512 device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
513 __func__, __LINE__);
514 ret = -EFAULT;
515 goto end;
516 }
517
518 end:
519 return ret;
520 }
521
522 static int
bnxt_mgmt_process_hwrm(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)523 bnxt_mgmt_process_hwrm(struct cdev *dev, u_long cmd, caddr_t data,
524 int flag, struct thread *td)
525 {
526 struct bnxt_softc *softc = NULL;
527 struct bnxt_mgmt_req mgmt_req = {};
528 struct bnxt_mgmt_fw_msg msg_temp, *msg, *msg2 = NULL;
529 void *user_ptr, *req, *resp;
530 int ret = 0, num_allocated = 0, i;
531 uint16_t num_ind = 0;
532
533 memcpy(&user_ptr, data, sizeof(user_ptr));
534 if (copyin(user_ptr, &mgmt_req, sizeof(struct bnxt_mgmt_req))) {
535 printf("%s: %s:%d Failed to copy data from user\n",
536 DRIVER_NAME, __func__, __LINE__);
537 return -EFAULT;
538 }
539 softc = bnxt_find_dev(mgmt_req.hdr.domain, mgmt_req.hdr.bus,
540 mgmt_req.hdr.devfn, NULL);
541 if (!softc) {
542 printf("%s: %s:%d unable to find softc reference\n",
543 DRIVER_NAME, __func__, __LINE__);
544 return -ENODEV;
545 }
546
547 if (copyin((void*)mgmt_req.req.hreq, &msg_temp, sizeof(msg_temp))) {
548 device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
549 __func__, __LINE__);
550 return -EFAULT;
551 }
552
553 if (msg_temp.len_req > BNXT_MGMT_MAX_HWRM_REQ_LENGTH ||
554 msg_temp.len_resp > BNXT_MGMT_MAX_HWRM_RESP_LENGTH) {
555 device_printf(softc->dev, "%s:%d Invalid length\n",
556 __func__, __LINE__);
557 return -EINVAL;
558 }
559
560 if (msg_temp.num_dma_indications > MAX_NUM_DMA_INDICATIONS) {
561 device_printf(softc->dev, "%s:%d Max num_dma_indications "
562 "supported is %d\n", __func__, __LINE__,
563 MAX_NUM_DMA_INDICATIONS);
564 return -EINVAL;
565 }
566
567 req = malloc(msg_temp.len_req, M_BNXT, M_WAITOK | M_ZERO);
568 resp = malloc(msg_temp.len_resp, M_BNXT, M_WAITOK | M_ZERO);
569
570 if (copyin((void *)msg_temp.usr_req, req, msg_temp.len_req)) {
571 device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
572 __func__, __LINE__);
573 ret = -EFAULT;
574 goto end;
575 }
576
577 msg = &msg_temp;
578 num_ind = msg_temp.num_dma_indications;
579 if (num_ind) {
580 int size;
581 void *dma_ptr;
582 uint64_t *dmap;
583
584 size = sizeof(struct bnxt_mgmt_fw_msg) +
585 (num_ind * sizeof(struct dma_info));
586
587 msg2 = malloc(size, M_BNXT, M_WAITOK | M_ZERO);
588
589 if (copyin((void *)mgmt_req.req.hreq, msg2, size)) {
590 device_printf(softc->dev, "%s:%d Failed to copy"
591 "data from user\n", __func__, __LINE__);
592 ret = -EFAULT;
593 goto end;
594 }
595 msg = msg2;
596
597 for (i = 0; i < num_ind; i++) {
598
599 if (msg->dma[i].length == 0) {
600 device_printf(softc->dev,
601 "%s:%d i:%d Invalid DMA memory length\n",
602 __func__, __LINE__, i);
603 ret = -ENOMEM;
604 goto end;
605 }
606
607 memset(&softc->mgmt_dma_data[i], 0, sizeof(struct iflib_dma_info));
608
609 ret = iflib_dma_alloc(softc->ctx, msg->dma[i].length, &softc->mgmt_dma_data[i],
610 BUS_DMA_WAITOK);
611 if (ret) {
612 device_printf(softc->dev,
613 "%s:%d iflib_dma_alloc failed with ret = 0x%x\n",
614 __func__, __LINE__, ret);
615 ret = -ENOMEM;
616 goto end;
617 }
618
619 num_allocated++;
620 if (!(msg->dma[i].read_or_write)) {
621 if (copyin((void *)msg->dma[i].data,
622 softc->mgmt_dma_data[i].idi_vaddr,
623 msg->dma[i].length)) {
624 device_printf(softc->dev,
625 "%s:%d Failed to copy data from user\n",
626 __func__, __LINE__);
627 ret = -EFAULT;
628 goto end;
629 }
630 }
631 dma_ptr = (void *) ((uint64_t) req + msg->dma[i].offset);
632 dmap = dma_ptr;
633 *dmap = htole64(softc->mgmt_dma_data[i].idi_paddr);
634 }
635 }
636
637 ret = bnxt_hwrm_passthrough(softc, req, msg->len_req, resp, msg->len_resp, msg->timeout);
638 if (ret)
639 goto end;
640
641 for (i = 0; i < num_ind; i++) {
642 if ((msg->dma[i].read_or_write)) {
643 if (copyout(softc->mgmt_dma_data[i].idi_vaddr,
644 (void *)msg->dma[i].data,
645 msg->dma[i].length)) {
646 device_printf(softc->dev,
647 "%s:%d Failed to copy data to user\n",
648 __func__, __LINE__);
649 ret = -EFAULT;
650 goto end;
651 }
652 }
653 }
654
655 if (copyout(resp, (void *) msg->usr_resp, msg->len_resp)) {
656 device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
657 __func__, __LINE__);
658 ret = -EFAULT;
659 goto end;
660 }
661
662 end:
663 if (req)
664 free(req, M_BNXT);
665 if (resp)
666 free(resp, M_BNXT);
667 if (msg2)
668 free(msg2, M_BNXT);
669 if (num_allocated) {
670 for (i = 0; i < num_allocated; i++)
671 if (softc->mgmt_dma_data[i].idi_paddr)
672 iflib_dma_free(&softc->mgmt_dma_data[i]);
673 }
674 return ret;
675 }
676
677 static int
bnxt_mgmt_get_dev_info(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)678 bnxt_mgmt_get_dev_info(struct cdev *dev, u_long cmd, caddr_t data,
679 int flag, struct thread *td)
680 {
681 struct bnxt_softc *softc = NULL;
682 struct bnxt_dev_info dev_info;
683 void *user_ptr;
684 uint32_t dev_sn_lo, dev_sn_hi;
685 int dev_sn_offset = 0;
686 char dsn[16];
687 uint16_t lnk;
688 int capreg;
689
690 memcpy(&user_ptr, data, sizeof(user_ptr));
691 if (copyin(user_ptr, &dev_info, sizeof(dev_info))) {
692 printf("%s: %s:%d Failed to copy data from user\n",
693 DRIVER_NAME, __func__, __LINE__);
694 return -EFAULT;
695 }
696
697 softc = bnxt_find_dev(0, 0, 0, dev_info.nic_info.dev_name);
698 if (!softc) {
699 printf("%s: %s:%d unable to find softc reference\n",
700 DRIVER_NAME, __func__, __LINE__);
701 return -ENODEV;
702 }
703
704 strncpy(dev_info.nic_info.driver_version, bnxt_driver_version, 64);
705 strncpy(dev_info.nic_info.driver_name, device_get_name(softc->dev), 64);
706 dev_info.pci_info.domain_no = softc->domain;
707 dev_info.pci_info.bus_no = softc->bus;
708 dev_info.pci_info.device_no = softc->slot;
709 dev_info.pci_info.function_no = softc->function;
710 dev_info.pci_info.vendor_id = pci_get_vendor(softc->dev);
711 dev_info.pci_info.device_id = pci_get_device(softc->dev);
712 dev_info.pci_info.sub_system_vendor_id = pci_get_subvendor(softc->dev);
713 dev_info.pci_info.sub_system_device_id = pci_get_subdevice(softc->dev);
714 dev_info.pci_info.revision = pci_read_config(softc->dev, PCIR_REVID, 1);
715 dev_info.pci_info.chip_rev_id = (dev_info.pci_info.device_id << 16);
716 dev_info.pci_info.chip_rev_id |= dev_info.pci_info.revision;
717 if (pci_find_extcap(softc->dev, PCIZ_SERNUM, &dev_sn_offset)) {
718 device_printf(softc->dev, "%s:%d device serial number is not found"
719 "or not supported\n", __func__, __LINE__);
720 } else {
721 dev_sn_lo = pci_read_config(softc->dev, dev_sn_offset + 4, 4);
722 dev_sn_hi = pci_read_config(softc->dev, dev_sn_offset + 8, 4);
723 snprintf(dsn, sizeof(dsn), "%02x%02x%02x%02x%02x%02x%02x%02x",
724 (dev_sn_lo & 0x000000FF),
725 (dev_sn_lo >> 8) & 0x0000FF,
726 (dev_sn_lo >> 16) & 0x00FF,
727 (dev_sn_lo >> 24 ) & 0xFF,
728 (dev_sn_hi & 0x000000FF),
729 (dev_sn_hi >> 8) & 0x0000FF,
730 (dev_sn_hi >> 16) & 0x00FF,
731 (dev_sn_hi >> 24 ) & 0xFF);
732 strncpy(dev_info.nic_info.device_serial_number, dsn, sizeof(dsn));
733 }
734
735 if_t ifp = iflib_get_ifp(softc->ctx);
736 dev_info.nic_info.mtu = if_getmtu(ifp);
737 memcpy(dev_info.nic_info.mac, softc->func.mac_addr, ETHER_ADDR_LEN);
738
739 if (pci_find_cap(softc->dev, PCIY_EXPRESS, &capreg)) {
740 device_printf(softc->dev, "%s:%d pci link capability is not found"
741 "or not supported\n", __func__, __LINE__);
742 } else {
743 lnk = pci_read_config(softc->dev, capreg + PCIER_LINK_STA, 2);
744 dev_info.nic_info.pci_link_speed = (lnk & PCIEM_LINK_STA_SPEED);
745 dev_info.nic_info.pci_link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
746 }
747
748 if (copyout(&dev_info, user_ptr, sizeof(dev_info))) {
749 device_printf(softc->dev, "%s:%d Failed to copy data to user\n",
750 __func__, __LINE__);
751 return (-EFAULT);
752 }
753
754 return (0);
755 }
756
757 static int
bnxt_mgmt_drv_dump(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)758 bnxt_mgmt_drv_dump(struct cdev *dev, u_long cmd, caddr_t data,
759 int flag, struct thread *td)
760 {
761 struct bnxt_softc *softc = NULL;
762 void *buf = NULL;
763 struct bnxt_logger *logger = NULL, *lg_tmp;
764 int buf_sz = 0;
765 struct bnxt_mgmt_drv_dump mgmt_drv_dump = {};
766 void *user_ptr;
767 int ret = 0, offset = 0;
768
769 memcpy(&user_ptr, data, sizeof(user_ptr));
770 if (copyin(user_ptr, &mgmt_drv_dump, sizeof(mgmt_drv_dump))) {
771 printf("%s: %s:%d Failed to copy data from user\n",
772 DRIVER_NAME, __func__, __LINE__);
773 return (-EFAULT);
774 }
775 softc = bnxt_find_dev(mgmt_drv_dump.hdr.domain, mgmt_drv_dump.hdr.bus,
776 mgmt_drv_dump.hdr.devfn, NULL);
777 if (!softc) {
778 printf("%s: %s:%d unable to find softc reference\n",
779 DRIVER_NAME, __func__, __LINE__);
780 return (-ENODEV);
781 }
782
783 switch (mgmt_drv_dump.op) {
784 case BNXT_MGMT_GET_DRV_DUMP_SIZE:
785 mtx_lock(&softc->log_lock);
786 TAILQ_FOREACH_SAFE(logger, &softc->loggers_list, list, lg_tmp)
787 buf_sz += logger->buffer_size;
788 mtx_unlock(&softc->log_lock);
789
790 mgmt_drv_dump.buf_size = buf_sz +
791 bnxt_get_driver_coredump_len(softc);
792 if (copyout(&mgmt_drv_dump, user_ptr, sizeof(mgmt_drv_dump))) {
793 device_printf(softc->dev,
794 "%s:%d Failed to copy response to user\n",
795 __func__, __LINE__);
796 ret = -EFAULT;
797 }
798 break;
799 case BNXT_MGMT_GET_DRV_DUMP:
800 buf = malloc(mgmt_drv_dump.buf_size, M_BNXT, M_WAITOK);
801 /*Dump the driver logs */
802 memset(buf, 0, mgmt_drv_dump.buf_size);
803 offset = bnxt_start_logging_driver_coredump(softc, buf);
804
805 if (!offset) {
806 device_printf(softc->dev,
807 "%s:%d Drivers logs are empty\n",
808 __func__, __LINE__);
809 }
810
811 /* Dump the ctx logs*/
812 if (softc->ctx_mem)
813 bnxt_get_ctx_coredump(softc, (uint8_t *)buf + offset);
814
815 if (copyout(buf, mgmt_drv_dump.buf, mgmt_drv_dump.buf_size)) {
816 device_printf(softc->dev,
817 "%s:%d Failed to copy response to user\n",
818 __func__, __LINE__);
819 ret = -EFAULT;
820 }
821
822 free(buf, M_BNXT);
823 break;
824 default:
825 device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
826 __func__, __LINE__, mgmt_drv_dump.op);
827 ret = -EFAULT;
828 }
829
830 return (ret);
831 }
832
833 /*
834 * IOCTL entry point.
835 */
836 static int
bnxt_mgmt_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)837 bnxt_mgmt_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
838 struct thread *td)
839 {
840 int ret = 0;
841
842 switch(cmd) {
843 case IO_BNXT_MGMT_OPCODE_GET_DEV_INFO:
844 case IOW_BNXT_MGMT_OPCODE_GET_DEV_INFO:
845 ret = bnxt_mgmt_get_dev_info(dev, cmd, data, flag, td);
846 break;
847 case IO_BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
848 case IOW_BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
849 sx_xlock(&mgmt_lock);
850 ret = bnxt_mgmt_process_hwrm(dev, cmd, data, flag, td);
851 sx_xunlock(&mgmt_lock);
852 break;
853 case IO_BNXT_MGMT_OPCODE_DCB_OPS:
854 case IOW_BNXT_MGMT_OPCODE_DCB_OPS:
855 ret = bnxt_mgmt_process_dcb(dev, cmd, data, flag, td);
856 break;
857 case IO_BNXT_MGMT_OPCODE_DRV_DUMP:
858 case IOW_BNXT_MGMT_OPCODE_DRV_DUMP:
859 ret = bnxt_mgmt_drv_dump(dev, cmd, data, flag, td);
860 break;
861 case IO_BNXT_MGMT_OPCODE_CRASH_DUMP:
862 case IOW_BNXT_MGMT_OPCODE_CRASH_DUMP:
863 ret = bnxt_mgmt_crash_dump(dev, cmd, data, flag, td);
864 break;
865 default:
866 printf("%s: Unknown command 0x%lx\n", DRIVER_NAME, cmd);
867 ret = -EINVAL;
868 break;
869 }
870
871 return (ret);
872 }
873
874 static int
bnxt_mgmt_close(struct cdev * dev,int flags,int devtype,struct thread * td)875 bnxt_mgmt_close(struct cdev *dev, int flags, int devtype, struct thread *td)
876 {
877 return (0);
878 }
879
880 static int
bnxt_mgmt_open(struct cdev * dev,int flags,int devtype,struct thread * td)881 bnxt_mgmt_open(struct cdev *dev, int flags, int devtype, struct thread *td)
882 {
883 return (0);
884 }
885
886 DEV_MODULE(bnxt_mgmt, bnxt_mgmt_loader, NULL);
887
888