#include "bnxt_mgmt.h"
#include "bnxt.h"
#include "bnxt_hwrm.h"
#include "bnxt_coredump.h"
#include "bnxt_log.h"
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <sys/endian.h>
#include <sys/lock.h>
static d_open_t bnxt_mgmt_open;
static d_close_t bnxt_mgmt_close;
static d_ioctl_t bnxt_mgmt_ioctl;
static struct cdevsw bnxt_mgmt_cdevsw = {
.d_version = D_VERSION,
.d_open = bnxt_mgmt_open,
.d_close = bnxt_mgmt_close,
.d_ioctl = bnxt_mgmt_ioctl,
.d_name = "bnxt_mgmt",
};
static struct cdev *bnxt_mgmt_dev;
struct sx mgmt_lock;
MALLOC_DEFINE(M_BNXT, "bnxt_mgmt_buffer", "buffer for bnxt_mgmt module");
static uint32_t
bnxt_get_driver_coredump_len(struct bnxt_softc *softc)
{
uint32_t type, i, j, n;
uint32_t buf_size = 0;
int ctx_page_count = 0;
int segment_len = 0;
int driver_segment_record_len = 0;
uint32_t dump_len = 0;
int record_len = sizeof(struct bnxt_driver_segment_record);
struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
if (!ctx)
return (dump_len);
for (type = BNXT_CTX_SRT_TRACE; type <= BNXT_CTX_ROCE_HWRM_TRACE;
type++) {
struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
if (!ctx_pg)
continue;
if (ctxm->instance_bmap)
n = bitcount32(ctxm->instance_bmap);
else
n = 1;
for (i = 0; i < n; i++) {
struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
if (ctx_pg->nr_pages > MAX_CTX_PAGES ||
ctx_pg->ctx_pg_tbl) {
int k = 0, nr_tbls = rmem->nr_pages;
for (k = 0; k < nr_tbls; k++) {
struct bnxt_ctx_pg_info *pg_tbl;
struct bnxt_ring_mem_info *rmem2;
pg_tbl = ctx_pg->ctx_pg_tbl[k];
if (!pg_tbl)
continue;
rmem2 = &pg_tbl->ring_mem;
for (j = 0; j < rmem2->nr_pages; j++) {
if (!rmem2->pg_arr[j].idi_vaddr)
continue;
ctx_page_count++;
}
}
} else {
struct bnxt_ring_mem_info *rmem2 = rmem;
for (j = 0; j < rmem2->nr_pages; j++) {
if (!rmem2->pg_arr[j].idi_vaddr)
continue;
ctx_page_count++;
}
}
}
segment_len += 64;
driver_segment_record_len += record_len;
}
buf_size = driver_segment_record_len + segment_len +
(ctx_page_count * 4096);
return (buf_size);
}
inline void
bnxt_bs_trace_check_wrapping(struct bnxt_bs_trace_info *bs_trace,
u32 offset)
{
if (!bs_trace->wrapped &&
*bs_trace->magic_byte != BNXT_TRACE_BUF_MAGIC_BYTE)
bs_trace->wrapped = 1;
bs_trace->last_offset = offset;
}
static int
bnxt_hwrm_dbg_log_buffer_flush(struct bnxt_softc *bp, u16 type, u32 flags,
u32 *offset)
{
int status = 0;
hwrm_dbg_log_buffer_flush_input_t buff_flush_req;
hwrm_dbg_log_buffer_flush_output_t *buff_flush_resp =
(hwrm_dbg_log_buffer_flush_output_t *)(void *)
bp->hwrm_cmd_resp.idi_vaddr;
bnxt_hwrm_cmd_hdr_init(bp, &buff_flush_req, HWRM_DBG_LOG_BUFFER_FLUSH);
buff_flush_req.type = type;
buff_flush_req.flags = flags;
status = hwrm_send_message(bp, &buff_flush_req, sizeof(buff_flush_req));
if (!status)
*offset = buff_flush_resp->current_buffer_offset;
return (status);
}
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)
{
struct bnxt_bs_trace_info *bs_trace = &bp->bs_trace[type];
uint32_t offset;
if (bnxt_hwrm_dbg_log_buffer_flush(bp, type, 0, &offset) == 0) {
bnxt_bs_trace_check_wrapping(bs_trace, offset);
}
drv_seg_rec->max_entries = ctxm->max_entries;
drv_seg_rec->entry_size = ctxm->entry_size;
drv_seg_rec->offset = bs_trace->last_offset;
drv_seg_rec->wrapped = bs_trace->wrapped;
}
static void
bnxt_retrieve_driver_coredump(struct bnxt_softc *softc, void *buf,
uint16_t type, uint32_t *seg_len)
{
struct bnxt_driver_segment_record drv_seg_rec = {0};
struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
uint32_t dump_len, data_offset, record_len, seg_hdr_len;
uint32_t i, j, k, n = 1, nr_tbls;
dump_len = 0;
record_len = sizeof(struct bnxt_driver_segment_record);
seg_hdr_len = sizeof(struct bnxt_coredump_segment_hdr);
data_offset = seg_hdr_len + record_len;
bnxt_fill_driver_segment_record(softc, &drv_seg_rec, ctxm,
(type - BNXT_CTX_SRT_TRACE));
for (i = 0; i < n; i++) {
struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
if (ctx_pg->nr_pages > MAX_CTX_PAGES || ctx_pg->ctx_pg_tbl) {
nr_tbls = rmem->nr_pages;
for (j = 0; j < nr_tbls; j++) {
struct bnxt_ctx_pg_info *pg_tbl;
struct bnxt_ring_mem_info *rmem2;
pg_tbl = ctx_pg->ctx_pg_tbl[j];
if (!pg_tbl)
continue;
rmem2 = &pg_tbl->ring_mem;
for (k = 0; k < rmem2->nr_pages; k++) {
if (!rmem2->pg_arr[k].idi_vaddr)
continue;
memcpy((uint8_t *)buf + data_offset,
rmem2->pg_arr[k].idi_vaddr,
rmem2->page_size);
data_offset += rmem2->page_size;
dump_len += rmem2->page_size;
}
}
} else {
for (k = 0; k < rmem->nr_pages; k++) {
if (!rmem->pg_arr[k].idi_vaddr)
continue;
memcpy((uint8_t *)buf + data_offset,
rmem->pg_arr[k].idi_vaddr,
rmem->page_size);
data_offset += rmem->page_size;
dump_len += rmem->page_size;
}
}
}
memcpy((uint8_t *)buf + seg_hdr_len, &drv_seg_rec, record_len);
*seg_len = dump_len + record_len;
}
void
bnxt_get_ctx_coredump(struct bnxt_softc *softc, void *buf)
{
struct bnxt_ctx_mem_info *ctx = softc->ctx_mem;
struct bnxt_coredump_segment_hdr seg_hdr;
uint32_t type = 0, i = 0;
uint32_t seg_hdr_len = 0;
seg_hdr_len = sizeof(seg_hdr);
for (type = BNXT_CTX_SRT_TRACE, i = DRV_SRT_TRACE_SEG_ID;
type <= BNXT_CTX_ROCE_HWRM_TRACE; type++, i++) {
struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
uint16_t comp_id = DRV_COREDUMP_COMP_ID;
uint16_t seg_id = i;
uint32_t seg_len = 0;
ctxm = &ctx->ctx_arr[type];
if (!(ctxm->flags & BNXT_CTX_MEM_TYPE_VALID) ||
!ctxm->mem_valid)
continue;
bnxt_retrieve_driver_coredump(softc, buf, type, &seg_len);
bnxt_fill_coredump_seg_hdr(softc, &seg_hdr, NULL, seg_len,
0, 0, 0, comp_id, seg_id);
memcpy((uint8_t *)buf, &seg_hdr, seg_hdr_len);
buf = (uint8_t *)buf + seg_hdr_len + seg_len;
}
}
static int
bnxt_mgmt_crash_dump(struct cdev *dev, u_long cmd, caddr_t data,
int flag, struct thread *td)
{
struct bnxt_softc *softc = NULL;
struct bnxt_mgmt_crash_dump mgmt_crash_dump = {0};
void *user_ptr;
int ret = 0;
void *dump_buf = NULL;
uint32_t dump_len;
memcpy(&user_ptr, data, sizeof(user_ptr));
if (copyin(user_ptr, &mgmt_crash_dump, sizeof(mgmt_crash_dump))) {
printf("%s: %s:%d Failed to copy data from user\n",
DRIVER_NAME, __func__, __LINE__);
return (-EFAULT);
}
softc = bnxt_find_dev(mgmt_crash_dump.hdr.domain,
mgmt_crash_dump.hdr.bus,
mgmt_crash_dump.hdr.devfn, NULL);
if (!softc) {
printf("%s: %s:%d unable to find softc reference\n",
DRIVER_NAME, __func__, __LINE__);
return (-ENODEV);
}
switch (mgmt_crash_dump.op) {
case BNXT_MGMT_SET_DUMP_FLAG:
if (mgmt_crash_dump.req.set_flag.dump_flag >
BNXT_DUMP_LIVE_WITH_CTX_L1_CACHE) {
device_printf(softc->dev,
"Supports only Live(0), Crash(1), Driver(2), "
"Live with cached context(3) dumps.\n");
ret = -EINVAL;
break;
}
if (mgmt_crash_dump.req.set_flag.dump_flag == BNXT_DUMP_CRASH) {
if (softc->fw_dbg_cap & BNXT_FW_DBG_CAP_CRASHDUMP_SOC) {
device_printf(softc->dev,
"Cannot collect crash dump as TEE is not supported.\n");
ret = -ENOTSUP;
break;
} else if (!(softc->fw_dbg_cap &
BNXT_FW_DBG_CAP_CRASHDUMP_HOST)) {
device_printf(softc->dev,
"FW does not support crash dump collection.\n");
ret = -ENOTSUP;
break;
}
}
softc->dump_flag = mgmt_crash_dump.req.set_flag.dump_flag;
break;
case BNXT_MGMT_GET_DUMP_FLAG:
if (softc->hwrm_spec_code < 0x10801) {
ret = -ENOTSUP;
break;
}
mgmt_crash_dump.req.get_flag.version =
(softc->ver_resp.hwrm_fw_maj_8b << 24) |
(softc->ver_resp.hwrm_fw_min_8b << 16) |
(softc->ver_resp.hwrm_fw_bld_8b << 8) |
(softc->ver_resp.hwrm_fw_rsvd_8b);
mgmt_crash_dump.req.get_flag.dump_flag = softc->dump_flag;
mgmt_crash_dump.req.get_flag.dump_len =
bnxt_get_coredump_length(softc, softc->dump_flag);
break;
case BNXT_MGMT_GET_DUMP_DATA:
if (softc->hwrm_spec_code < 0x10801) {
ret = -ENOTSUP;
break;
}
dump_len = bnxt_get_coredump_length(softc,
mgmt_crash_dump.req.get_data.dump_flag);
if (dump_len == 0) {
device_printf(softc->dev, "No dump data available\n");
ret = -ENOENT;
break;
}
if (mgmt_crash_dump.req.get_data.buffer_size < dump_len) {
device_printf(softc->dev,
"Buffer too small: need %u bytes, got %zu bytes\n",
dump_len, mgmt_crash_dump.req.get_data.buffer_size);
mgmt_crash_dump.req.get_data.dump_len = dump_len;
ret = -ENOSPC;
break;
}
dump_buf = malloc(dump_len, M_BNXT, M_WAITOK);
if (!dump_buf) {
ret = -ENOMEM;
break;
}
ret = bnxt_get_coredump(softc,
mgmt_crash_dump.req.get_data.dump_flag,
dump_buf, &dump_len);
if (ret) {
device_printf(softc->dev,
"Failed to get coredump: %d\n", ret);
free(dump_buf, M_BNXT);
break;
}
if (copyout(dump_buf,
mgmt_crash_dump.req.get_data.dump_buffer, dump_len)) {
device_printf(softc->dev,
"%s:%d Failed to copy dump data to user\n",
__func__, __LINE__);
ret = -EFAULT;
free(dump_buf, M_BNXT);
break;
}
mgmt_crash_dump.req.get_data.dump_len = dump_len;
mgmt_crash_dump.req.get_data.dump_flag = softc->dump_flag;
free(dump_buf, M_BNXT);
break;
default:
device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
__func__, __LINE__, mgmt_crash_dump.op);
ret = -EFAULT;
break;
}
if (!ret && copyout(&mgmt_crash_dump, user_ptr,
sizeof(mgmt_crash_dump))) {
device_printf(softc->dev,
"%s:%d Failed to copy response to user\n",
__func__, __LINE__);
ret = -EFAULT;
}
return (ret);
}
static int
bnxt_mgmt_loader(struct module *m, int what, void *arg)
{
int error = 0;
switch (what) {
case MOD_LOAD:
error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
&bnxt_mgmt_dev,
&bnxt_mgmt_cdevsw,
0,
UID_ROOT,
GID_WHEEL,
0600,
"bnxt_mgmt");
if (error != 0) {
printf("%s: %s:%s:%d Failed to create the"
"bnxt_mgmt device node\n", DRIVER_NAME,
__FILE__, __func__, __LINE__);
return (error);
}
sx_init(&mgmt_lock, "BNXT MGMT Lock");
break;
case MOD_UNLOAD:
sx_destroy(&mgmt_lock);
destroy_dev(bnxt_mgmt_dev);
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
static int
bnxt_mgmt_process_dcb(struct cdev *dev, u_long cmd, caddr_t data,
int flag, struct thread *td)
{
struct bnxt_softc *softc = NULL;
struct bnxt_mgmt_dcb mgmt_dcb = {};
void *user_ptr;
int ret = 0;
memcpy(&user_ptr, data, sizeof(user_ptr));
if (copyin(user_ptr, &mgmt_dcb, sizeof(mgmt_dcb))) {
printf("%s: %s:%d Failed to copy data from user\n",
DRIVER_NAME, __func__, __LINE__);
return -EFAULT;
}
softc = bnxt_find_dev(mgmt_dcb.hdr.domain, mgmt_dcb.hdr.bus,
mgmt_dcb.hdr.devfn, NULL);
if (!softc) {
printf("%s: %s:%d unable to find softc reference\n",
DRIVER_NAME, __func__, __LINE__);
return -ENODEV;
}
switch (mgmt_dcb.op) {
case BNXT_MGMT_DCB_GET_ETS:
bnxt_dcb_ieee_getets(softc, &mgmt_dcb.req.ets);
break;
case BNXT_MGMT_DCB_SET_ETS:
bnxt_dcb_ieee_setets(softc, &mgmt_dcb.req.ets);
break;
case BNXT_MGMT_DCB_GET_PFC:
bnxt_dcb_ieee_getpfc(softc, &mgmt_dcb.req.pfc);
break;
case BNXT_MGMT_DCB_SET_PFC:
bnxt_dcb_ieee_setpfc(softc, &mgmt_dcb.req.pfc);
break;
case BNXT_MGMT_DCB_SET_APP:
bnxt_dcb_ieee_setapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
break;
case BNXT_MGMT_DCB_DEL_APP:
bnxt_dcb_ieee_delapp(softc, &mgmt_dcb.req.app_tlv.app[0]);
break;
case BNXT_MGMT_DCB_LIST_APP:
bnxt_dcb_ieee_listapp(softc, &mgmt_dcb.req.app_tlv.app[0],
nitems(mgmt_dcb.req.app_tlv.app),
&mgmt_dcb.req.app_tlv.num_app);
break;
default:
device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
__func__, __LINE__, mgmt_dcb.op);
ret = -EFAULT;
goto end;
}
if (copyout(&mgmt_dcb, user_ptr, sizeof(mgmt_dcb))) {
device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
__func__, __LINE__);
ret = -EFAULT;
goto end;
}
end:
return ret;
}
static int
bnxt_mgmt_process_hwrm(struct cdev *dev, u_long cmd, caddr_t data,
int flag, struct thread *td)
{
struct bnxt_softc *softc = NULL;
struct bnxt_mgmt_req mgmt_req = {};
struct bnxt_mgmt_fw_msg msg_temp, *msg, *msg2 = NULL;
void *user_ptr, *req, *resp;
int ret = 0, num_allocated = 0, i;
uint16_t num_ind = 0;
memcpy(&user_ptr, data, sizeof(user_ptr));
if (copyin(user_ptr, &mgmt_req, sizeof(struct bnxt_mgmt_req))) {
printf("%s: %s:%d Failed to copy data from user\n",
DRIVER_NAME, __func__, __LINE__);
return -EFAULT;
}
softc = bnxt_find_dev(mgmt_req.hdr.domain, mgmt_req.hdr.bus,
mgmt_req.hdr.devfn, NULL);
if (!softc) {
printf("%s: %s:%d unable to find softc reference\n",
DRIVER_NAME, __func__, __LINE__);
return -ENODEV;
}
if (copyin((void*)mgmt_req.req.hreq, &msg_temp, sizeof(msg_temp))) {
device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
__func__, __LINE__);
return -EFAULT;
}
if (msg_temp.len_req > BNXT_MGMT_MAX_HWRM_REQ_LENGTH ||
msg_temp.len_resp > BNXT_MGMT_MAX_HWRM_RESP_LENGTH) {
device_printf(softc->dev, "%s:%d Invalid length\n",
__func__, __LINE__);
return -EINVAL;
}
if (msg_temp.num_dma_indications > MAX_NUM_DMA_INDICATIONS) {
device_printf(softc->dev, "%s:%d Max num_dma_indications "
"supported is %d\n", __func__, __LINE__,
MAX_NUM_DMA_INDICATIONS);
return -EINVAL;
}
req = malloc(msg_temp.len_req, M_BNXT, M_WAITOK | M_ZERO);
resp = malloc(msg_temp.len_resp, M_BNXT, M_WAITOK | M_ZERO);
if (copyin((void *)msg_temp.usr_req, req, msg_temp.len_req)) {
device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
__func__, __LINE__);
ret = -EFAULT;
goto end;
}
msg = &msg_temp;
num_ind = msg_temp.num_dma_indications;
if (num_ind) {
int size;
void *dma_ptr;
uint64_t *dmap;
size = sizeof(struct bnxt_mgmt_fw_msg) +
(num_ind * sizeof(struct dma_info));
msg2 = malloc(size, M_BNXT, M_WAITOK | M_ZERO);
if (copyin((void *)mgmt_req.req.hreq, msg2, size)) {
device_printf(softc->dev, "%s:%d Failed to copy"
"data from user\n", __func__, __LINE__);
ret = -EFAULT;
goto end;
}
msg = msg2;
for (i = 0; i < num_ind; i++) {
if (msg->dma[i].length == 0) {
device_printf(softc->dev,
"%s:%d i:%d Invalid DMA memory length\n",
__func__, __LINE__, i);
ret = -ENOMEM;
goto end;
}
memset(&softc->mgmt_dma_data[i], 0, sizeof(struct iflib_dma_info));
ret = iflib_dma_alloc(softc->ctx, msg->dma[i].length, &softc->mgmt_dma_data[i],
BUS_DMA_WAITOK);
if (ret) {
device_printf(softc->dev,
"%s:%d iflib_dma_alloc failed with ret = 0x%x\n",
__func__, __LINE__, ret);
ret = -ENOMEM;
goto end;
}
num_allocated++;
if (!(msg->dma[i].read_or_write)) {
if (copyin((void *)msg->dma[i].data,
softc->mgmt_dma_data[i].idi_vaddr,
msg->dma[i].length)) {
device_printf(softc->dev,
"%s:%d Failed to copy data from user\n",
__func__, __LINE__);
ret = -EFAULT;
goto end;
}
}
dma_ptr = (void *) ((uint64_t) req + msg->dma[i].offset);
dmap = dma_ptr;
*dmap = htole64(softc->mgmt_dma_data[i].idi_paddr);
}
}
ret = bnxt_hwrm_passthrough(softc, req, msg->len_req, resp, msg->len_resp, msg->timeout);
if (ret)
goto end;
for (i = 0; i < num_ind; i++) {
if ((msg->dma[i].read_or_write)) {
if (copyout(softc->mgmt_dma_data[i].idi_vaddr,
(void *)msg->dma[i].data,
msg->dma[i].length)) {
device_printf(softc->dev,
"%s:%d Failed to copy data to user\n",
__func__, __LINE__);
ret = -EFAULT;
goto end;
}
}
}
if (copyout(resp, (void *) msg->usr_resp, msg->len_resp)) {
device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
__func__, __LINE__);
ret = -EFAULT;
goto end;
}
end:
if (req)
free(req, M_BNXT);
if (resp)
free(resp, M_BNXT);
if (msg2)
free(msg2, M_BNXT);
if (num_allocated) {
for (i = 0; i < num_allocated; i++)
if (softc->mgmt_dma_data[i].idi_paddr)
iflib_dma_free(&softc->mgmt_dma_data[i]);
}
return ret;
}
static int
bnxt_mgmt_get_dev_info(struct cdev *dev, u_long cmd, caddr_t data,
int flag, struct thread *td)
{
struct bnxt_softc *softc = NULL;
struct bnxt_dev_info dev_info;
void *user_ptr;
uint32_t dev_sn_lo, dev_sn_hi;
int dev_sn_offset = 0;
char dsn[16];
uint16_t lnk;
int capreg;
memcpy(&user_ptr, data, sizeof(user_ptr));
if (copyin(user_ptr, &dev_info, sizeof(dev_info))) {
printf("%s: %s:%d Failed to copy data from user\n",
DRIVER_NAME, __func__, __LINE__);
return -EFAULT;
}
softc = bnxt_find_dev(0, 0, 0, dev_info.nic_info.dev_name);
if (!softc) {
printf("%s: %s:%d unable to find softc reference\n",
DRIVER_NAME, __func__, __LINE__);
return -ENODEV;
}
strncpy(dev_info.nic_info.driver_version, bnxt_driver_version, 64);
strncpy(dev_info.nic_info.driver_name, device_get_name(softc->dev), 64);
dev_info.pci_info.domain_no = softc->domain;
dev_info.pci_info.bus_no = softc->bus;
dev_info.pci_info.device_no = softc->slot;
dev_info.pci_info.function_no = softc->function;
dev_info.pci_info.vendor_id = pci_get_vendor(softc->dev);
dev_info.pci_info.device_id = pci_get_device(softc->dev);
dev_info.pci_info.sub_system_vendor_id = pci_get_subvendor(softc->dev);
dev_info.pci_info.sub_system_device_id = pci_get_subdevice(softc->dev);
dev_info.pci_info.revision = pci_read_config(softc->dev, PCIR_REVID, 1);
dev_info.pci_info.chip_rev_id = (dev_info.pci_info.device_id << 16);
dev_info.pci_info.chip_rev_id |= dev_info.pci_info.revision;
if (pci_find_extcap(softc->dev, PCIZ_SERNUM, &dev_sn_offset)) {
device_printf(softc->dev, "%s:%d device serial number is not found"
"or not supported\n", __func__, __LINE__);
} else {
dev_sn_lo = pci_read_config(softc->dev, dev_sn_offset + 4, 4);
dev_sn_hi = pci_read_config(softc->dev, dev_sn_offset + 8, 4);
snprintf(dsn, sizeof(dsn), "%02x%02x%02x%02x%02x%02x%02x%02x",
(dev_sn_lo & 0x000000FF),
(dev_sn_lo >> 8) & 0x0000FF,
(dev_sn_lo >> 16) & 0x00FF,
(dev_sn_lo >> 24 ) & 0xFF,
(dev_sn_hi & 0x000000FF),
(dev_sn_hi >> 8) & 0x0000FF,
(dev_sn_hi >> 16) & 0x00FF,
(dev_sn_hi >> 24 ) & 0xFF);
strncpy(dev_info.nic_info.device_serial_number, dsn, sizeof(dsn));
}
if_t ifp = iflib_get_ifp(softc->ctx);
dev_info.nic_info.mtu = if_getmtu(ifp);
memcpy(dev_info.nic_info.mac, softc->func.mac_addr, ETHER_ADDR_LEN);
if (pci_find_cap(softc->dev, PCIY_EXPRESS, &capreg)) {
device_printf(softc->dev, "%s:%d pci link capability is not found"
"or not supported\n", __func__, __LINE__);
} else {
lnk = pci_read_config(softc->dev, capreg + PCIER_LINK_STA, 2);
dev_info.nic_info.pci_link_speed = (lnk & PCIEM_LINK_STA_SPEED);
dev_info.nic_info.pci_link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
}
if (copyout(&dev_info, user_ptr, sizeof(dev_info))) {
device_printf(softc->dev, "%s:%d Failed to copy data to user\n",
__func__, __LINE__);
return (-EFAULT);
}
return (0);
}
static int
bnxt_mgmt_drv_dump(struct cdev *dev, u_long cmd, caddr_t data,
int flag, struct thread *td)
{
struct bnxt_softc *softc = NULL;
void *buf = NULL;
struct bnxt_logger *logger = NULL, *lg_tmp;
int buf_sz = 0;
struct bnxt_mgmt_drv_dump mgmt_drv_dump = {};
void *user_ptr;
int ret = 0, offset = 0;
memcpy(&user_ptr, data, sizeof(user_ptr));
if (copyin(user_ptr, &mgmt_drv_dump, sizeof(mgmt_drv_dump))) {
printf("%s: %s:%d Failed to copy data from user\n",
DRIVER_NAME, __func__, __LINE__);
return (-EFAULT);
}
softc = bnxt_find_dev(mgmt_drv_dump.hdr.domain, mgmt_drv_dump.hdr.bus,
mgmt_drv_dump.hdr.devfn, NULL);
if (!softc) {
printf("%s: %s:%d unable to find softc reference\n",
DRIVER_NAME, __func__, __LINE__);
return (-ENODEV);
}
switch (mgmt_drv_dump.op) {
case BNXT_MGMT_GET_DRV_DUMP_SIZE:
mtx_lock(&softc->log_lock);
TAILQ_FOREACH_SAFE(logger, &softc->loggers_list, list, lg_tmp)
buf_sz += logger->buffer_size;
mtx_unlock(&softc->log_lock);
mgmt_drv_dump.buf_size = buf_sz +
bnxt_get_driver_coredump_len(softc);
if (copyout(&mgmt_drv_dump, user_ptr, sizeof(mgmt_drv_dump))) {
device_printf(softc->dev,
"%s:%d Failed to copy response to user\n",
__func__, __LINE__);
ret = -EFAULT;
}
break;
case BNXT_MGMT_GET_DRV_DUMP:
buf = malloc(mgmt_drv_dump.buf_size, M_BNXT, M_WAITOK);
memset(buf, 0, mgmt_drv_dump.buf_size);
offset = bnxt_start_logging_driver_coredump(softc, buf);
if (!offset) {
device_printf(softc->dev,
"%s:%d Drivers logs are empty\n",
__func__, __LINE__);
}
if (softc->ctx_mem)
bnxt_get_ctx_coredump(softc, (uint8_t *)buf + offset);
if (copyout(buf, mgmt_drv_dump.buf, mgmt_drv_dump.buf_size)) {
device_printf(softc->dev,
"%s:%d Failed to copy response to user\n",
__func__, __LINE__);
ret = -EFAULT;
}
free(buf, M_BNXT);
break;
default:
device_printf(softc->dev, "%s:%d Invalid op 0x%x\n",
__func__, __LINE__, mgmt_drv_dump.op);
ret = -EFAULT;
}
return (ret);
}
static int
bnxt_mgmt_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
struct thread *td)
{
int ret = 0;
switch(cmd) {
case IO_BNXT_MGMT_OPCODE_GET_DEV_INFO:
case IOW_BNXT_MGMT_OPCODE_GET_DEV_INFO:
ret = bnxt_mgmt_get_dev_info(dev, cmd, data, flag, td);
break;
case IO_BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
case IOW_BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
sx_xlock(&mgmt_lock);
ret = bnxt_mgmt_process_hwrm(dev, cmd, data, flag, td);
sx_xunlock(&mgmt_lock);
break;
case IO_BNXT_MGMT_OPCODE_DCB_OPS:
case IOW_BNXT_MGMT_OPCODE_DCB_OPS:
ret = bnxt_mgmt_process_dcb(dev, cmd, data, flag, td);
break;
case IO_BNXT_MGMT_OPCODE_DRV_DUMP:
case IOW_BNXT_MGMT_OPCODE_DRV_DUMP:
ret = bnxt_mgmt_drv_dump(dev, cmd, data, flag, td);
break;
case IO_BNXT_MGMT_OPCODE_CRASH_DUMP:
case IOW_BNXT_MGMT_OPCODE_CRASH_DUMP:
ret = bnxt_mgmt_crash_dump(dev, cmd, data, flag, td);
break;
default:
printf("%s: Unknown command 0x%lx\n", DRIVER_NAME, cmd);
ret = -EINVAL;
break;
}
return (ret);
}
static int
bnxt_mgmt_close(struct cdev *dev, int flags, int devtype, struct thread *td)
{
return (0);
}
static int
bnxt_mgmt_open(struct cdev *dev, int flags, int devtype, struct thread *td)
{
return (0);
}
DEV_MODULE(bnxt_mgmt, bnxt_mgmt_loader, NULL);