From dd44f2142609fdc875fa2e88e12f49b5ecd5d1e6 Mon Sep 17 00:00:00 2001 From: davidcs Date: Thu, 19 Oct 2017 17:57:38 +0000 Subject: [PATCH] MFC r324538 Added support driver state capture/retrieval git-svn-id: svn://svn.freebsd.org/base/stable/9@324766 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/qlxgbe/ql_def.h | 3 +- sys/dev/qlxgbe/ql_glbl.h | 4 + sys/dev/qlxgbe/ql_hw.h | 3 + sys/dev/qlxgbe/ql_ioctl.c | 228 ++++++++++++++++++++++++++++++++++++++ sys/dev/qlxgbe/ql_ioctl.h | 72 ++++++++++++ sys/dev/qlxgbe/ql_os.c | 2 + sys/dev/qlxgbe/ql_ver.h | 2 +- 7 files changed, 311 insertions(+), 3 deletions(-) diff --git a/sys/dev/qlxgbe/ql_def.h b/sys/dev/qlxgbe/ql_def.h index d768dbd42..dacc6b19d 100644 --- a/sys/dev/qlxgbe/ql_def.h +++ b/sys/dev/qlxgbe/ql_def.h @@ -201,7 +201,6 @@ struct qla_host { qla_rx_buf_t *rxb_free; uint32_t rxb_free_count; - volatile uint32_t posting; /* stats */ uint32_t err_m_getcl; @@ -264,7 +263,7 @@ struct qla_host { typedef struct qla_host qla_host_t; /* note that align has to be a power of 2 */ -#define QL_ALIGN(size, align) (size + (align - 1)) & ~(align - 1); +#define QL_ALIGN(size, align) (((size) + ((align) - 1)) & (~((align) - 1))); #define QL_MIN(x, y) ((x < y) ? x : y) #define QL_RUNNING(ifp) (ifp->if_drv_flags & IFF_DRV_RUNNING) diff --git a/sys/dev/qlxgbe/ql_glbl.h b/sys/dev/qlxgbe/ql_glbl.h index 2af8b97ad..f8c7c8b16 100644 --- a/sys/dev/qlxgbe/ql_glbl.h +++ b/sys/dev/qlxgbe/ql_glbl.h @@ -112,4 +112,8 @@ extern unsigned int ql83xx_resetseq_len; extern unsigned char ql83xx_minidump[]; extern unsigned int ql83xx_minidump_len; +extern void ql_alloc_drvr_state_buffer(qla_host_t *ha); +extern void ql_free_drvr_state_buffer(qla_host_t *ha); +extern void ql_capture_drvr_state(qla_host_t *ha); + #endif /* #ifndef_QL_GLBL_H_ */ diff --git a/sys/dev/qlxgbe/ql_hw.h b/sys/dev/qlxgbe/ql_hw.h index 84260087f..e8f53c864 100644 --- a/sys/dev/qlxgbe/ql_hw.h +++ b/sys/dev/qlxgbe/ql_hw.h @@ -1703,6 +1703,9 @@ typedef struct _qla_hw { uint32_t mdump_buffer_size; void *mdump_template; uint32_t mdump_template_size; + + /* driver state related */ + void *drvr_state; } qla_hw_t; #define QL_UPDATE_RDS_PRODUCER_INDEX(ha, prod_reg, val) \ diff --git a/sys/dev/qlxgbe/ql_ioctl.c b/sys/dev/qlxgbe/ql_ioctl.c index 8284cc723..7675d5482 100644 --- a/sys/dev/qlxgbe/ql_ioctl.c +++ b/sys/dev/qlxgbe/ql_ioctl.c @@ -39,7 +39,11 @@ __FBSDID("$FreeBSD$"); #include "ql_inline.h" #include "ql_glbl.h" #include "ql_ioctl.h" +#include "ql_ver.h" +#include "ql_dbg.h" +static int ql_drvr_state(qla_host_t *ha, qla_driver_state_t *drvr_state); +static uint32_t ql_drvr_state_size(qla_host_t *ha); static int ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td); @@ -279,6 +283,10 @@ ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, rval = ENXIO; break; + case QLA_RD_DRVR_STATE: + rval = ql_drvr_state(ha, (qla_driver_state_t *)data); + break; + case QLA_RD_PCI_IDS: pci_ids = (qla_rd_pci_ids_t *)data; pci_ids->ven_id = pci_get_vendor(pci_dev); @@ -295,3 +303,223 @@ ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, return rval; } + +static int +ql_drvr_state(qla_host_t *ha, qla_driver_state_t *state) +{ + int rval = 0; + uint32_t drvr_state_size; + qla_drvr_state_hdr_t *hdr; + + drvr_state_size = ql_drvr_state_size(ha); + + if (state->buffer == NULL) { + state->size = drvr_state_size; + return (0); + } + + if (state->size < drvr_state_size) + return (ENXIO); + + if (ha->hw.drvr_state == NULL) + return (ENOMEM); + + hdr = ha->hw.drvr_state; + + if (!hdr->drvr_version_major) + ql_capture_drvr_state(ha); + + rval = copyout(ha->hw.drvr_state, state->buffer, drvr_state_size); + + bzero(ha->hw.drvr_state, drvr_state_size); + + return (rval); +} + +static uint32_t +ql_drvr_state_size(qla_host_t *ha) +{ + uint32_t drvr_state_size; + uint32_t size; + + size = sizeof (qla_drvr_state_hdr_t); + drvr_state_size = QL_ALIGN(size, 64); + + size = ha->hw.num_tx_rings * (sizeof (qla_drvr_state_tx_t)); + drvr_state_size += QL_ALIGN(size, 64); + + size = ha->hw.num_rds_rings * (sizeof (qla_drvr_state_rx_t)); + drvr_state_size += QL_ALIGN(size, 64); + + size = ha->hw.num_sds_rings * (sizeof (qla_drvr_state_sds_t)); + drvr_state_size += QL_ALIGN(size, 64); + + size = sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS * ha->hw.num_tx_rings; + drvr_state_size += QL_ALIGN(size, 64); + + size = sizeof(q80_recv_desc_t) * NUM_RX_DESCRIPTORS * ha->hw.num_rds_rings; + drvr_state_size += QL_ALIGN(size, 64); + + size = sizeof(q80_stat_desc_t) * NUM_STATUS_DESCRIPTORS * + ha->hw.num_sds_rings; + drvr_state_size += QL_ALIGN(size, 64); + + return (drvr_state_size); +} + +static void +ql_get_tx_state(qla_host_t *ha, qla_drvr_state_tx_t *tx_state) +{ + int i; + + for (i = 0; i < ha->hw.num_tx_rings; i++) { + tx_state->base_p_addr = ha->hw.tx_cntxt[i].tx_ring_paddr; + tx_state->cons_p_addr = ha->hw.tx_cntxt[i].tx_cons_paddr; + tx_state->tx_prod_reg = ha->hw.tx_cntxt[i].tx_prod_reg; + tx_state->tx_cntxt_id = ha->hw.tx_cntxt[i].tx_cntxt_id; + tx_state->txr_free = ha->hw.tx_cntxt[i].txr_free; + tx_state->txr_next = ha->hw.tx_cntxt[i].txr_next; + tx_state->txr_comp = ha->hw.tx_cntxt[i].txr_comp; + tx_state++; + } + return; +} + +static void +ql_get_rx_state(qla_host_t *ha, qla_drvr_state_rx_t *rx_state) +{ + int i; + + for (i = 0; i < ha->hw.num_rds_rings; i++) { + rx_state->prod_std = ha->hw.rds[i].prod_std; + rx_state->rx_next = ha->hw.rds[i].rx_next; + rx_state++; + } + return; +} + +static void +ql_get_sds_state(qla_host_t *ha, qla_drvr_state_sds_t *sds_state) +{ + int i; + + for (i = 0; i < ha->hw.num_sds_rings; i++) { + sds_state->sdsr_next = ha->hw.sds[i].sdsr_next; + sds_state->sds_consumer = ha->hw.sds[i].sds_consumer; + sds_state++; + } + return; +} + +void +ql_capture_drvr_state(qla_host_t *ha) +{ + uint8_t *state_buffer; + uint8_t *ptr; + uint32_t drvr_state_size; + qla_drvr_state_hdr_t *hdr; + uint32_t size; + int i; + + drvr_state_size = ql_drvr_state_size(ha); + + state_buffer = ha->hw.drvr_state; + + if (state_buffer == NULL) + return; + + bzero(state_buffer, drvr_state_size); + + hdr = (qla_drvr_state_hdr_t *)state_buffer; + + hdr->drvr_version_major = QLA_VERSION_MAJOR; + hdr->drvr_version_minor = QLA_VERSION_MINOR; + hdr->drvr_version_build = QLA_VERSION_BUILD; + + bcopy(ha->hw.mac_addr, hdr->mac_addr, ETHER_ADDR_LEN); + + hdr->link_speed = ha->hw.link_speed; + hdr->cable_length = ha->hw.cable_length; + hdr->cable_oui = ha->hw.cable_oui; + hdr->link_up = ha->hw.link_up; + hdr->module_type = ha->hw.module_type; + hdr->link_faults = ha->hw.link_faults; + hdr->rcv_intr_coalesce = ha->hw.rcv_intr_coalesce; + hdr->xmt_intr_coalesce = ha->hw.xmt_intr_coalesce; + + size = sizeof (qla_drvr_state_hdr_t); + hdr->tx_state_offset = QL_ALIGN(size, 64); + + ptr = state_buffer + hdr->tx_state_offset; + + ql_get_tx_state(ha, (qla_drvr_state_tx_t *)ptr); + + size = ha->hw.num_tx_rings * (sizeof (qla_drvr_state_tx_t)); + hdr->rx_state_offset = hdr->tx_state_offset + QL_ALIGN(size, 64); + ptr = state_buffer + hdr->rx_state_offset; + + ql_get_rx_state(ha, (qla_drvr_state_rx_t *)ptr); + + size = ha->hw.num_rds_rings * (sizeof (qla_drvr_state_rx_t)); + hdr->sds_state_offset = hdr->rx_state_offset + QL_ALIGN(size, 64); + ptr = state_buffer + hdr->sds_state_offset; + + ql_get_sds_state(ha, (qla_drvr_state_sds_t *)ptr); + + size = ha->hw.num_sds_rings * (sizeof (qla_drvr_state_sds_t)); + hdr->txr_offset = hdr->sds_state_offset + QL_ALIGN(size, 64); + ptr = state_buffer + hdr->txr_offset; + + hdr->num_tx_rings = ha->hw.num_tx_rings; + hdr->txr_size = sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS; + hdr->txr_entries = NUM_TX_DESCRIPTORS; + + size = hdr->num_tx_rings * hdr->txr_size; + bcopy(ha->hw.dma_buf.tx_ring.dma_b, ptr, size); + + hdr->rxr_offset = hdr->txr_offset + QL_ALIGN(size, 64); + ptr = state_buffer + hdr->rxr_offset; + + hdr->rxr_size = sizeof(q80_recv_desc_t) * NUM_RX_DESCRIPTORS; + hdr->rxr_entries = NUM_RX_DESCRIPTORS; + hdr->num_rx_rings = ha->hw.num_rds_rings; + + for (i = 0; i < ha->hw.num_rds_rings; i++) { + bcopy(ha->hw.dma_buf.rds_ring[i].dma_b, ptr, hdr->rxr_size); + ptr += hdr->rxr_size; + } + + size = hdr->rxr_size * hdr->num_rx_rings; + hdr->sds_offset = hdr->rxr_offset + QL_ALIGN(size, 64); + hdr->sds_ring_size = sizeof(q80_stat_desc_t) * NUM_STATUS_DESCRIPTORS; + hdr->sds_entries = NUM_STATUS_DESCRIPTORS; + hdr->num_sds_rings = ha->hw.num_sds_rings; + + ptr = state_buffer + hdr->sds_offset; + for (i = 0; i < ha->hw.num_sds_rings; i++) { + bcopy(ha->hw.dma_buf.sds_ring[i].dma_b, ptr, hdr->sds_ring_size); + ptr += hdr->sds_ring_size; + } + return; +} + +void +ql_alloc_drvr_state_buffer(qla_host_t *ha) +{ + uint32_t drvr_state_size; + + drvr_state_size = ql_drvr_state_size(ha); + + ha->hw.drvr_state = malloc(drvr_state_size, M_QLA83XXBUF, M_NOWAIT); + + return; +} + +void +ql_free_drvr_state_buffer(qla_host_t *ha) +{ + if (ha->hw.drvr_state != NULL) + free(ha->hw.drvr_state, M_QLA83XXBUF); + return; +} + diff --git a/sys/dev/qlxgbe/ql_ioctl.h b/sys/dev/qlxgbe/ql_ioctl.h index 8787af4e6..f985958a7 100644 --- a/sys/dev/qlxgbe/ql_ioctl.h +++ b/sys/dev/qlxgbe/ql_ioctl.h @@ -93,6 +93,72 @@ struct qla_rd_fw_dump { }; typedef struct qla_rd_fw_dump qla_rd_fw_dump_t; +struct qla_drvr_state_tx { + uint64_t base_p_addr; + uint64_t cons_p_addr; + uint32_t tx_prod_reg; + uint32_t tx_cntxt_id; + uint32_t txr_free; + uint32_t txr_next; + uint32_t txr_comp; +}; +typedef struct qla_drvr_state_tx qla_drvr_state_tx_t; + +struct qla_drvr_state_sds { + uint32_t sdsr_next; /* next entry in SDS ring to process */ + uint32_t sds_consumer; +}; +typedef struct qla_drvr_state_sds qla_drvr_state_sds_t; + +struct qla_drvr_state_rx { + uint32_t prod_std; + uint32_t rx_next; /* next standard rcv ring to arm fw */; +}; +typedef struct qla_drvr_state_rx qla_drvr_state_rx_t; + +struct qla_drvr_state_hdr { + uint32_t drvr_version_major; + uint32_t drvr_version_minor; + uint32_t drvr_version_build; + + uint8_t mac_addr[ETHER_ADDR_LEN]; + uint16_t link_speed; + uint16_t cable_length; + uint32_t cable_oui; + uint8_t link_up; + uint8_t module_type; + uint8_t link_faults; + uint32_t rcv_intr_coalesce; + uint32_t xmt_intr_coalesce; + + uint32_t tx_state_offset;/* size = sizeof (qla_drvr_state_tx_t) * num_tx_rings */ + uint32_t rx_state_offset;/* size = sizeof (qla_drvr_state_rx_t) * num_rx_rings */ + uint32_t sds_state_offset;/* size = sizeof (qla_drvr_state_sds_t) * num_sds_rings */ + + uint32_t num_tx_rings; /* number of tx rings */ + uint32_t txr_size; /* size of each tx ring in bytes */ + uint32_t txr_entries; /* number of descriptors in each tx ring */ + uint32_t txr_offset; /* start of tx ring [0 - #rings] content */ + + uint32_t num_rx_rings; /* number of rx rings */ + uint32_t rxr_size; /* size of each rx ring in bytes */ + uint32_t rxr_entries; /* number of descriptors in each rx ring */ + uint32_t rxr_offset; /* start of rx ring [0 - #rings] content */ + + uint32_t num_sds_rings; /* number of sds rings */ + uint32_t sds_ring_size; /* size of each sds ring in bytes */ + uint32_t sds_entries; /* number of descriptors in each sds ring */ + uint32_t sds_offset; /* start of sds ring [0 - #rings] content */ +}; + +typedef struct qla_drvr_state_hdr qla_drvr_state_hdr_t; + +struct qla_driver_state { + uint32_t size; + void *buffer; +}; +typedef struct qla_driver_state qla_driver_state_t; + /* * Read/Write Register */ @@ -133,4 +199,10 @@ typedef struct qla_rd_fw_dump qla_rd_fw_dump_t; */ #define QLA_RD_FW_DUMP _IOWR('q', 8, qla_rd_fw_dump_t) +/* + * Read Driver State + */ +#define QLA_RD_DRVR_STATE _IOWR('q', 9, qla_driver_state_t) + + #endif /* #ifndef _QL_IOCTL_H_ */ diff --git a/sys/dev/qlxgbe/ql_os.c b/sys/dev/qlxgbe/ql_os.c index 6ed682b60..0accee7bf 100644 --- a/sys/dev/qlxgbe/ql_os.c +++ b/sys/dev/qlxgbe/ql_os.c @@ -492,6 +492,7 @@ qla_pci_attach(device_t dev) device_printf(dev, "%s: ql_minidump_init failed\n", __func__); goto qla_pci_attach_err; } + ql_alloc_drvr_state_buffer(ha); /* create the o.s ethernet interface */ qla_init_ifnet(dev, ha); @@ -645,6 +646,7 @@ qla_release(qla_host_t *ha) if (ha->ifp != NULL) ether_ifdetach(ha->ifp); + ql_free_drvr_state_buffer(ha); ql_free_dma(ha); qla_free_parent_dma_tag(ha); diff --git a/sys/dev/qlxgbe/ql_ver.h b/sys/dev/qlxgbe/ql_ver.h index e6c06ed29..24a9d30d1 100644 --- a/sys/dev/qlxgbe/ql_ver.h +++ b/sys/dev/qlxgbe/ql_ver.h @@ -36,6 +36,6 @@ #define QLA_VERSION_MAJOR 3 #define QLA_VERSION_MINOR 10 -#define QLA_VERSION_BUILD 34 +#define QLA_VERSION_BUILD 35 #endif /* #ifndef _QL_VER_H_ */ -- 2.42.0