mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	qlge: Add ethtool register dump function.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									bc083ce98e
								
							
						
					
					
						commit
						a61f802613
					
				
					 3 changed files with 345 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -1400,6 +1400,153 @@ struct nic_stats {
 | 
			
		|||
	u64 rx_nic_fifo_drop;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Address/Length pairs for the coredump. */
 | 
			
		||||
enum {
 | 
			
		||||
	MPI_CORE_REGS_ADDR = 0x00030000,
 | 
			
		||||
	MPI_CORE_REGS_CNT = 127,
 | 
			
		||||
	MPI_CORE_SH_REGS_CNT = 16,
 | 
			
		||||
	TEST_REGS_ADDR = 0x00001000,
 | 
			
		||||
	TEST_REGS_CNT = 23,
 | 
			
		||||
	RMII_REGS_ADDR = 0x00001040,
 | 
			
		||||
	RMII_REGS_CNT = 64,
 | 
			
		||||
	FCMAC1_REGS_ADDR = 0x00001080,
 | 
			
		||||
	FCMAC2_REGS_ADDR = 0x000010c0,
 | 
			
		||||
	FCMAC_REGS_CNT = 64,
 | 
			
		||||
	FC1_MBX_REGS_ADDR = 0x00001100,
 | 
			
		||||
	FC2_MBX_REGS_ADDR = 0x00001240,
 | 
			
		||||
	FC_MBX_REGS_CNT = 64,
 | 
			
		||||
	IDE_REGS_ADDR = 0x00001140,
 | 
			
		||||
	IDE_REGS_CNT = 64,
 | 
			
		||||
	NIC1_MBX_REGS_ADDR = 0x00001180,
 | 
			
		||||
	NIC2_MBX_REGS_ADDR = 0x00001280,
 | 
			
		||||
	NIC_MBX_REGS_CNT = 64,
 | 
			
		||||
	SMBUS_REGS_ADDR = 0x00001200,
 | 
			
		||||
	SMBUS_REGS_CNT = 64,
 | 
			
		||||
	I2C_REGS_ADDR = 0x00001fc0,
 | 
			
		||||
	I2C_REGS_CNT = 64,
 | 
			
		||||
	MEMC_REGS_ADDR = 0x00003000,
 | 
			
		||||
	MEMC_REGS_CNT = 256,
 | 
			
		||||
	PBUS_REGS_ADDR = 0x00007c00,
 | 
			
		||||
	PBUS_REGS_CNT = 256,
 | 
			
		||||
	MDE_REGS_ADDR = 0x00010000,
 | 
			
		||||
	MDE_REGS_CNT = 6,
 | 
			
		||||
	CODE_RAM_ADDR = 0x00020000,
 | 
			
		||||
	CODE_RAM_CNT = 0x2000,
 | 
			
		||||
	MEMC_RAM_ADDR = 0x00100000,
 | 
			
		||||
	MEMC_RAM_CNT = 0x2000,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MPI_COREDUMP_COOKIE 0x5555aaaa
 | 
			
		||||
struct mpi_coredump_global_header {
 | 
			
		||||
	u32	cookie;
 | 
			
		||||
	u8	idString[16];
 | 
			
		||||
	u32	timeLo;
 | 
			
		||||
	u32	timeHi;
 | 
			
		||||
	u32	imageSize;
 | 
			
		||||
	u32	headerSize;
 | 
			
		||||
	u8	info[220];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mpi_coredump_segment_header {
 | 
			
		||||
	u32	cookie;
 | 
			
		||||
	u32	segNum;
 | 
			
		||||
	u32	segSize;
 | 
			
		||||
	u32	extra;
 | 
			
		||||
	u8	description[16];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Reg dump segment numbers. */
 | 
			
		||||
enum {
 | 
			
		||||
	CORE_SEG_NUM = 1,
 | 
			
		||||
	TEST_LOGIC_SEG_NUM = 2,
 | 
			
		||||
	RMII_SEG_NUM = 3,
 | 
			
		||||
	FCMAC1_SEG_NUM = 4,
 | 
			
		||||
	FCMAC2_SEG_NUM = 5,
 | 
			
		||||
	FC1_MBOX_SEG_NUM = 6,
 | 
			
		||||
	IDE_SEG_NUM = 7,
 | 
			
		||||
	NIC1_MBOX_SEG_NUM = 8,
 | 
			
		||||
	SMBUS_SEG_NUM = 9,
 | 
			
		||||
	FC2_MBOX_SEG_NUM = 10,
 | 
			
		||||
	NIC2_MBOX_SEG_NUM = 11,
 | 
			
		||||
	I2C_SEG_NUM = 12,
 | 
			
		||||
	MEMC_SEG_NUM = 13,
 | 
			
		||||
	PBUS_SEG_NUM = 14,
 | 
			
		||||
	MDE_SEG_NUM = 15,
 | 
			
		||||
	NIC1_CONTROL_SEG_NUM = 16,
 | 
			
		||||
	NIC2_CONTROL_SEG_NUM = 17,
 | 
			
		||||
	NIC1_XGMAC_SEG_NUM = 18,
 | 
			
		||||
	NIC2_XGMAC_SEG_NUM = 19,
 | 
			
		||||
	WCS_RAM_SEG_NUM = 20,
 | 
			
		||||
	MEMC_RAM_SEG_NUM = 21,
 | 
			
		||||
	XAUI_AN_SEG_NUM = 22,
 | 
			
		||||
	XAUI_HSS_PCS_SEG_NUM = 23,
 | 
			
		||||
	XFI_AN_SEG_NUM = 24,
 | 
			
		||||
	XFI_TRAIN_SEG_NUM = 25,
 | 
			
		||||
	XFI_HSS_PCS_SEG_NUM = 26,
 | 
			
		||||
	XFI_HSS_TX_SEG_NUM = 27,
 | 
			
		||||
	XFI_HSS_RX_SEG_NUM = 28,
 | 
			
		||||
	XFI_HSS_PLL_SEG_NUM = 29,
 | 
			
		||||
	MISC_NIC_INFO_SEG_NUM = 30,
 | 
			
		||||
	INTR_STATES_SEG_NUM = 31,
 | 
			
		||||
	CAM_ENTRIES_SEG_NUM = 32,
 | 
			
		||||
	ROUTING_WORDS_SEG_NUM = 33,
 | 
			
		||||
	ETS_SEG_NUM = 34,
 | 
			
		||||
	PROBE_DUMP_SEG_NUM = 35,
 | 
			
		||||
	ROUTING_INDEX_SEG_NUM = 36,
 | 
			
		||||
	MAC_PROTOCOL_SEG_NUM = 37,
 | 
			
		||||
	XAUI2_AN_SEG_NUM = 38,
 | 
			
		||||
	XAUI2_HSS_PCS_SEG_NUM = 39,
 | 
			
		||||
	XFI2_AN_SEG_NUM = 40,
 | 
			
		||||
	XFI2_TRAIN_SEG_NUM = 41,
 | 
			
		||||
	XFI2_HSS_PCS_SEG_NUM = 42,
 | 
			
		||||
	XFI2_HSS_TX_SEG_NUM = 43,
 | 
			
		||||
	XFI2_HSS_RX_SEG_NUM = 44,
 | 
			
		||||
	XFI2_HSS_PLL_SEG_NUM = 45,
 | 
			
		||||
	SEM_REGS_SEG_NUM = 50
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ql_nic_misc {
 | 
			
		||||
	u32 rx_ring_count;
 | 
			
		||||
	u32 tx_ring_count;
 | 
			
		||||
	u32 intr_count;
 | 
			
		||||
	u32 function;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ql_reg_dump {
 | 
			
		||||
 | 
			
		||||
	/* segment 0 */
 | 
			
		||||
	struct mpi_coredump_global_header mpi_global_header;
 | 
			
		||||
 | 
			
		||||
	/* segment 16 */
 | 
			
		||||
	struct mpi_coredump_segment_header nic_regs_seg_hdr;
 | 
			
		||||
	u32 nic_regs[64];
 | 
			
		||||
 | 
			
		||||
	/* 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_CPUS];
 | 
			
		||||
 | 
			
		||||
	/* 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];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * intr_context structure is used during initialization
 | 
			
		||||
 * to hook the interrupts.  It is also used in a single
 | 
			
		||||
| 
						 | 
				
			
			@ -1658,6 +1805,8 @@ int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control);
 | 
			
		|||
int ql_mb_get_port_cfg(struct ql_adapter *qdev);
 | 
			
		||||
int ql_mb_set_port_cfg(struct ql_adapter *qdev);
 | 
			
		||||
int ql_wait_fifo_empty(struct ql_adapter *qdev);
 | 
			
		||||
void ql_gen_reg_dump(struct ql_adapter *qdev,
 | 
			
		||||
			struct ql_reg_dump *mpi_coredump);
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
#define QL_ALL_DUMP
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,185 @@
 | 
			
		|||
#include "qlge.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int ql_get_ets_regs(struct ql_adapter *qdev, u32 * buf)
 | 
			
		||||
{
 | 
			
		||||
	int status = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 8; i++, buf++) {
 | 
			
		||||
		ql_write32(qdev, NIC_ETS, i << 29 | 0x08000000);
 | 
			
		||||
		*buf = ql_read32(qdev, NIC_ETS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 2; i++, buf++) {
 | 
			
		||||
		ql_write32(qdev, CNA_ETS, i << 29 | 0x08000000);
 | 
			
		||||
		*buf = ql_read32(qdev, CNA_ETS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ql_get_intr_states(struct ql_adapter *qdev, u32 * buf)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < qdev->rx_ring_count; i++, buf++) {
 | 
			
		||||
		ql_write32(qdev, INTR_EN,
 | 
			
		||||
				qdev->intr_context[i].intr_read_mask);
 | 
			
		||||
		*buf = ql_read32(qdev, INTR_EN);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ql_get_cam_entries(struct ql_adapter *qdev, u32 * buf)
 | 
			
		||||
{
 | 
			
		||||
	int i, status;
 | 
			
		||||
	u32 value[3];
 | 
			
		||||
 | 
			
		||||
	status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
 | 
			
		||||
	if (status)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 16; i++) {
 | 
			
		||||
		status = ql_get_mac_addr_reg(qdev,
 | 
			
		||||
					MAC_ADDR_TYPE_CAM_MAC, i, value);
 | 
			
		||||
		if (status) {
 | 
			
		||||
			QPRINTK(qdev, DRV, ERR,
 | 
			
		||||
				"Failed read of mac index register.\n");
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
		*buf++ = value[0];	/* lower MAC address */
 | 
			
		||||
		*buf++ = value[1];	/* upper MAC address */
 | 
			
		||||
		*buf++ = value[2];	/* output */
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < 32; i++) {
 | 
			
		||||
		status = ql_get_mac_addr_reg(qdev,
 | 
			
		||||
					MAC_ADDR_TYPE_MULTI_MAC, i, value);
 | 
			
		||||
		if (status) {
 | 
			
		||||
			QPRINTK(qdev, DRV, ERR,
 | 
			
		||||
				"Failed read of mac index register.\n");
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
		*buf++ = value[0];	/* lower Mcast address */
 | 
			
		||||
		*buf++ = value[1];	/* upper Mcast address */
 | 
			
		||||
	}
 | 
			
		||||
err:
 | 
			
		||||
	ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ql_get_routing_entries(struct ql_adapter *qdev, u32 * buf)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	u32 value, i;
 | 
			
		||||
 | 
			
		||||
	status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
 | 
			
		||||
	if (status)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 16; i++) {
 | 
			
		||||
		status = ql_get_routing_reg(qdev, i, &value);
 | 
			
		||||
		if (status) {
 | 
			
		||||
			QPRINTK(qdev, DRV, ERR,
 | 
			
		||||
				"Failed read of routing index register.\n");
 | 
			
		||||
			goto err;
 | 
			
		||||
		} else {
 | 
			
		||||
			*buf++ = value;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
err:
 | 
			
		||||
	ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Create a coredump segment header */
 | 
			
		||||
static void ql_build_coredump_seg_header(
 | 
			
		||||
		struct mpi_coredump_segment_header *seg_hdr,
 | 
			
		||||
		u32 seg_number, u32 seg_size, u8 *desc)
 | 
			
		||||
{
 | 
			
		||||
	memset(seg_hdr, 0, sizeof(struct mpi_coredump_segment_header));
 | 
			
		||||
	seg_hdr->cookie = MPI_COREDUMP_COOKIE;
 | 
			
		||||
	seg_hdr->segNum = seg_number;
 | 
			
		||||
	seg_hdr->segSize = seg_size;
 | 
			
		||||
	memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ql_gen_reg_dump(struct ql_adapter *qdev,
 | 
			
		||||
			struct ql_reg_dump *mpi_coredump)
 | 
			
		||||
{
 | 
			
		||||
	int i, status;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	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_reg_dump);
 | 
			
		||||
	memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
 | 
			
		||||
		sizeof(mpi_coredump->mpi_global_header.idString));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* segment 16 */
 | 
			
		||||
	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 16, Rev C. Step 18 */
 | 
			
		||||
	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),
 | 
			
		||||
				"NIC Registers");
 | 
			
		||||
	/* Get generic reg dump */
 | 
			
		||||
	for (i = 0; i < 64; i++)
 | 
			
		||||
		mpi_coredump->nic_regs[i] = ql_read32(qdev, i * sizeof(u32));
 | 
			
		||||
 | 
			
		||||
	/* 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)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* 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)
 | 
			
		||||
		return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef QL_REG_DUMP
 | 
			
		||||
static void ql_dump_intr_states(struct ql_adapter *qdev)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -428,6 +428,20 @@ static int ql_phys_id(struct net_device *ndev, u32 data)
 | 
			
		|||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ql_get_regs_len(struct net_device *ndev)
 | 
			
		||||
{
 | 
			
		||||
	return sizeof(struct ql_reg_dump);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ql_get_regs(struct net_device *ndev,
 | 
			
		||||
			struct ethtool_regs *regs, void *p)
 | 
			
		||||
{
 | 
			
		||||
	struct ql_adapter *qdev = netdev_priv(ndev);
 | 
			
		||||
 | 
			
		||||
	ql_gen_reg_dump(qdev, p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 | 
			
		||||
{
 | 
			
		||||
	struct ql_adapter *qdev = netdev_priv(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -555,6 +569,8 @@ const struct ethtool_ops qlge_ethtool_ops = {
 | 
			
		|||
	.get_drvinfo = ql_get_drvinfo,
 | 
			
		||||
	.get_wol = ql_get_wol,
 | 
			
		||||
	.set_wol = ql_set_wol,
 | 
			
		||||
	.get_regs_len	= ql_get_regs_len,
 | 
			
		||||
	.get_regs = ql_get_regs,
 | 
			
		||||
	.get_msglevel = ql_get_msglevel,
 | 
			
		||||
	.set_msglevel = ql_set_msglevel,
 | 
			
		||||
	.get_link = ethtool_op_get_link,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue