Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a61f8026 authored by Ron Mercer's avatar Ron Mercer Committed by David S. Miller
Browse files

qlge: Add ethtool register dump function.

parent bc083ce9
Loading
Loading
Loading
Loading
+149 −0
Original line number Diff line number Diff line
@@ -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
+180 −0
Original line number Diff line number Diff line
#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)
{
+16 −0
Original line number Diff line number Diff line
@@ -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,