* [net-next PATCH 0/8] qlge: Add firmware coredump functionality.
@ 2010-01-12 1:12 Ron Mercer
2010-01-12 1:12 ` [net-next PATCH 1/8] qlge: Add data for firmware dump Ron Mercer
` (8 more replies)
0 siblings, 9 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:12 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Dump all regsiters and on chip RAM when a fatal firmware error is
encountered. This features is turn on by default but can be
turned off with a module parameter.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [net-next PATCH 1/8] qlge: Add data for firmware dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
@ 2010-01-12 1:12 ` Ron Mercer
2010-01-12 6:20 ` David Miller
2010-01-12 1:12 ` [net-next PATCH 2/8] qlge: Add basic " Ron Mercer
` (7 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:12 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 285 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 284 insertions(+), 1 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index ee0e2bd..0094263 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -75,6 +75,16 @@
#define TX_DESC_PER_OAL 0
#endif
+/* Word shifting for converting 64-bit
+ * address to a series of 16-bit words.
+ * This is used for some MPI firmware
+ * mailbox commands.
+ */
+#define LSW(x) ((u16)(x))
+#define MSW(x) ((u16)((u32)(x) >> 16))
+#define LSD(x) ((u32)((u64)(x)))
+#define MSD(x) ((u32)((((u64)(x)) >> 16) >> 16))
+
/* MPI test register definitions. This register
* is used for determining alternate NIC function's
* PCI->func number.
@@ -464,7 +474,7 @@ enum {
MDIO_PORT = 0x00000440,
MDIO_STATUS = 0x00000450,
- /* XGMAC AUX statistics registers */
+ XGMAC_REGISTER_END = 0x00000740,
};
/*
@@ -664,6 +674,14 @@ enum {
};
/*
+ * Serdes Address Register (XG_SERDES_ADDR) bit definitions.
+ */
+enum {
+ XG_SERDES_ADDR_RDY = (1 << 31),
+ XG_SERDES_ADDR_R = (1 << 30),
+};
+
+/*
* Control Register Set Map
*/
enum {
@@ -1538,6 +1556,60 @@ enum {
};
+/* Probe dump constants */
+/* 64 probes, 8 bytes per probe + 4 bytes to list the probe ID */
+#define PROBE_DATA_LENGTH_WORDS ((64*2) + 1)
+#define NUMBER_OF_PROBES 34
+#define NUMBER_ROUTING_REG_ENTRIES 48
+#define WORDS_PER_ROUTING_REG_ENTRY 4
+#define MAC_PROTOCOL_REGISTER_WORDS ((512 * 3) + (32 * 2) + (4096 * 1) + \
+(4096 * 1) + (4 * 2) + (8 * 2) + (16 * 1) + (4 * 1) + (4 * 4) + (4 * 1))
+
+/* Save both the address and data register */
+#define WORDS_PER_MAC_PROT_ENTRY 2
+#define MAX_SEMAPHORE_FUNCTIONS 5
+#define WQC_WORD_SIZE 6
+#define NUMBER_OF_WQCS 128
+#define CQC_WORD_SIZE 13
+#define NUMBER_OF_CQCS 128
+
+#define MPI_READ 0x00000000
+#define REG_BLOCK 0x00020000
+#define TEST_LOGIC_FUNC_PORT_CONFIG 0x1002
+#define NIC1_FUNCTION_ENABLE 0x00000001
+#define NIC1_FUNCTION_MASK 0x0000000e
+#define NIC1_FUNCTION_SHIFT 1
+#define NIC2_FUNCTION_ENABLE 0x00000010
+#define NIC2_FUNCTION_MASK 0x000000e0
+#define NIC2_FUNCTION_SHIFT 5
+#define FC1_FUNCTION_ENABLE 0x00000100
+#define FC1_FUNCTION_MASK 0x00000e00
+#define FC1_FUNCTION_SHIFT 9
+#define FC2_FUNCTION_ENABLE 0x00001000
+#define FC2_FUNCTION_MASK 0x0000e000
+#define FC2_FUNCTION_SHIFT 13
+#define FUNCTION_SHIFT 6
+
+#define XFI1_POWERED_UP 0x00000005
+#define XFI2_POWERED_UP 0x0000000A
+#define XAUI_POWERED_DOWN 0x00000001
+
+#define RISC_124 0x0003007c
+#define RISC_127 0x0003007f
+#define SHADOW_OFFSET 0xb0000000
+
+#define SYS_CLOCK (0x00)
+#define PCI_CLOCK (0x80)
+#define FC_CLOCK (0x140)
+#define XGM_CLOCK (0x180)
+#define ADDRESS_REGISTER_ENABLE 0x00010000
+#define UP 0x00008000
+#define MAX_MUX 0x40
+#define MAX_MODULES 0x1F
+#define RS_AND_ADR 0x06000000
+#define RS_ONLY 0x04000000
+#define NUM_TYPES 10
+
struct ql_nic_misc {
u32 rx_ring_count;
u32 tx_ring_count;
@@ -1579,6 +1651,214 @@ struct ql_reg_dump {
u32 ets[8+2];
};
+struct ql_mpi_coredump {
+ /* segment 0 */
+ struct mpi_coredump_global_header mpi_global_header;
+
+ /* segment 1 */
+ struct mpi_coredump_segment_header core_regs_seg_hdr;
+ u32 mpi_core_regs[MPI_CORE_REGS_CNT];
+ u32 mpi_core_sh_regs[MPI_CORE_SH_REGS_CNT];
+
+ /* segment 2 */
+ struct mpi_coredump_segment_header test_logic_regs_seg_hdr;
+ u32 test_logic_regs[TEST_REGS_CNT];
+
+ /* segment 3 */
+ struct mpi_coredump_segment_header rmii_regs_seg_hdr;
+ u32 rmii_regs[RMII_REGS_CNT];
+
+ /* segment 4 */
+ struct mpi_coredump_segment_header fcmac1_regs_seg_hdr;
+ u32 fcmac1_regs[FCMAC_REGS_CNT];
+
+ /* segment 5 */
+ struct mpi_coredump_segment_header fcmac2_regs_seg_hdr;
+ u32 fcmac2_regs[FCMAC_REGS_CNT];
+
+ /* segment 6 */
+ struct mpi_coredump_segment_header fc1_mbx_regs_seg_hdr;
+ u32 fc1_mbx_regs[FC_MBX_REGS_CNT];
+
+ /* segment 7 */
+ struct mpi_coredump_segment_header ide_regs_seg_hdr;
+ u32 ide_regs[IDE_REGS_CNT];
+
+ /* segment 8 */
+ struct mpi_coredump_segment_header nic1_mbx_regs_seg_hdr;
+ u32 nic1_mbx_regs[NIC_MBX_REGS_CNT];
+
+ /* segment 9 */
+ struct mpi_coredump_segment_header smbus_regs_seg_hdr;
+ u32 smbus_regs[SMBUS_REGS_CNT];
+
+ /* segment 10 */
+ struct mpi_coredump_segment_header fc2_mbx_regs_seg_hdr;
+ u32 fc2_mbx_regs[FC_MBX_REGS_CNT];
+
+ /* segment 11 */
+ struct mpi_coredump_segment_header nic2_mbx_regs_seg_hdr;
+ u32 nic2_mbx_regs[NIC_MBX_REGS_CNT];
+
+ /* segment 12 */
+ struct mpi_coredump_segment_header i2c_regs_seg_hdr;
+ u32 i2c_regs[I2C_REGS_CNT];
+ /* segment 13 */
+ struct mpi_coredump_segment_header memc_regs_seg_hdr;
+ u32 memc_regs[MEMC_REGS_CNT];
+
+ /* segment 14 */
+ struct mpi_coredump_segment_header pbus_regs_seg_hdr;
+ u32 pbus_regs[PBUS_REGS_CNT];
+
+ /* segment 15 */
+ struct mpi_coredump_segment_header mde_regs_seg_hdr;
+ u32 mde_regs[MDE_REGS_CNT];
+
+ /* segment 16 */
+ struct mpi_coredump_segment_header nic_regs_seg_hdr;
+ u32 nic_regs[64];
+
+ /* segment 17 */
+ struct mpi_coredump_segment_header nic2_regs_seg_hdr;
+ u32 nic2_regs[64];
+
+ /* segment 18 */
+ struct mpi_coredump_segment_header xgmac1_seg_hdr;
+ u32 xgmac1[XGMAC_REGISTER_END / 4];
+
+ /* segment 19 */
+ struct mpi_coredump_segment_header xgmac2_seg_hdr;
+ u32 xgmac2[XGMAC_REGISTER_END / 4];
+
+ /* segment 20 */
+ struct mpi_coredump_segment_header code_ram_seg_hdr;
+ u32 code_ram[CODE_RAM_CNT];
+
+ /* segment 21 */
+ struct mpi_coredump_segment_header memc_ram_seg_hdr;
+ u32 memc_ram[MEMC_RAM_CNT];
+
+ /* segment 22 */
+ struct mpi_coredump_segment_header xaui_an_hdr;
+ u32 serdes_xaui_an[14];
+
+ /* segment 23 */
+ struct mpi_coredump_segment_header xaui_hss_pcs_hdr;
+ u32 serdes_xaui_hss_pcs[33];
+
+ /* segment 24 */
+ struct mpi_coredump_segment_header xfi_an_hdr;
+ u32 serdes_xfi_an[14];
+
+ /* segment 25 */
+ struct mpi_coredump_segment_header xfi_train_hdr;
+ u32 serdes_xfi_train[12];
+
+ /* segment 26 */
+ struct mpi_coredump_segment_header xfi_hss_pcs_hdr;
+ u32 serdes_xfi_hss_pcs[15];
+
+ /* segment 27 */
+ struct mpi_coredump_segment_header xfi_hss_tx_hdr;
+ u32 serdes_xfi_hss_tx[32];
+
+ /* segment 28 */
+ struct mpi_coredump_segment_header xfi_hss_rx_hdr;
+ u32 serdes_xfi_hss_rx[32];
+
+ /* segment 29 */
+ struct mpi_coredump_segment_header xfi_hss_pll_hdr;
+ u32 serdes_xfi_hss_pll[32];
+
+ /* segment 30 */
+ struct mpi_coredump_segment_header misc_nic_seg_hdr;
+ struct ql_nic_misc misc_nic_info;
+
+ /* segment 31 */
+ /* one interrupt state for each CQ */
+ struct mpi_coredump_segment_header intr_states_seg_hdr;
+ u32 intr_states[MAX_RX_RINGS];
+
+ /* segment 32 */
+ /* 3 cam words each for 16 unicast,
+ * 2 cam words for each of 32 multicast.
+ */
+ struct mpi_coredump_segment_header cam_entries_seg_hdr;
+ u32 cam_entries[(16 * 3) + (32 * 3)];
+
+ /* segment 33 */
+ struct mpi_coredump_segment_header nic_routing_words_seg_hdr;
+ u32 nic_routing_words[16];
+
+ /* segment 34 */
+ struct mpi_coredump_segment_header ets_seg_hdr;
+ u32 ets[8+2];
+
+ /* segment 35 */
+ struct mpi_coredump_segment_header probe_dump_seg_hdr;
+ u32 probe_dump[PROBE_DATA_LENGTH_WORDS * NUMBER_OF_PROBES];
+
+ /* segment 36 */
+ struct mpi_coredump_segment_header routing_reg_seg_hdr;
+ u32 routing_regs[NUMBER_ROUTING_REG_ENTRIES *
+ WORDS_PER_ROUTING_REG_ENTRY];
+
+ /* segment 37 */
+ struct mpi_coredump_segment_header mac_prot_reg_seg_hdr;
+ u32 mac_prot_regs[MAC_PROTOCOL_REGISTER_WORDS *
+ WORDS_PER_MAC_PROT_ENTRY];
+
+ /* segment 38 */
+ struct mpi_coredump_segment_header xaui2_an_hdr;
+ u32 serdes2_xaui_an[14];
+
+ /* segment 39 */
+ struct mpi_coredump_segment_header xaui2_hss_pcs_hdr;
+ u32 serdes2_xaui_hss_pcs[33];
+
+ /* segment 40 */
+ struct mpi_coredump_segment_header xfi2_an_hdr;
+ u32 serdes2_xfi_an[14];
+
+ /* segment 41 */
+ struct mpi_coredump_segment_header xfi2_train_hdr;
+ u32 serdes2_xfi_train[12];
+
+ /* segment 42 */
+ struct mpi_coredump_segment_header xfi2_hss_pcs_hdr;
+ u32 serdes2_xfi_hss_pcs[15];
+
+ /* segment 43 */
+ struct mpi_coredump_segment_header xfi2_hss_tx_hdr;
+ u32 serdes2_xfi_hss_tx[32];
+
+ /* segment 44 */
+ struct mpi_coredump_segment_header xfi2_hss_rx_hdr;
+ u32 serdes2_xfi_hss_rx[32];
+
+ /* segment 45 */
+ struct mpi_coredump_segment_header xfi2_hss_pll_hdr;
+ u32 serdes2_xfi_hss_pll[32];
+
+ /* segment 50 */
+ /* semaphore register for all 5 functions */
+ struct mpi_coredump_segment_header sem_regs_seg_hdr;
+ u32 sem_regs[MAX_SEMAPHORE_FUNCTIONS];
+
+ struct mpi_coredump_segment_header wqc1_seg_hdr;
+ u32 wqc1[WQC_WORD_SIZE * NUMBER_OF_WQCS];
+
+ struct mpi_coredump_segment_header cqc1_seg_hdr;
+ u32 cqc1[CQC_WORD_SIZE * NUMBER_OF_CQCS];
+
+ struct mpi_coredump_segment_header wqc2_seg_hdr;
+ u32 wqc2[WQC_WORD_SIZE * NUMBER_OF_WQCS];
+
+ struct mpi_coredump_segment_header cqc2_seg_hdr;
+ u32 cqc2[CQC_WORD_SIZE * NUMBER_OF_CQCS];
+};
+
/*
* intr_context structure is used during initialization
* to hook the interrupts. It is also used in a single
@@ -1735,6 +2015,8 @@ struct ql_adapter {
u32 port_link_up;
u32 port_init;
u32 link_status;
+ struct ql_mpi_coredump *mpi_coredump;
+ u32 core_is_dumped;
u32 link_config;
u32 led_config;
u32 max_frame_size;
@@ -1747,6 +2029,7 @@ struct ql_adapter {
struct delayed_work mpi_work;
struct delayed_work mpi_port_cfg_work;
struct delayed_work mpi_idc_work;
+ struct delayed_work mpi_core_to_log;
struct completion ide_completion;
struct nic_operations *nic_ops;
u16 device_id;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 2/8] qlge: Add basic firmware dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
2010-01-12 1:12 ` [net-next PATCH 1/8] qlge: Add data for firmware dump Ron Mercer
@ 2010-01-12 1:12 ` Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 3/8] qlge: Add probe regs to " Ron Mercer
` (6 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:12 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Adding the infrstructure and basic data for the firmware
core dump.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 6 +
drivers/net/qlge/qlge_dbg.c | 544 ++++++++++++++++++++++++++++++++++++++++++
drivers/net/qlge/qlge_main.c | 19 ++
drivers/net/qlge/qlge_mpi.c | 78 ++++++
4 files changed, 647 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 0094263..826ca54 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -2101,6 +2101,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
void ql_queue_fw_error(struct ql_adapter *qdev);
void ql_mpi_work(struct work_struct *work);
void ql_mpi_reset_work(struct work_struct *work);
+void ql_mpi_core_to_log(struct work_struct *work);
int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit);
void ql_queue_asic_error(struct ql_adapter *qdev);
u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
@@ -2111,6 +2112,11 @@ void ql_mpi_port_cfg_work(struct work_struct *work);
int ql_mb_get_fw_state(struct ql_adapter *qdev);
int ql_cam_route_initialize(struct ql_adapter *qdev);
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
+int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data);
+int ql_unpause_mpi_risc(struct ql_adapter *qdev);
+int ql_pause_mpi_risc(struct ql_adapter *qdev);
+int ql_core_dump(struct ql_adapter *qdev,
+ struct ql_mpi_coredump *mpi_coredump);
int ql_mb_about_fw(struct ql_adapter *qdev);
int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 9f58c47..bacad16 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,6 +1,30 @@
#include "qlge.h"
+/* Read out the SERDES registers */
+int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
+{
+ int status;
+
+ /* wait for reg to come ready */
+ status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* set up for reg read */
+ ql_write32(qdev, XG_SERDES_ADDR, reg | PROC_ADDR_R);
+ /* wait for reg to come ready */
+ status = ql_wait_reg_rdy(qdev, XG_SERDES_ADDR, XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* get the data */
+ *data = ql_read32(qdev, XG_SERDES_DATA);
+exit:
+ return status;
+}
+
+/* Read out the ETS registers */
static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
{
int status = 0;
@@ -19,6 +43,7 @@ static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
return status;
}
+/* For each RX Ring, read the interrupt enable register */
static void ql_get_intr_states(struct ql_adapter *qdev, u32 * buf)
{
int i;
@@ -91,6 +116,165 @@ err:
return status;
}
+/* Read the MPI Processor shadow registers */
+static int ql_get_mpi_shadow_regs(struct ql_adapter *qdev, u32 * buf)
+{
+ u32 i;
+ int status;
+
+ for (i = 0; i < MPI_CORE_SH_REGS_CNT; i++, buf++) {
+ status = ql_write_mpi_reg(qdev, RISC_124,
+ (SHADOW_OFFSET | i << 20));
+ if (status)
+ goto end;
+ status = ql_read_mpi_reg(qdev, RISC_127, buf);
+ if (status)
+ goto end;
+ }
+end:
+ return status;
+}
+
+/* Read the MPI Processor core registers */
+static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf,
+ u32 offset, u32 count)
+{
+ int i, status = 0;
+ for (i = 0; i < count; i++, buf++) {
+ status = ql_read_mpi_reg(qdev, offset + i, buf);
+ if (status)
+ return status;
+ }
+ return status;
+}
+
+
+/* Read out the routing index registers */
+static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf)
+{
+ int status;
+ u32 type, index, index_max;
+ u32 result_index;
+ u32 result_data;
+ u32 val;
+
+ status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+ if (status)
+ return status;
+
+ for (type = 0; type < 4; type++) {
+ if (type < 2)
+ index_max = 8;
+ else
+ index_max = 16;
+ for (index = 0; index < index_max; index++) {
+ val = 0x04000000 | (type << 16) | (index << 8);
+ ql_write32(qdev, RT_IDX, val);
+ result_index = 0;
+ while ((result_index & 0x40000000) == 0)
+ result_index = ql_read32(qdev, RT_IDX);
+ result_data = ql_read32(qdev, RT_DATA);
+ *buf = type;
+ buf++;
+ *buf = index;
+ buf++;
+ *buf = result_index;
+ buf++;
+ *buf = result_data;
+ buf++;
+ }
+ }
+ ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+ return status;
+}
+
+/* Read out the MAC protocol registers */
+static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
+{
+ u32 result_index, result_data;
+ u32 type;
+ u32 index;
+ u32 offset;
+ u32 val;
+ u32 initial_val = 0;
+ u32 max_index;
+ u32 max_offset;
+
+ for (type = 0; type < NUM_TYPES; type++) {
+ switch (type) {
+
+ case 0: /* CAM */
+ initial_val = RS_AND_ADR;
+ max_index = 512;
+ max_offset = 3;
+ break;
+ case 1: /* Multicast MAC Address */
+ initial_val = RS_ONLY;
+ max_index = 32;
+ max_offset = 2;
+ break;
+ case 2: /* VLAN filter mask */
+ case 3: /* MC filter mask */
+ initial_val = RS_ONLY;
+ max_index = 4096;
+ max_offset = 1;
+ break;
+ case 4: /* FC MAC addresses */
+ initial_val = RS_ONLY;
+ max_index = 4;
+ max_offset = 2;
+ break;
+ case 5: /* Mgmt MAC addresses */
+ initial_val = RS_ONLY;
+ max_index = 8;
+ max_offset = 2;
+ break;
+ case 6: /* Mgmt VLAN addresses */
+ initial_val = RS_ONLY;
+ max_index = 16;
+ max_offset = 1;
+ break;
+ case 7: /* Mgmt IPv4 address */
+ initial_val = RS_ONLY;
+ max_index = 4;
+ max_offset = 1;
+ break;
+ case 8: /* Mgmt IPv6 address */
+ initial_val = RS_ONLY;
+ max_index = 4;
+ max_offset = 4;
+ break;
+ case 9: /* Mgmt TCP/UDP Dest port */
+ initial_val = RS_ONLY;
+ max_index = 4;
+ max_offset = 1;
+ break;
+ default:
+ printk(KERN_ERR "Bad type!!! 0x%08x\n", type);
+ max_index = 0;
+ max_offset = 0;
+ break;
+ }
+ for (index = 0; index < max_index; index++) {
+ for (offset = 0; offset < max_offset; offset++) {
+ val = initial_val | (type << 16) |
+ (index << 4) | (offset);
+ ql_write32(qdev, MAC_ADDR_IDX, val);
+ result_index = 0;
+ while ((result_index & 0x40000000) == 0) {
+ result_index = ql_read32(qdev,
+ MAC_ADDR_IDX);
+ }
+ result_data = ql_read32(qdev, MAC_ADDR_DATA);
+ *buf = result_index;
+ buf++;
+ *buf = result_data;
+ buf++;
+ }
+ }
+ }
+}
+
/* Create a coredump segment header */
static void ql_build_coredump_seg_header(
struct mpi_coredump_segment_header *seg_hdr,
@@ -103,6 +287,339 @@ static void ql_build_coredump_seg_header(
memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
}
+
+/*
+ * This function should be called when a coredump / probedump
+ * is to be extracted from the HBA. It is assumed there is a
+ * qdev structure that contains the base address of the register
+ * space for this function as well as a coredump structure that
+ * will contain the dump.
+ */
+int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
+{
+ int status;
+ int i;
+ unsigned int func_num, reg, reg_val;
+
+ if (!mpi_coredump) {
+ QPRINTK(qdev, DRV, ERR,
+ "No memory available.\n");
+ return -ENOMEM;
+ }
+
+ /* Try to get the spinlock, but dont worry if
+ * it isn't available. If the firmware died it
+ * might be holding the sem.
+ */
+ ql_sem_spinlock(qdev, SEM_PROC_REG_MASK);
+
+ status = ql_pause_mpi_risc(qdev);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed RISC pause. Status = 0x%.08x\n", status);
+ goto err;
+ }
+
+ /* Insert the global header */
+ memset(&(mpi_coredump->mpi_global_header), 0,
+ sizeof(struct mpi_coredump_global_header));
+ mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
+ mpi_coredump->mpi_global_header.headerSize =
+ sizeof(struct mpi_coredump_global_header);
+ mpi_coredump->mpi_global_header.imageSize =
+ sizeof(struct ql_mpi_coredump);
+ memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+ sizeof(mpi_coredump->mpi_global_header.idString));
+
+ /* Get generic NIC reg dump */
+ ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr,
+ NIC1_CONTROL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->nic_regs), "NIC1 Registers");
+
+ if (qdev->func & 1) {
+ /* Odd means our function is NIC 2 */
+ for (i = 0; i < 64; i++)
+ mpi_coredump->nic2_regs[i] =
+ ql_read32(qdev, i * sizeof(u32));
+ } else {
+ /* Even means our function is NIC 1 */
+ for (i = 0; i < 64; i++)
+ mpi_coredump->nic_regs[i] =
+ ql_read32(qdev, i * sizeof(u32));
+ }
+
+ ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
+ CORE_SEG_NUM,
+ sizeof(mpi_coredump->core_regs_seg_hdr) +
+ sizeof(mpi_coredump->mpi_core_regs) +
+ sizeof(mpi_coredump->mpi_core_sh_regs),
+ "Core Registers");
+
+ /* Get the MPI Core Registers */
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->mpi_core_regs[0],
+ MPI_CORE_REGS_ADDR, MPI_CORE_REGS_CNT);
+ if (status)
+ goto err;
+ /* Get the 16 MPI shadow registers */
+ status = ql_get_mpi_shadow_regs(qdev,
+ &mpi_coredump->mpi_core_sh_regs[0]);
+ if (status)
+ goto err;
+
+ /* Get the Test Logic Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->test_logic_regs_seg_hdr,
+ TEST_LOGIC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->test_logic_regs),
+ "Test Logic Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->test_logic_regs[0],
+ TEST_REGS_ADDR, TEST_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the RMII Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->rmii_regs_seg_hdr,
+ RMII_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->rmii_regs),
+ "RMII Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->rmii_regs[0],
+ RMII_REGS_ADDR, RMII_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FCMAC1 Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->fcmac1_regs_seg_hdr,
+ FCMAC1_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fcmac1_regs),
+ "FCMAC1 Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac1_regs[0],
+ FCMAC1_REGS_ADDR, FCMAC_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FCMAC2 Registers */
+
+ ql_build_coredump_seg_header(&mpi_coredump->fcmac2_regs_seg_hdr,
+ FCMAC2_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fcmac2_regs),
+ "FCMAC2 Registers");
+
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fcmac2_regs[0],
+ FCMAC2_REGS_ADDR, FCMAC_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FC1 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->fc1_mbx_regs_seg_hdr,
+ FC1_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fc1_mbx_regs),
+ "FC1 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fc1_mbx_regs[0],
+ FC1_MBX_REGS_ADDR, FC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the IDE Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->ide_regs_seg_hdr,
+ IDE_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->ide_regs),
+ "IDE Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->ide_regs[0],
+ IDE_REGS_ADDR, IDE_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the NIC1 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->nic1_mbx_regs_seg_hdr,
+ NIC1_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic1_mbx_regs),
+ "NIC1 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->nic1_mbx_regs[0],
+ NIC1_MBX_REGS_ADDR, NIC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the SMBus Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->smbus_regs_seg_hdr,
+ SMBUS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->smbus_regs),
+ "SMBus Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->smbus_regs[0],
+ SMBUS_REGS_ADDR, SMBUS_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the FC2 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->fc2_mbx_regs_seg_hdr,
+ FC2_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->fc2_mbx_regs),
+ "FC2 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->fc2_mbx_regs[0],
+ FC2_MBX_REGS_ADDR, FC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the NIC2 MBX Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->nic2_mbx_regs_seg_hdr,
+ NIC2_MBOX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic2_mbx_regs),
+ "NIC2 MBox Regs");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->nic2_mbx_regs[0],
+ NIC2_MBX_REGS_ADDR, NIC_MBX_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the I2C Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->i2c_regs_seg_hdr,
+ I2C_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->i2c_regs),
+ "I2C Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->i2c_regs[0],
+ I2C_REGS_ADDR, I2C_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the MEMC Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->memc_regs_seg_hdr,
+ MEMC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->memc_regs),
+ "MEMC Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->memc_regs[0],
+ MEMC_REGS_ADDR, MEMC_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the PBus Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->pbus_regs_seg_hdr,
+ PBUS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->pbus_regs),
+ "PBUS Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->pbus_regs[0],
+ PBUS_REGS_ADDR, PBUS_REGS_CNT);
+ if (status)
+ goto err;
+
+ /* Get the MDE Registers */
+ ql_build_coredump_seg_header(&mpi_coredump->mde_regs_seg_hdr,
+ MDE_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->mde_regs),
+ "MDE Registers");
+ status = ql_get_mpi_regs(qdev, &mpi_coredump->mde_regs[0],
+ MDE_REGS_ADDR, MDE_REGS_CNT);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr,
+ MISC_NIC_INFO_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->misc_nic_info),
+ "MISC NIC INFO");
+ mpi_coredump->misc_nic_info.rx_ring_count = qdev->rx_ring_count;
+ mpi_coredump->misc_nic_info.tx_ring_count = qdev->tx_ring_count;
+ mpi_coredump->misc_nic_info.intr_count = qdev->intr_count;
+ mpi_coredump->misc_nic_info.function = qdev->func;
+
+ /* Segment 31 */
+ /* Get indexed register values. */
+ ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr,
+ INTR_STATES_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->intr_states),
+ "INTR States");
+ ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]);
+
+ ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr,
+ CAM_ENTRIES_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->cam_entries),
+ "CAM Entries");
+ status = ql_get_cam_entries(qdev, &mpi_coredump->cam_entries[0]);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr,
+ ROUTING_WORDS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->nic_routing_words),
+ "Routing Words");
+ status = ql_get_routing_entries(qdev,
+ &mpi_coredump->nic_routing_words[0]);
+ if (status)
+ goto err;
+
+ /* Segment 34 (Rev C. step 23) */
+ ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr,
+ ETS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->ets),
+ "ETS Registers");
+ status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr,
+ ROUTING_INDEX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->routing_regs),
+ "Routing Regs");
+ status = ql_get_routing_index_registers(qdev,
+ &mpi_coredump->routing_regs[0]);
+ if (status)
+ goto err;
+
+ ql_build_coredump_seg_header(&mpi_coredump->mac_prot_reg_seg_hdr,
+ MAC_PROTOCOL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->mac_prot_regs),
+ "MAC Prot Regs");
+ ql_get_mac_protocol_registers(qdev, &mpi_coredump->mac_prot_regs[0]);
+
+ /* Get the semaphore registers for all 5 functions */
+ ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr,
+ SEM_REGS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->sem_regs), "Sem Registers");
+
+ for (func_num = 0; func_num < MAX_SEMAPHORE_FUNCTIONS ; func_num++) {
+ reg = REG_BLOCK | (func_num << FUNCTION_SHIFT) | (SEM / 4);
+ status = ql_read_mpi_reg(qdev, reg, ®_val);
+ mpi_coredump->sem_regs[func_num] = reg_val;
+ if (status != 0)
+ mpi_coredump->sem_regs[func_num] = 0xdeadbeef;
+ }
+
+ /* not in the spec... but we need to prevent the mpi restarting
+ * while we dump the memory
+ */
+ ql_write_mpi_reg(qdev, 0x100a, 0x3);
+
+ /* clear the pause */
+ status = ql_unpause_mpi_risc(qdev);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed RISC unpause. Status = 0x%.08x\n", status);
+ goto err;
+ }
+err:
+ ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */
+ return status;
+
+}
+
void ql_gen_reg_dump(struct ql_adapter *qdev,
struct ql_reg_dump *mpi_coredump)
{
@@ -180,6 +697,33 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
return;
}
+/* Coredump to messages log file using separate worker thread */
+void ql_mpi_core_to_log(struct work_struct *work)
+{
+ struct ql_adapter *qdev =
+ container_of(work, struct ql_adapter, mpi_core_to_log.work);
+ u32 *tmp, count;
+ int i;
+
+ count = sizeof(struct ql_mpi_coredump) / sizeof(u32);
+ tmp = (u32 *)qdev->mpi_coredump;
+ QPRINTK(qdev, DRV, DEBUG, "Core is dumping to log file!\n");
+
+ for (i = 0; i < count; i += 8) {
+ printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
+ "%.08x %.08x %.08x \n", i,
+ tmp[i + 0],
+ tmp[i + 1],
+ tmp[i + 2],
+ tmp[i + 3],
+ tmp[i + 4],
+ tmp[i + 5],
+ tmp[i + 6],
+ tmp[i + 7]);
+ msleep(5);
+ }
+}
+
#ifdef QL_REG_DUMP
static void ql_dump_intr_states(struct ql_adapter *qdev)
{
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 167a3da..9106c08 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -73,6 +73,12 @@ static int qlge_irq_type = MSIX_IRQ;
module_param(qlge_irq_type, int, MSIX_IRQ);
MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
+static int qlge_mpi_coredump = 1;
+module_param(qlge_mpi_coredump, int, 0);
+MODULE_PARM_DESC(qlge_mpi_coredump,
+ "Option to enable allocation of memory for an MPI "
+ "firmware dump. Default is 1 - allocate memory.");
+
static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
@@ -3842,6 +3848,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
cancel_delayed_work_sync(&qdev->mpi_reset_work);
cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work);
+ cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
for (i = 0; i < qdev->rss_ring_count; i++)
@@ -4398,6 +4405,7 @@ static void ql_release_all(struct pci_dev *pdev)
iounmap(qdev->reg_base);
if (qdev->doorbell_area)
iounmap(qdev->doorbell_area);
+ vfree(qdev->mpi_coredump);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -4479,6 +4487,15 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
spin_lock_init(&qdev->hw_lock);
spin_lock_init(&qdev->stats_lock);
+ if (qlge_mpi_coredump) {
+ qdev->mpi_coredump =
+ vmalloc(sizeof(struct ql_mpi_coredump));
+ if (qdev->mpi_coredump == NULL) {
+ dev_err(&pdev->dev, "Coredump alloc failed.\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+ }
/* make sure the EEPROM is good */
err = qdev->nic_ops->get_flash(qdev);
if (err) {
@@ -4508,6 +4525,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
+ INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
init_completion(&qdev->ide_completion);
if (!cards_found) {
@@ -4630,6 +4648,7 @@ static void ql_eeh_close(struct net_device *ndev)
cancel_delayed_work_sync(&qdev->mpi_reset_work);
cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work);
+ cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
for (i = 0; i < qdev->rss_ring_count; i++)
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index e2b2286..115bf70 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -1,5 +1,35 @@
#include "qlge.h"
+int ql_unpause_mpi_risc(struct ql_adapter *qdev)
+{
+ u32 tmp;
+
+ /* Un-pause the RISC */
+ tmp = ql_read32(qdev, CSR);
+ if (!(tmp & CSR_RP))
+ return -EIO;
+
+ ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE);
+ return 0;
+}
+
+int ql_pause_mpi_risc(struct ql_adapter *qdev)
+{
+ u32 tmp;
+ int count = UDELAY_COUNT;
+
+ /* Pause the RISC */
+ ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE);
+ do {
+ tmp = ql_read32(qdev, CSR);
+ if (tmp & CSR_RP)
+ break;
+ mdelay(UDELAY_DELAY);
+ count--;
+ } while (count);
+ return (count == 0) ? -ETIMEDOUT : 0;
+}
+
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
{
int status;
@@ -45,6 +75,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
return status;
}
+/* Determine if we are in charge of the firwmare. If
+ * we are the lower of the 2 NIC pcie functions, or if
+ * we are the higher function and the lower function
+ * is not enabled.
+ */
+int ql_own_firmware(struct ql_adapter *qdev)
+{
+ u32 temp;
+
+ /* If we are the lower of the 2 NIC functions
+ * on the chip the we are responsible for
+ * core dump and firmware reset after an error.
+ */
+ if (qdev->func < qdev->alt_func)
+ return 1;
+
+ /* If we are the higher of the 2 NIC functions
+ * on the chip and the lower function is not
+ * enabled, then we are responsible for
+ * core dump and firmware reset after an error.
+ */
+ temp = ql_read32(qdev, STS);
+ if (!(temp & (1 << (8 + qdev->alt_func))))
+ return 1;
+
+ return 0;
+
+}
+
static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
{
int i, status;
@@ -1143,5 +1202,24 @@ void ql_mpi_reset_work(struct work_struct *work)
cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work);
+ /* If we're not the dominant NIC function,
+ * then there is nothing to do.
+ */
+ if (!ql_own_firmware(qdev)) {
+ QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n");
+ return;
+ }
+
+ /* If the dump completed successfully we
+ * signal ethtool that there is information
+ * available.
+ */
+
+ if (!ql_core_dump(qdev, qdev->mpi_coredump)) {
+ QPRINTK(qdev, DRV, ERR, "Core is dumped!\n");
+ qdev->core_is_dumped = 1;
+ queue_delayed_work(qdev->workqueue,
+ &qdev->mpi_core_to_log, 5 * HZ);
+ }
ql_soft_reset_mpi_risc(qdev);
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 3/8] qlge: Add probe regs to firmware dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
2010-01-12 1:12 ` [net-next PATCH 1/8] qlge: Add data for firmware dump Ron Mercer
2010-01-12 1:12 ` [net-next PATCH 2/8] qlge: Add basic " Ron Mercer
@ 2010-01-12 1:13 ` Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 4/8] qlge: Add RAM dump " Ron Mercer
` (5 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:13 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_dbg.c | 191 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 191 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index bacad16..a822456 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -148,6 +148,190 @@ static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 * buf,
return status;
}
+/* Read the ASIC probe dump */
+static unsigned int *ql_get_probe(struct ql_adapter *qdev, u32 clock,
+ u8 *valid, u32 *buf)
+{
+ u32 module, mux_sel, probe, lo_val, hi_val;
+
+ for (module = 0; module < MAX_MODULES; module++) {
+ if (valid[module]) {
+ for (mux_sel = 0; mux_sel < MAX_MUX; mux_sel++) {
+ probe = clock | ADDRESS_REGISTER_ENABLE |
+ mux_sel | (module << 9);
+ ql_write32(qdev, PRB_MX_ADDR, probe);
+ lo_val = ql_read32(qdev, PRB_MX_DATA);
+ if (mux_sel == 0) {
+ *buf = probe;
+ buf++;
+ }
+ probe |= UP;
+ ql_write32(qdev, PRB_MX_ADDR, probe);
+ hi_val = ql_read32(qdev, PRB_MX_DATA);
+ *buf = lo_val;
+ buf++;
+ *buf = hi_val;
+ buf++;
+ }
+ }
+ }
+ return buf;
+}
+
+static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf)
+{
+
+ unsigned char sys_clock_valid_modules[0x20] = {
+ 1, /* 0x00 */
+ 1, /* 0x01 */
+ 1, /* 0x02 */
+ 0, /* 0x03 */
+ 1, /* 0x04 */
+ 1, /* 0x05 */
+ 1, /* 0x06 */
+ 1, /* 0x07 */
+ 1, /* 0x08 */
+ 1, /* 0x09 */
+ 1, /* 0x0A */
+ 1, /* 0x0B */
+ 1, /* 0x0C */
+ 1, /* 0x0D */
+ 1, /* 0x0E */
+ 0, /* 0x0F */
+ 1, /* 0x10 */
+ 1, /* 0x11 */
+ 1, /* 0x12 */
+ 1, /* 0x13 */
+ 0, /* 0x14 */
+ 0, /* 0x15 */
+ 0, /* 0x16 */
+ 0, /* 0x17 */
+ 0, /* 0x18 */
+ 0, /* 0x19 */
+ 0, /* 0x1A */
+ 0, /* 0x1B */
+ 0, /* 0x1C */
+ 0, /* 0x1D */
+ 0, /* 0x1E */
+ 0 /* 0x1F */
+ };
+
+
+ unsigned char pci_clock_valid_modules[0x20] = {
+ 1, /* 0x00 */
+ 0, /* 0x01 */
+ 0, /* 0x02 */
+ 0, /* 0x03 */
+ 0, /* 0x04 */
+ 0, /* 0x05 */
+ 1, /* 0x06 */
+ 1, /* 0x07 */
+ 0, /* 0x08 */
+ 0, /* 0x09 */
+ 0, /* 0x0A */
+ 0, /* 0x0B */
+ 0, /* 0x0C */
+ 0, /* 0x0D */
+ 1, /* 0x0E */
+ 0, /* 0x0F */
+ 0, /* 0x10 */
+ 0, /* 0x11 */
+ 0, /* 0x12 */
+ 0, /* 0x13 */
+ 0, /* 0x14 */
+ 0, /* 0x15 */
+ 0, /* 0x16 */
+ 0, /* 0x17 */
+ 0, /* 0x18 */
+ 0, /* 0x19 */
+ 0, /* 0x1A */
+ 0, /* 0x1B */
+ 0, /* 0x1C */
+ 0, /* 0x1D */
+ 0, /* 0x1E */
+ 0 /* 0x1F */
+ };
+
+ unsigned char xgm_clock_valid_modules[0x20] = {
+ 1, /* 0x00 */
+ 0, /* 0x01 */
+ 0, /* 0x02 */
+ 1, /* 0x03 */
+ 0, /* 0x04 */
+ 0, /* 0x05 */
+ 0, /* 0x06 */
+ 0, /* 0x07 */
+ 1, /* 0x08 */
+ 1, /* 0x09 */
+ 0, /* 0x0A */
+ 0, /* 0x0B */
+ 1, /* 0x0C */
+ 1, /* 0x0D */
+ 1, /* 0x0E */
+ 0, /* 0x0F */
+ 1, /* 0x10 */
+ 1, /* 0x11 */
+ 0, /* 0x12 */
+ 0, /* 0x13 */
+ 0, /* 0x14 */
+ 0, /* 0x15 */
+ 0, /* 0x16 */
+ 0, /* 0x17 */
+ 0, /* 0x18 */
+ 0, /* 0x19 */
+ 0, /* 0x1A */
+ 0, /* 0x1B */
+ 0, /* 0x1C */
+ 0, /* 0x1D */
+ 0, /* 0x1E */
+ 0 /* 0x1F */
+ };
+
+ unsigned char fc_clock_valid_modules[0x20] = {
+ 1, /* 0x00 */
+ 0, /* 0x01 */
+ 0, /* 0x02 */
+ 0, /* 0x03 */
+ 0, /* 0x04 */
+ 0, /* 0x05 */
+ 0, /* 0x06 */
+ 0, /* 0x07 */
+ 0, /* 0x08 */
+ 0, /* 0x09 */
+ 0, /* 0x0A */
+ 0, /* 0x0B */
+ 1, /* 0x0C */
+ 1, /* 0x0D */
+ 0, /* 0x0E */
+ 0, /* 0x0F */
+ 0, /* 0x10 */
+ 0, /* 0x11 */
+ 0, /* 0x12 */
+ 0, /* 0x13 */
+ 0, /* 0x14 */
+ 0, /* 0x15 */
+ 0, /* 0x16 */
+ 0, /* 0x17 */
+ 0, /* 0x18 */
+ 0, /* 0x19 */
+ 0, /* 0x1A */
+ 0, /* 0x1B */
+ 0, /* 0x1C */
+ 0, /* 0x1D */
+ 0, /* 0x1E */
+ 0 /* 0x1F */
+ };
+
+ /* First we have to enable the probe mux */
+ ql_write_mpi_reg(qdev, 0x100e, 0x18a20000);
+ buf = ql_get_probe(qdev, SYS_CLOCK, sys_clock_valid_modules, buf);
+ buf = ql_get_probe(qdev, PCI_CLOCK, pci_clock_valid_modules, buf);
+ buf = ql_get_probe(qdev, XGM_CLOCK, xgm_clock_valid_modules, buf);
+ buf = ql_get_probe(qdev, FC_CLOCK, fc_clock_valid_modules, buf);
+
+ return 0;
+
+}
/* Read out the routing index registers */
static int ql_get_routing_index_registers(struct ql_adapter *qdev, u32 *buf)
@@ -571,6 +755,13 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
if (status)
goto err;
+ ql_build_coredump_seg_header(&mpi_coredump->probe_dump_seg_hdr,
+ PROBE_DUMP_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->probe_dump),
+ "Probe Dump");
+ ql_get_probe_dump(qdev, &mpi_coredump->probe_dump[0]);
+
ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr,
ROUTING_INDEX_SEG_NUM,
sizeof(struct mpi_coredump_segment_header)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 4/8] qlge: Add RAM dump to firmware dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
` (2 preceding siblings ...)
2010-01-12 1:13 ` [net-next PATCH 3/8] qlge: Add probe regs to " Ron Mercer
@ 2010-01-12 1:13 ` Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 5/8] qlge: Add alternate function's reg dump to fw dump Ron Mercer
` (4 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:13 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 3 ++
drivers/net/qlge/qlge_dbg.c | 35 ++++++++++++++++++++
drivers/net/qlge/qlge_mpi.c | 76 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 826ca54..3f3ec57 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -2115,6 +2115,9 @@ int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data);
int ql_unpause_mpi_risc(struct ql_adapter *qdev);
int ql_pause_mpi_risc(struct ql_adapter *qdev);
+int ql_hard_reset_mpi_risc(struct ql_adapter *qdev);
+int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
+ u32 ram_addr, int word_count);
int ql_core_dump(struct ql_adapter *qdev,
struct ql_mpi_coredump *mpi_coredump);
int ql_mb_about_fw(struct ql_adapter *qdev);
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index a822456..48ff0fd 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -805,6 +805,41 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
"Failed RISC unpause. Status = 0x%.08x\n", status);
goto err;
}
+
+ /* Reset the RISC so we can dump RAM */
+ status = ql_hard_reset_mpi_risc(qdev);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed RISC reset. Status = 0x%.08x\n", status);
+ goto err;
+ }
+
+ ql_build_coredump_seg_header(&mpi_coredump->code_ram_seg_hdr,
+ WCS_RAM_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->code_ram),
+ "WCS RAM");
+ status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0],
+ CODE_RAM_ADDR, CODE_RAM_CNT);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed Dump of CODE RAM. Status = 0x%.08x\n", status);
+ goto err;
+ }
+
+ /* Insert the segment header */
+ ql_build_coredump_seg_header(&mpi_coredump->memc_ram_seg_hdr,
+ MEMC_RAM_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header)
+ + sizeof(mpi_coredump->memc_ram),
+ "MEMC RAM");
+ status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0],
+ MEMC_RAM_ADDR, MEMC_RAM_CNT);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed Dump of MEMC RAM. Status = 0x%.08x\n", status);
+ goto err;
+ }
err:
ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */
return status;
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 115bf70..0ba6b90 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -30,6 +30,25 @@ int ql_pause_mpi_risc(struct ql_adapter *qdev)
return (count == 0) ? -ETIMEDOUT : 0;
}
+int ql_hard_reset_mpi_risc(struct ql_adapter *qdev)
+{
+ u32 tmp;
+ int count = UDELAY_COUNT;
+
+ /* Reset the RISC */
+ ql_write32(qdev, CSR, CSR_CMD_SET_RST);
+ do {
+ tmp = ql_read32(qdev, CSR);
+ if (tmp & CSR_RR) {
+ ql_write32(qdev, CSR, CSR_CMD_CLR_RST);
+ break;
+ }
+ mdelay(UDELAY_DELAY);
+ count--;
+ } while (count);
+ return (count == 0) ? -ETIMEDOUT : 0;
+}
+
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
{
int status;
@@ -728,6 +747,63 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev)
return status;
}
+int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr,
+ u32 size)
+{
+ int status = 0;
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 9;
+ mbcp->out_count = 1;
+
+ mbcp->mbox_in[0] = MB_CMD_DUMP_RISC_RAM;
+ mbcp->mbox_in[1] = LSW(addr);
+ mbcp->mbox_in[2] = MSW(req_dma);
+ mbcp->mbox_in[3] = LSW(req_dma);
+ mbcp->mbox_in[4] = MSW(size);
+ mbcp->mbox_in[5] = LSW(size);
+ mbcp->mbox_in[6] = MSW(MSD(req_dma));
+ mbcp->mbox_in[7] = LSW(MSD(req_dma));
+ mbcp->mbox_in[8] = MSW(addr);
+
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed to dump risc RAM.\n");
+ status = -EIO;
+ }
+ return status;
+}
+
+/* Issue a mailbox command to dump RISC RAM. */
+int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
+ u32 ram_addr, int word_count)
+{
+ int status;
+ char *my_buf;
+ dma_addr_t buf_dma;
+
+ my_buf = pci_alloc_consistent(qdev->pdev, word_count * sizeof(u32),
+ &buf_dma);
+ if (!my_buf)
+ return -EIO;
+
+ status = ql_mb_dump_ram(qdev, buf_dma, ram_addr, word_count);
+ if (!status)
+ memcpy(buf, my_buf, word_count * sizeof(u32));
+
+ pci_free_consistent(qdev->pdev, word_count * sizeof(u32), my_buf,
+ buf_dma);
+ return status;
+}
+
/* Get link settings and maximum frame size settings
* for the current port.
* Most likely will block.
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 5/8] qlge: Add alternate function's reg dump to fw dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
` (3 preceding siblings ...)
2010-01-12 1:13 ` [net-next PATCH 4/8] qlge: Add RAM dump " Ron Mercer
@ 2010-01-12 1:13 ` Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 6/8] qlge: Add serdes reg dump to firmware dump Ron Mercer
` (3 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:13 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Get the 2nd (other) nic functions register values.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_dbg.c | 79 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 48ff0fd..63822f7 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1,5 +1,69 @@
#include "qlge.h"
+static u32 ql_get_other_func_num(struct ql_adapter *qdev)
+{
+ u32 other_function;
+ int status;
+ u32 test_logic;
+ u32 nic1_function_num = 0xffffffff;
+ u32 nic2_function_num = 0xffffffff;
+ u32 fc1_function_num = 0xffffffff;
+ u32 fc2_function_num = 0xffffffff;
+
+ status = ql_read_mpi_reg(qdev, TEST_LOGIC_FUNC_PORT_CONFIG,
+ &test_logic);
+ if (status)
+ return 0xffffffff;
+
+ /* First, establish the function number of the other PCI function */
+ if (test_logic & FC1_FUNCTION_ENABLE)
+ fc1_function_num = (test_logic & FC1_FUNCTION_MASK) >>
+ FC1_FUNCTION_SHIFT;
+ if (test_logic & FC2_FUNCTION_ENABLE)
+ fc2_function_num = (test_logic & FC2_FUNCTION_MASK) >>
+ FC2_FUNCTION_SHIFT;
+ if (test_logic & NIC1_FUNCTION_ENABLE)
+ nic1_function_num = (test_logic & NIC1_FUNCTION_MASK) >>
+ NIC1_FUNCTION_SHIFT;
+ if (test_logic & NIC2_FUNCTION_ENABLE)
+ nic2_function_num = (test_logic & NIC2_FUNCTION_MASK) >>
+ NIC2_FUNCTION_SHIFT;
+ if (qdev->func == nic1_function_num)
+ other_function = nic2_function_num;
+ else
+ other_function = nic1_function_num;
+
+ return other_function;
+}
+
+static u32 ql_read_other_func_reg(struct ql_adapter *qdev,
+ u32 reg)
+{
+ u32 other_function;
+ u32 register_to_read;
+ u32 reg_val;
+ unsigned int status = 0;
+
+ other_function = ql_get_other_func_num(qdev);
+
+ /* The other function is not enabled so we don't need
+ * to read anything out of it.
+ */
+ if (other_function == 0xffffffff)
+ return other_function;
+
+ /* The other function is there so now we need to
+ * read the requested register.
+ */
+ register_to_read = REG_BLOCK | MPI_READ |
+ (other_function << FUNCTION_SHIFT) | reg;
+ status = ql_read_mpi_reg(qdev, register_to_read, ®_val);
+ if (status != 0)
+ return 0xffffffff;
+
+ return reg_val;
+}
+
/* Read out the SERDES registers */
int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
{
@@ -521,16 +585,31 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
sizeof(struct mpi_coredump_segment_header) +
sizeof(mpi_coredump->nic_regs), "NIC1 Registers");
+ ql_build_coredump_seg_header(&mpi_coredump->nic2_regs_seg_hdr,
+ NIC2_CONTROL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->nic2_regs), "NIC2 Registers");
+
if (qdev->func & 1) {
/* Odd means our function is NIC 2 */
for (i = 0; i < 64; i++)
mpi_coredump->nic2_regs[i] =
ql_read32(qdev, i * sizeof(u32));
+
+ for (i = 0; i < 64; i++)
+ mpi_coredump->nic_regs[i] =
+ ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+
} else {
/* Even means our function is NIC 1 */
for (i = 0; i < 64; i++)
mpi_coredump->nic_regs[i] =
ql_read32(qdev, i * sizeof(u32));
+
+ for (i = 0; i < 64; i++)
+ mpi_coredump->nic2_regs[i] =
+ ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+
}
ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 6/8] qlge: Add serdes reg dump to firmware dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
` (4 preceding siblings ...)
2010-01-12 1:13 ` [net-next PATCH 5/8] qlge: Add alternate function's reg dump to fw dump Ron Mercer
@ 2010-01-12 1:13 ` Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 7/8] qlge: Add xgmac regs to firwmare dump Ron Mercer
` (2 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:13 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_dbg.c | 382 ++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 381 insertions(+), 1 deletions(-)
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 63822f7..6416fc3 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -64,8 +64,81 @@ static u32 ql_read_other_func_reg(struct ql_adapter *qdev,
return reg_val;
}
+static int ql_write_other_func_reg(struct ql_adapter *qdev,
+ u32 reg, u32 reg_val)
+{
+ u32 other_function;
+ u32 register_to_read;
+ int status = 0;
+
+ other_function = ql_get_other_func_num(qdev);
+
+ /*
+ * The other function is not enabled so we don't
+ * need to read anything out of it.
+ */
+ if (other_function == 0xffffffff)
+ return -1;
+
+ /*
+ * The other function is there so now we need
+ * to read the requested register.
+ */
+ register_to_read = REG_BLOCK | MPI_READ |
+ (other_function << FUNCTION_SHIFT) | reg;
+ status = ql_write_mpi_reg(qdev, register_to_read, reg_val);
+
+ return status;
+}
+
+static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg,
+ u32 bit, u32 err_bit)
+{
+ u32 temp;
+ int count = 10;
+
+ while (count) {
+ temp = ql_read_other_func_reg(qdev, reg);
+
+ /* check for errors */
+ if (temp & err_bit)
+ return -1;
+ else if (temp & bit)
+ return 0;
+ mdelay(10);
+ count--;
+ }
+ return -1;
+}
+
+static int ql_read_other_func_serdes_reg(struct ql_adapter *qdev, u32 reg,
+ u32 *data)
+{
+ int status;
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+ XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* set up for reg read */
+ ql_write_other_func_reg(qdev, XG_SERDES_ADDR/4, reg | PROC_ADDR_R);
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4,
+ XG_SERDES_ADDR_RDY, 0);
+ if (status)
+ goto exit;
+
+ /* get the data */
+ *data = ql_read_other_func_reg(qdev, (XG_SERDES_DATA / 4));
+exit:
+ return status;
+}
+
/* Read out the SERDES registers */
-int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
+static int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
{
int status;
@@ -88,6 +161,208 @@ exit:
return status;
}
+static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr,
+ u32 *direct_ptr, u32 *indirect_ptr,
+ unsigned int direct_valid, unsigned int indirect_valid)
+{
+ unsigned int status;
+
+ status = 0xffffffff;
+ if (direct_valid)
+ status = ql_read_serdes_reg(qdev, addr, direct_ptr);
+
+ if (status)
+ *direct_ptr = 0xDEADBEEF;
+
+ status = 0xffffffff;
+ if (indirect_valid)
+ status = ql_read_other_func_serdes_reg(
+ qdev, addr, indirect_ptr);
+
+ if (status)
+ *indirect_ptr = 0xDEADBEEF;
+}
+
+static int ql_get_serdes_regs(struct ql_adapter *qdev,
+ struct ql_mpi_coredump *mpi_coredump)
+{
+ int status;
+ unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid;
+ unsigned int xaui_indirect_valid, xaui_reg, i;
+ u32 *direct_ptr, temp;
+ u32 *indirect_ptr;
+
+ xfi_direct_valid = xfi_indirect_valid = 0;
+ xaui_direct_valid = xaui_indirect_valid = 1;
+
+ /* The XAUI needs to be read out per port */
+ xaui_reg = 0x800;
+ if (qdev->func & 1) {
+ /* We are NIC 2 */
+ status = ql_read_other_func_serdes_reg(qdev, xaui_reg, &temp);
+ if (status)
+ temp = XAUI_POWERED_DOWN;
+ if ((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+ xaui_indirect_valid = 0;
+
+ status = ql_read_serdes_reg(qdev, xaui_reg, &temp);
+ if (status)
+ temp = XAUI_POWERED_DOWN;
+
+ if ((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+ xaui_direct_valid = 0;
+ } else {
+ /* We are NIC 1 */
+ status = ql_read_other_func_serdes_reg(qdev, xaui_reg, &temp);
+ if (status)
+ temp = XAUI_POWERED_DOWN;
+ if ((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+ xaui_indirect_valid = 0;
+
+ status = ql_read_serdes_reg(qdev, xaui_reg, &temp);
+ if (status)
+ temp = XAUI_POWERED_DOWN;
+ if ((temp & XAUI_POWERED_DOWN) == XAUI_POWERED_DOWN)
+ xaui_direct_valid = 0;
+ }
+
+ /*
+ * XFI register is shared so only need to read one
+ * functions and then check the bits.
+ */
+ status = ql_read_serdes_reg(qdev, 0x1E06, &temp);
+ if (status)
+ temp = 0;
+
+ if ((temp & XFI1_POWERED_UP) == XFI1_POWERED_UP) {
+ /* now see if i'm NIC 1 or NIC 2 */
+ if (qdev->func & 1)
+ /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+ xfi_indirect_valid = 1;
+ else
+ xfi_direct_valid = 1;
+ }
+ if ((temp & XFI2_POWERED_UP) == XFI2_POWERED_UP) {
+ /* now see if i'm NIC 1 or NIC 2 */
+ if (qdev->func & 1)
+ /* I'm NIC 2, so the indirect (NIC1) xfi is up. */
+ xfi_direct_valid = 1;
+ else
+ xfi_indirect_valid = 1;
+ }
+
+ if (qdev->func & 1) {
+ /* Function 2 is direct */
+ direct_ptr = mpi_coredump->serdes2_xaui_an;
+ indirect_ptr = mpi_coredump->serdes_xaui_an;
+ } else {
+ /* Function 1 is direct */
+ direct_ptr = mpi_coredump->serdes_xaui_an;
+ indirect_ptr = mpi_coredump->serdes2_xaui_an;
+ }
+
+ for (i = 0; i <= 0x000000034; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xaui_direct_valid, xaui_indirect_valid);
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xaui_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes_xaui_hss_pcs;
+ } else {
+ direct_ptr =
+ mpi_coredump->serdes_xaui_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes2_xaui_hss_pcs;
+ }
+
+ for (i = 0x800; i <= 0x880; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xaui_direct_valid, xaui_indirect_valid);
+ if (qdev->func & 1) {
+ direct_ptr = mpi_coredump->serdes2_xfi_an;
+ indirect_ptr = mpi_coredump->serdes_xfi_an;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_an;
+ indirect_ptr = mpi_coredump->serdes2_xfi_an;
+ }
+
+ for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+ if (qdev->func & 1) {
+ direct_ptr = mpi_coredump->serdes2_xfi_train;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_train;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_train;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_train;
+ }
+
+ for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_pcs;
+ } else {
+ direct_ptr =
+ mpi_coredump->serdes_xfi_hss_pcs;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_pcs;
+ }
+
+ for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_tx;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_tx;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_hss_tx;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_tx;
+ }
+ for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_rx;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_rx;
+ } else {
+ direct_ptr = mpi_coredump->serdes_xfi_hss_rx;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_rx;
+ }
+
+ for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+
+ if (qdev->func & 1) {
+ direct_ptr =
+ mpi_coredump->serdes2_xfi_hss_pll;
+ indirect_ptr =
+ mpi_coredump->serdes_xfi_hss_pll;
+ } else {
+ direct_ptr =
+ mpi_coredump->serdes_xfi_hss_pll;
+ indirect_ptr =
+ mpi_coredump->serdes2_xfi_hss_pll;
+ }
+ for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr++, indirect_ptr++)
+ ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr,
+ xfi_direct_valid, xfi_indirect_valid);
+ return 0;
+}
+
/* Read out the ETS registers */
static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
{
@@ -612,6 +887,111 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
}
+ /* Rev C. Step 20a */
+ ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr,
+ XAUI_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xaui_an),
+ "XAUI AN Registers");
+
+ /* Rev C. Step 20b */
+ ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr,
+ XAUI_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xaui_hss_pcs),
+ "XAUI HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_an),
+ "XFI AN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr,
+ XFI_TRAIN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_train),
+ "XFI TRAIN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr,
+ XFI_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_pcs),
+ "XFI HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr,
+ XFI_HSS_TX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_tx),
+ "XFI HSS TX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr,
+ XFI_HSS_RX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_rx),
+ "XFI HSS RX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr,
+ XFI_HSS_PLL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes_xfi_hss_pll),
+ "XFI HSS PLL Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xaui2_an_hdr,
+ XAUI2_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xaui_an),
+ "XAUI2 AN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xaui2_hss_pcs_hdr,
+ XAUI2_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xaui_hss_pcs),
+ "XAUI2 HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_an_hdr,
+ XFI2_AN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_an),
+ "XFI2 AN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_train_hdr,
+ XFI2_TRAIN_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_train),
+ "XFI2 TRAIN Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pcs_hdr,
+ XFI2_HSS_PCS_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_pcs),
+ "XFI2 HSS PCS Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_tx_hdr,
+ XFI2_HSS_TX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_tx),
+ "XFI2 HSS TX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_rx_hdr,
+ XFI2_HSS_RX_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_rx),
+ "XFI2 HSS RX Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pll_hdr,
+ XFI2_HSS_PLL_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->serdes2_xfi_hss_pll),
+ "XFI2 HSS PLL Registers");
+
+ status = ql_get_serdes_regs(qdev, mpi_coredump);
+ if (status) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed Dump of Serdes Registers. Status = 0x%.08x\n",
+ status);
+ goto err;
+ }
+
ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr,
CORE_SEG_NUM,
sizeof(mpi_coredump->core_regs_seg_hdr) +
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 7/8] qlge: Add xgmac regs to firwmare dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
` (5 preceding siblings ...)
2010-01-12 1:13 ` [net-next PATCH 6/8] qlge: Add serdes reg dump to firmware dump Ron Mercer
@ 2010-01-12 1:13 ` Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 8/8] qlge: Add option to force firmware core dump Ron Mercer
2010-01-12 6:22 ` [net-next PATCH 0/8] qlge: Add firmware coredump functionality David Miller
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:13 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_dbg.c | 85 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 85 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 6416fc3..f087038 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -137,6 +137,32 @@ exit:
return status;
}
+static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg,
+ u32 *data)
+{
+ int status = 0;
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+ XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+ if (status)
+ goto exit;
+
+ /* set up for reg read */
+ ql_write_other_func_reg(qdev, XGMAC_ADDR / 4, reg | XGMAC_ADDR_R);
+
+ /* wait for reg to come ready */
+ status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4,
+ XGMAC_ADDR_RDY, XGMAC_ADDR_XME);
+ if (status)
+ goto exit;
+
+ /* get the data */
+ *data = ql_read_other_func_reg(qdev, XGMAC_DATA / 4);
+exit:
+ return status;
+}
+
/* Read out the SERDES registers */
static int ql_read_serdes_reg(struct ql_adapter *qdev, u32 reg, u32 * data)
{
@@ -363,6 +389,50 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev,
return 0;
}
+/* Read the 400 xgmac control/statistics registers
+ * skipping unused locations.
+ */
+static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 * buf,
+ unsigned int other_function)
+{
+ int status = 0;
+ int i;
+
+ for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) {
+ /* We're reading 400 xgmac registers, but we filter out
+ * serveral locations that are non-responsive to reads.
+ */
+ if ((i == 0x00000114) ||
+ (i == 0x00000118) ||
+ (i == 0x0000013c) ||
+ (i == 0x00000140) ||
+ (i > 0x00000150 && i < 0x000001fc) ||
+ (i > 0x00000278 && i < 0x000002a0) ||
+ (i > 0x000002c0 && i < 0x000002cf) ||
+ (i > 0x000002dc && i < 0x000002f0) ||
+ (i > 0x000003c8 && i < 0x00000400) ||
+ (i > 0x00000400 && i < 0x00000410) ||
+ (i > 0x00000410 && i < 0x00000420) ||
+ (i > 0x00000420 && i < 0x00000430) ||
+ (i > 0x00000430 && i < 0x00000440) ||
+ (i > 0x00000440 && i < 0x00000450) ||
+ (i > 0x00000450 && i < 0x00000500) ||
+ (i > 0x0000054c && i < 0x00000568) ||
+ (i > 0x000005c8 && i < 0x00000600)) {
+ if (other_function)
+ status =
+ ql_read_other_func_xgmac_reg(qdev, i, buf);
+ else
+ status = ql_read_xgmac_reg(qdev, i, buf);
+
+ if (status)
+ *buf = 0xdeadbeef;
+ break;
+ }
+ }
+ return status;
+}
+
/* Read out the ETS registers */
static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
{
@@ -865,6 +935,17 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
sizeof(struct mpi_coredump_segment_header) +
sizeof(mpi_coredump->nic2_regs), "NIC2 Registers");
+ /* Get XGMac registers. (Segment 18, Rev C. step 21) */
+ ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr,
+ NIC1_XGMAC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->xgmac1), "NIC1 XGMac Registers");
+
+ ql_build_coredump_seg_header(&mpi_coredump->xgmac2_seg_hdr,
+ NIC2_XGMAC_SEG_NUM,
+ sizeof(struct mpi_coredump_segment_header) +
+ sizeof(mpi_coredump->xgmac2), "NIC2 XGMac Registers");
+
if (qdev->func & 1) {
/* Odd means our function is NIC 2 */
for (i = 0; i < 64; i++)
@@ -875,6 +956,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
mpi_coredump->nic_regs[i] =
ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 0);
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 1);
} else {
/* Even means our function is NIC 1 */
for (i = 0; i < 64; i++)
@@ -885,6 +968,8 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
mpi_coredump->nic2_regs[i] =
ql_read_other_func_reg(qdev, (i * sizeof(u32)) / 4);
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac1[0], 0);
+ ql_get_xgmac_regs(qdev, &mpi_coredump->xgmac2[0], 1);
}
/* Rev C. Step 20a */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [net-next PATCH 8/8] qlge: Add option to force firmware core dump.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
` (6 preceding siblings ...)
2010-01-12 1:13 ` [net-next PATCH 7/8] qlge: Add xgmac regs to firwmare dump Ron Mercer
@ 2010-01-12 1:13 ` Ron Mercer
2010-01-12 6:22 ` [net-next PATCH 0/8] qlge: Add firmware coredump functionality David Miller
8 siblings, 0 replies; 13+ messages in thread
From: Ron Mercer @ 2010-01-12 1:13 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Default setting is 'off', don't allow force firmware dump.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 3 +++
drivers/net/qlge/qlge_dbg.c | 25 +++++++++++++++++++++++++
drivers/net/qlge/qlge_main.c | 8 ++++++++
drivers/net/qlge/qlge_mpi.c | 16 ++++++++++++++++
4 files changed, 52 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 3f3ec57..5a80ac9 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1894,6 +1894,7 @@ enum {
QL_CAM_RT_SET = 8,
QL_SELFTEST = 9,
QL_LB_LINK_UP = 10,
+ QL_FRC_COREDUMP = 11,
};
/* link_status bit definitions */
@@ -2120,6 +2121,7 @@ int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf,
u32 ram_addr, int word_count);
int ql_core_dump(struct ql_adapter *qdev,
struct ql_mpi_coredump *mpi_coredump);
+int ql_mb_sys_err(struct ql_adapter *qdev);
int ql_mb_about_fw(struct ql_adapter *qdev);
int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
@@ -2136,6 +2138,7 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
struct ql_reg_dump *mpi_coredump);
netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev);
void ql_check_lb_frame(struct ql_adapter *, struct sk_buff *);
+int ql_own_firmware(struct ql_adapter *qdev);
int ql_clean_lb_rx_ring(struct rx_ring *rx_ring, int budget);
#if 1
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index f087038..f218721 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -1390,6 +1390,28 @@ err:
}
+static void ql_get_core_dump(struct ql_adapter *qdev)
+{
+ if (!ql_own_firmware(qdev)) {
+ QPRINTK(qdev, DRV, ERR, "%s: Don't own firmware!\n",
+ qdev->ndev->name);
+ return;
+ }
+
+ if (!netif_running(qdev->ndev)) {
+ QPRINTK(qdev, IFUP, ERR,
+ "Force Coredump can only be done from interface "
+ "that is up.\n");
+ return;
+ }
+
+ if (ql_mb_sys_err(qdev)) {
+ QPRINTK(qdev, IFUP, ERR,
+ "Fail force coredump with ql_mb_sys_err().\n");
+ return;
+ }
+}
+
void ql_gen_reg_dump(struct ql_adapter *qdev,
struct ql_reg_dump *mpi_coredump)
{
@@ -1465,6 +1487,9 @@ void ql_gen_reg_dump(struct ql_adapter *qdev,
status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]);
if (status)
return;
+
+ if (test_bit(QL_FRC_COREDUMP, &qdev->flags))
+ ql_get_core_dump(qdev);
}
/* Coredump to messages log file using separate worker thread */
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 9106c08..2350d96 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -79,6 +79,12 @@ MODULE_PARM_DESC(qlge_mpi_coredump,
"Option to enable allocation of memory for an MPI "
"firmware dump. Default is 1 - allocate memory.");
+static int qlge_force_coredump;
+module_param(qlge_force_coredump, int, 0);
+MODULE_PARM_DESC(qlge_force_coredump,
+ "Option to allow force of firmware core dump. "
+ "Default is 0 - Do not allow.");
+
static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
@@ -4495,6 +4501,8 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
err = -ENOMEM;
goto err_out;
}
+ if (qlge_force_coredump)
+ set_bit(QL_FRC_COREDUMP, &qdev->flags);
}
/* make sure the EEPROM is good */
err = qdev->nic_ops->get_flash(qdev);
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 0ba6b90..ffc83e1 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -607,6 +607,22 @@ end:
return status;
}
+int ql_mb_sys_err(struct ql_adapter *qdev)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+
+ mbcp->in_count = 1;
+ mbcp->out_count = 0;
+
+ mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR;
+
+ status = ql_mailbox_command(qdev, mbcp);
+ return status;
+}
/* Get MPI firmware version. This will be used for
* driver banner and for ethtool info.
--
1.6.0.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [net-next PATCH 1/8] qlge: Add data for firmware dump.
2010-01-12 1:12 ` [net-next PATCH 1/8] qlge: Add data for firmware dump Ron Mercer
@ 2010-01-12 6:20 ` David Miller
0 siblings, 0 replies; 13+ messages in thread
From: David Miller @ 2010-01-12 6:20 UTC (permalink / raw)
To: ron.mercer; +Cc: netdev
From: Ron Mercer <ron.mercer@qlogic.com>
Date: Mon, 11 Jan 2010 17:12:58 -0800
> Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
> ---
> drivers/net/qlge/qlge.h | 285 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 284 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
> index ee0e2bd..0094263 100644
> --- a/drivers/net/qlge/qlge.h
> +++ b/drivers/net/qlge/qlge.h
> @@ -75,6 +75,16 @@
> #define TX_DESC_PER_OAL 0
> #endif
>
> +/* Word shifting for converting 64-bit
> + * address to a series of 16-bit words.
> + * This is used for some MPI firmware
> + * mailbox commands.
> + */
> +#define LSW(x) ((u16)(x))
> +#define MSW(x) ((u16)((u32)(x) >> 16))
> +#define LSD(x) ((u32)((u64)(x)))
> +#define MSD(x) ((u32)((((u64)(x)) >> 16) >> 16))
And using plain:
((u32)(((u64)x) >> 32))
doesn't work for MSD() because? Shifting right by 16 bits
twice is pointless, and even more importantly confusing.
> +#define MAC_PROTOCOL_REGISTER_WORDS ((512 * 3) + (32 * 2) + (4096 * 1) + \
> +(4096 * 1) + (4 * 2) + (8 * 2) + (16 * 1) + (4 * 1) + (4 * 4) + (4 * 1))
This is poorly formatted and full of magic constants with absolutely
no explanation.
> +/* Save both the address and data register */
> +#define WORDS_PER_MAC_PROT_ENTRY 2
> +#define MAX_SEMAPHORE_FUNCTIONS 5
> +#define WQC_WORD_SIZE 6
> +#define NUMBER_OF_WQCS 128
> +#define CQC_WORD_SIZE 13
> +#define NUMBER_OF_CQCS 128
Poor formatting.
> +#define MPI_READ 0x00000000
> +#define REG_BLOCK 0x00020000
> +#define TEST_LOGIC_FUNC_PORT_CONFIG 0x1002
> +#define NIC1_FUNCTION_ENABLE 0x00000001
> +#define NIC1_FUNCTION_MASK 0x0000000e
> +#define NIC1_FUNCTION_SHIFT 1
> +#define NIC2_FUNCTION_ENABLE 0x00000010
> +#define NIC2_FUNCTION_MASK 0x000000e0
> +#define NIC2_FUNCTION_SHIFT 5
> +#define FC1_FUNCTION_ENABLE 0x00000100
> +#define FC1_FUNCTION_MASK 0x00000e00
> +#define FC1_FUNCTION_SHIFT 9
> +#define FC2_FUNCTION_ENABLE 0x00001000
> +#define FC2_FUNCTION_MASK 0x0000e000
> +#define FC2_FUNCTION_SHIFT 13
> +#define FUNCTION_SHIFT 6
More poor formatting, use tabs to line up the define values
so that it's easier to read by humans (and therefore easier
to spot bugs).
Same goes for the rest of the defines added by this patch.
I'm not even going to look at the rest of this patch series,
please fix up these fundamental code formatting issues,
check for them in the rest of your changes, and resubmit
the whole series.
Thanks.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [net-next PATCH 0/8] qlge: Add firmware coredump functionality.
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
` (7 preceding siblings ...)
2010-01-12 1:13 ` [net-next PATCH 8/8] qlge: Add option to force firmware core dump Ron Mercer
@ 2010-01-12 6:22 ` David Miller
8 siblings, 0 replies; 13+ messages in thread
From: David Miller @ 2010-01-12 6:22 UTC (permalink / raw)
To: ron.mercer; +Cc: netdev
From: Ron Mercer <ron.mercer@qlogic.com>
Date: Mon, 11 Jan 2010 17:12:57 -0800
> Dump all regsiters and on chip RAM when a fatal firmware error is
> encountered. This features is turn on by default but can be
> turned off with a module parameter.
There is no way you should crap into someone's kernel log
with a large amount of information by default.
Yes, this is true even on fatal errors.
If you can't dump the information in say a dozen lines, it
is more trouble than it's worth as a default.
Make the default to off. Users can be asked to turn it on
if you need to capture more information for diagnostics,
and you personally can turn it on by default when doing
development.
Thanks.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [net-next PATCH 0/8] qlge: Add firmware coredump functionality.
@ 2010-01-15 23:31 Ron Mercer
2010-01-16 9:02 ` David Miller
0 siblings, 1 reply; 13+ messages in thread
From: Ron Mercer @ 2010-01-15 23:31 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Dump all regsiters and on-chip RAM when a fatal firmware error is
encountered. This feature is turn OFF by default but can be turned on
with a module parameter.
Dave,
The constant definitions have been cleaned up with aligned tabs per your
request. The dump function and it's memory allocation are now turned
OFF by default.
I've added/expanded register definitions to aid in dump process which
gets rid of the literal numeric constants.
Thanks, Ron
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [net-next PATCH 0/8] qlge: Add firmware coredump functionality.
2010-01-15 23:31 Ron Mercer
@ 2010-01-16 9:02 ` David Miller
0 siblings, 0 replies; 13+ messages in thread
From: David Miller @ 2010-01-16 9:02 UTC (permalink / raw)
To: ron.mercer; +Cc: netdev
From: Ron Mercer <ron.mercer@qlogic.com>
Date: Fri, 15 Jan 2010 15:31:26 -0800
>
> Dump all regsiters and on-chip RAM when a fatal firmware error is
> encountered. This feature is turn OFF by default but can be turned on
> with a module parameter.
>
> Dave,
>
> The constant definitions have been cleaned up with aligned tabs per your
> request. The dump function and it's memory allocation are now turned
> OFF by default.
> I've added/expanded register definitions to aid in dump process which
> gets rid of the literal numeric constants.
Looks good, all applied to net-next-2.6, thanks!
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2010-01-16 9:02 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-01-12 1:12 [net-next PATCH 0/8] qlge: Add firmware coredump functionality Ron Mercer
2010-01-12 1:12 ` [net-next PATCH 1/8] qlge: Add data for firmware dump Ron Mercer
2010-01-12 6:20 ` David Miller
2010-01-12 1:12 ` [net-next PATCH 2/8] qlge: Add basic " Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 3/8] qlge: Add probe regs to " Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 4/8] qlge: Add RAM dump " Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 5/8] qlge: Add alternate function's reg dump to fw dump Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 6/8] qlge: Add serdes reg dump to firmware dump Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 7/8] qlge: Add xgmac regs to firwmare dump Ron Mercer
2010-01-12 1:13 ` [net-next PATCH 8/8] qlge: Add option to force firmware core dump Ron Mercer
2010-01-12 6:22 ` [net-next PATCH 0/8] qlge: Add firmware coredump functionality David Miller
-- strict thread matches above, loose matches on Subject: below --
2010-01-15 23:31 Ron Mercer
2010-01-16 9:02 ` David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).