Skip to contentSkip to conversation

e1000e,igb,ixgbe: add registers etc. printout code just before resetting adapters

PATCH Superseded Taku Izumi 5 participants 20 messages Jan 22, 2010 – Feb 26, 2010

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Taku Izumi

author
#0 lore raw

v2 cover e1000e,igb,ixgbe: add registers etc. printout code just before resetting adapters

Hi Jeff,

This patchset is the update version of "register etc. printout code" patch. (sorry for late reply)
The old one is http://marc.info/?l=linux-netdev&m=126286127208276&w=2

v1 -> v2:
- replaced hexdump() with print_hex_dump()
- changed the register printout inplementation (for-switch-case -> data-driven-table)

However the default value of "dump_flag" is not changed (still 1). The reason I didn't change is
- I think HW index (TDH,TDT..) and SW index (NTC,NTU) are at least necessary
- the amount of default output is not so large (see bellow)
- the adapter resetting problem doesn't happen frequently

The default output sample (NOT the actual hangup case) is as follows:

Jan 22 14:17:14 fedora11 kernel: igb 0000:03:00.0: Net device Info
Jan 22 14:17:14 fedora11 kernel: Device Name     state            trans_start
last_rx
Jan 22 14:17:14 fedora11 kernel: eth1            0000000000000003 00000000FFFB922A
0000000000000000
Jan 22 14:17:14 fedora11 kernel: igb 0000:03:00.0: Register Dump
Jan 22 14:17:14 fedora11 kernel: Register Name   [value ]
Jan 22 14:17:14 fedora11 kernel: CTRL            18c00241
Jan 22 14:17:14 fedora11 kernel: STATUS          00080783
Jan 22 14:17:14 fedora11 kernel: CTRL_EXT        10180c00
Jan 22 14:17:14 fedora11 kernel: ICR             00000081
Jan 22 14:17:14 fedora11 kernel: RCTL            0400803a
Jan 22 14:17:14 fedora11 kernel: RDLEN[0-3]      00001000 00001000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: RDH[0-3]        000000bc 00000000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: RDT[0-3]        000000ba 000000fe 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: RXDCTL[0-3]     02010810 02010810 00010000 00010000
Jan 22 14:17:14 fedora11 kernel: RDBAL[0-3]      35e48000 35f68000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: RDBAH[0-3]      00000000 00000000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TCTL            a503f0fa
Jan 22 14:17:14 fedora11 kernel: TDBAL[0-3]      35e4c000 35ef1000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TDBAH[0-3]      00000000 00000000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TDLEN[0-3]      00001000 00001000 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TDH[0-3]        00000000 0000001e 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TDT[0-3]        00000000 0000001e 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TXDCTL[0-3]     02000108 02000108 00000000 00000000
Jan 22 14:17:14 fedora11 kernel: TDFH            40020272
Jan 22 14:17:14 fedora11 kernel: TDFT            00000270
Jan 22 14:17:14 fedora11 kernel: TDFHS           00000272
Jan 22 14:17:14 fedora11 kernel: TDFPC           00000000
Jan 22 14:17:14 fedora11 kernel: igb 0000:03:00.0: TX Rings Summary
Jan 22 14:17:14 fedora11 kernel: Queue [NTU] [NTC] [bi(ntc)->dma  ] leng ntw timestamp
Jan 22 14:17:14 fedora11 kernel:     0     0     0 0000000000000000 0000   0
0000000000000000
Jan 22 14:17:14 fedora11 kernel:     1    1E    1E 0000000000000000 0000   0
0000000000000000
Jan 22 14:17:14 fedora11 kernel: igb 0000:03:00.0: RX Rings Summary
Jan 22 14:17:14 fedora11 kernel: Queue [NTU] [NTC]
Jan 22 14:17:14 fedora11 kernel:     0    BB    BC
Jan 22 14:17:14 fedora11 kernel:     1    FF     0

Best regards,
Taku Izumi

author
#1 lore raw

PATCH v2 1/3 e1000e: add registers etc. printout code just before resetting adapters

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/e1000e/hw.h     |   27 +++
 drivers/net/e1000e/netdev.c |  341 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 368 insertions(+)
drivers/net/e1000e/netdev.c +341 -0
Index: net-next-2.6/drivers/net/e1000e/netdev.c
===================================================================
@@ -52,6 +52,14 @@
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define E1000_DUMP_REGS		(1 << 0)
+#define E1000_DUMP_TX_RINGS	(1 << 1)
+#define E1000_DUMP_RX_RINGS	(1 << 2)
+#define E1000_DUMP_BUFFERS	(1 << 3)
+
 static const struct e1000_info *e1000_info_tbl[] = {
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
@@ -65,6 +73,338 @@ static const struct e1000_info *e1000_in
 	[board_pchlan]		= &e1000_pch_info,
 };
 
+/*
+ * e1000_regdump - register printout routine
+ */
+static void e1000_regdump(struct e1000_hw *hw, u32 reg,
+			  char *name, u32 (*get_regofs)(int))
+{
+	printk(KERN_ERR "%-15s %08x\n", name, __er32(hw, reg));
+}
+
+/*
+ * e1000_regdump_n - register printout routine
+ */
+static void e1000_regdump_n(struct e1000_hw *hw, u32 reg,
+			    char *name, u32 (*get_regofs)(int))
+{
+	int n = 0;
+	char rname[16];
+
+	if (!get_regofs)
+		return;
+
+	snprintf(rname, 16, "%s%s", name, "[0-1]");
+	printk(KERN_ERR "%-15s ", rname);
+	for (n = 0; n < 2; n++)
+		printk("%08x ", __er32(hw, get_regofs(n)));
+	printk("\n");
+}
+
+static const struct e1000_reg_info e1000_reg_info_tbl[] = {
+
+	/* General Registers */
+	{E1000_CTRL, "CTRL", NULL, e1000_regdump},
+	{E1000_STATUS, "STATUS", NULL, e1000_regdump},
+	{E1000_CTRL_EXT, "CTRL_EXT", NULL, e1000_regdump},
+
+	/* Interrupt Registers */
+	{E1000_ICR, "ICR", NULL, e1000_regdump},
+
+	/* RX Registers */
+	{E1000_RCTL, "RCTL", NULL, e1000_regdump},
+	{E1000_RDLEN, "RDLEN", NULL, e1000_regdump},
+	{E1000_RDH, "RDH", NULL, e1000_regdump},
+	{E1000_RDT, "RDT", NULL, e1000_regdump},
+	{E1000_RDTR, "RDTR", NULL, e1000_regdump},
+	{E1000_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, e1000_regdump_n},
+	{E1000_ERT, "ERT", NULL, e1000_regdump},
+	{E1000_RDBAL, "RDBAL", NULL, e1000_regdump},
+	{E1000_RDBAH, "RDBAH", NULL, e1000_regdump},
+	{E1000_RDFH, "RDFH", NULL, e1000_regdump},
+	{E1000_RDFT, "RDFT", NULL, e1000_regdump},
+	{E1000_RDFHS, "RDFHS", NULL, e1000_regdump},
+	{E1000_RDFTS, "RDFTS", NULL, e1000_regdump},
+	{E1000_RDFPC, "RDFPC", NULL, e1000_regdump},
+
+	/* TX Registers */
+	{E1000_TCTL, "TCTL", NULL, e1000_regdump},
+	{E1000_TDBAL, "TDBAL", NULL, e1000_regdump},
+	{E1000_TDBAH, "TDBAH", NULL, e1000_regdump},
+	{E1000_TDLEN, "TDLEN", NULL, e1000_regdump},
+	{E1000_TDH, "TDH", NULL, e1000_regdump},
+	{E1000_TDT, "TDT", NULL, e1000_regdump},
+	{E1000_TIDV, "TIDV", NULL, e1000_regdump},
+	{E1000_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, e1000_regdump_n},
+	{E1000_TADV, "TADV", NULL, e1000_regdump},
+	{E1000_TARC(0), "TARC", get_regofs_TARC, e1000_regdump_n},
+	{E1000_TDFH, "TDFH", NULL, e1000_regdump},
+	{E1000_TDFT, "TDFT", NULL, e1000_regdump},
+	{E1000_TDFHS, "TDFHS", NULL, e1000_regdump},
+	{E1000_TDFTS, "TDFTS", NULL, e1000_regdump},
+	{E1000_TDFPC, "TDFPC", NULL, e1000_regdump},
+
+	/* List Terminator */
+	{}
+};
+
+/*
+ * e1000e_dump - Print registers, tx-ring and rx-ring
+ */
+static void e1000e_dump(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_reg_info *reginfo;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct e1000_buffer *buffer_info;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	union e1000_rx_desc_packet_split *rx_desc_ps;
+	struct e1000_rx_desc *rx_desc;
+	struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+	u32 staterr;
+	int i = 0;
+
+	/* Print netdevice Info */
+	if (netdev) {
+		dev_err(&adapter->pdev->dev, "Net device Info\n");
+		printk(KERN_ERR "Device Name     state            "
+			"trans_start      last_rx\n");
+		printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+			netdev->name,
+			netdev->state,
+			netdev->trans_start,
+			netdev->last_rx);
+	}
+
+	/* Print Registers */
+	if ((dump_flag & E1000_DUMP_REGS) == 0)
+		goto tx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "Register Dump\n");
+	printk(KERN_ERR " Register Name   Value\n");
+	for (reginfo = (struct e1000_reg_info *)e1000_reg_info_tbl;
+	     reginfo->name; reginfo++) {
+		reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+					reginfo->get_regofs);
+	}
+
+	/* Print TX Ring Summary */
+tx_ring_summary:
+	if (!netdev || !netif_running(netdev))
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+		" leng ntw timestamp\n");
+	buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+	printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+		0, tx_ring->next_to_use, tx_ring->next_to_clean,
+		(u64)buffer_info->dma,
+		buffer_info->length,
+		buffer_info->next_to_watch,
+		(u64)buffer_info->time_stamp);
+
+	/* Print TX Rings */
+	if ((dump_flag & E1000_DUMP_TX_RINGS) == 0)
+		goto rx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
+	 *
+	 * Legacy Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0] (Reserved on Write Back)       |
+	 *   +--------------------------------------------------------------+
+	 * 8 | Special  |    CSS     | Status |  CMD    |  CSO   |  Length  |
+	 *   +--------------------------------------------------------------+
+	 *   63       48 47        36 35    32 31     24 23    16 15        0
+	 *
+	 * Extended Context Descriptor (DTYP=0x0) for TSO or checksum offload
+	 *   63      48 47    40 39       32 31             16 15    8 7      0
+	 *   +----------------------------------------------------------------+
+	 * 0 |  TUCSE  | TUCS0  |   TUCSS   |     IPCSE       | IPCS0 | IPCSS |
+	 *   +----------------------------------------------------------------+
+	 * 8 |   MSS   | HDRLEN | RSV | STA | TUCMD | DTYP |      PAYLEN      |
+	 *   +----------------------------------------------------------------+
+	 *   63      48 47    40 39 36 35 32 31   24 23  20 19                0
+	 *
+	 * Extended Data Descriptor (DTYP=0x1)
+	 *   +----------------------------------------------------------------+
+	 * 0 |                     Buffer Address [63:0]                      |
+	 *   +----------------------------------------------------------------+
+	 * 8 | VLAN tag |  POPTS  | Rsvd | Status | Command | DTYP |  DTALEN  |
+	 *   +----------------------------------------------------------------+
+	 *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
+	 */
+	printk(KERN_ERR "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
+		" [bi->dma       ] leng  ntw timestamp        bi->skb "
+		"<-- Legacy format\n");
+	printk(KERN_ERR "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
+		" [bi->dma       ] leng  ntw timestamp        bi->skb "
+		"<-- Ext Context format\n");
+	printk(KERN_ERR "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
+		" [bi->dma       ] leng  ntw timestamp        bi->skb "
+		"<-- Ext Data format\n");
+	for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+		tx_desc = E1000_TX_DESC(*tx_ring, i);
+		buffer_info = &tx_ring->buffer_info[i];
+		u0 = (struct my_u0 *)tx_desc;
+		printk(KERN_ERR "T%c[0x%03X]    %016llX %016llX %016llX "
+			"%04X  %3X %016llX %p",
+		       (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
+			((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+		       le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+		       (u64)buffer_info->dma, buffer_info->length,
+		       buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+		       buffer_info->skb);
+		if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
+			printk(" NTC/U\n");
+		else if (i == tx_ring->next_to_use)
+			printk(" NTU\n");
+		else if (i == tx_ring->next_to_clean)
+			printk(" NTC\n");
+		else
+			printk("\n");
+
+		if ((dump_flag & E1000_DUMP_BUFFERS) && buffer_info->dma != 0)
+			print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS,
+					16, 1, phys_to_virt(buffer_info->dma),
+					buffer_info->length, true);
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC]\n");
+	printk(KERN_ERR " %5d %5X %5X\n", 0,
+		rx_ring->next_to_use, rx_ring->next_to_clean);
+
+	/* Print RX Rings */
+	if ((dump_flag & E1000_DUMP_RX_RINGS) == 0)
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+	switch (adapter->rx_ps_pages) {
+	case 1:
+	case 2:
+	case 3:
+		/* [Extended] Packet Split Receive Descriptor Format
+		 *
+		 *    +-----------------------------------------------------+
+		 *  0 |                Buffer Address 0 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 *  8 |                Buffer Address 1 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 * 16 |                Buffer Address 2 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 * 24 |                Buffer Address 3 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 */
+		printk(KERN_ERR "R  [desc]      [buffer 0 63:0 ] "
+			"[buffer 1 63:0 ] "
+		       "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
+		       "[bi->skb] <-- Ext Pkt Split format\n");
+		/* [Extended] Receive Descriptor (Write-Back) Format
+		 *
+		 *   63       48 47    32 31     13 12    8 7    4 3        0
+		 *   +------------------------------------------------------+
+		 * 0 | Packet   | IP     |  Rsvd   | MRQ   | Rsvd | MRQ RSS |
+		 *   | Checksum | Ident  |         | Queue |      |  Type   |
+		 *   +------------------------------------------------------+
+		 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+		 *   +------------------------------------------------------+
+		 *   63       48 47    32 31            20 19               0
+		 */
+		printk(KERN_ERR "RWB[desc]      [ck ipid mrqhsh] "
+			"[vl   l0 ee  es] "
+		       "[ l3  l2  l1 hs] [reserved      ] ---------------- "
+		       "[bi->skb] <-- Ext Rx Write-Back format\n");
+		for (i = 0; i < rx_ring->count; i++) {
+			buffer_info = &rx_ring->buffer_info[i];
+			rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
+			u1 = (struct my_u1 *)rx_desc_ps;
+			staterr =
+				le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+			if (staterr & E1000_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk(KERN_ERR "RWB[0x%03X]     %016llX "
+					"%016llX %016llX %016llX "
+					"---------------- %p", i,
+					le64_to_cpu(u1->a),
+					le64_to_cpu(u1->b),
+					le64_to_cpu(u1->c),
+					le64_to_cpu(u1->d),
+					buffer_info->skb);
+			} else {
+				printk(KERN_ERR "R  [0x%03X]     %016llX "
+					"%016llX %016llX %016llX %016llX %p", i,
+					le64_to_cpu(u1->a),
+					le64_to_cpu(u1->b),
+					le64_to_cpu(u1->c),
+					le64_to_cpu(u1->d),
+					(u64)buffer_info->dma,
+					buffer_info->skb);
+
+				if (dump_flag & E1000_DUMP_BUFFERS)
+					print_hex_dump(KERN_ERR, "",
+						DUMP_PREFIX_ADDRESS, 16, 1,
+						phys_to_virt(buffer_info->dma),
+						adapter->rx_ps_bsize0, true);
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+		}
+		break;
+	default:
+	case 0:
+		/* Legacy Receive Descriptor Format
+		 *
+		 * +-----------------------------------------------------+
+		 * |                Buffer Address [63:0]                |
+		 * +-----------------------------------------------------+
+		 * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
+		 * +-----------------------------------------------------+
+		 * 63       48 47    40 39      32 31         16 15      0
+		 */
+		printk(KERN_ERR "Rl[desc]     [address 63:0  ] "
+			"[vl er S cks ln] [bi->dma       ] [bi->skb] "
+			"<-- Legacy format\n");
+		for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
+			rx_desc = E1000_RX_DESC(*rx_ring, i);
+			buffer_info = &rx_ring->buffer_info[i];
+			u0 = (struct my_u0 *)rx_desc;
+			printk(KERN_ERR "Rl[0x%03X]    %016llX %016llX "
+				"%016llX %p",
+				i, le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+				(u64)buffer_info->dma, buffer_info->skb);
+			if (i == rx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+
+			if (dump_flag & E1000_DUMP_BUFFERS)
+				print_hex_dump(KERN_ERR, "",
+					DUMP_PREFIX_ADDRESS,
+					16, 1, phys_to_virt(buffer_info->dma),
+					adapter->rx_buffer_len, true);
+		}
+	}
+
+exit:
+	return;
+}
+
 /**
  * e1000_desc_unused - calculate if we have unused descriptors
  **/
@@ -4247,6 +4587,7 @@ static void e1000_reset_task(struct work
 	struct e1000_adapter *adapter;
 	adapter = container_of(work, struct e1000_adapter, reset_task);
 
+	e1000e_dump(adapter);
 	e1000e_reinit_locked(adapter);
 }
 
drivers/net/e1000e/hw.h +27 -0
Index: net-next-2.6/drivers/net/e1000e/hw.h
===================================================================
@@ -92,6 +92,11 @@ enum e1e_registers {
 	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
 	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
 	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
+	E1000_RDFH     = 0x02410, /* Rx Data FIFO Head - RW */
+	E1000_RDFT     = 0x02418, /* Rx Data FIFO Tail - RW */
+	E1000_RDFHS    = 0x02420, /* Rx Data FIFO Head Saved - RW */
+	E1000_RDFTS    = 0x02428, /* Rx Data FIFO Tail Saved - RW */
+	E1000_RDFPC    = 0x02430, /* Rx Data FIFO Packet Count - RW */
 	E1000_RDBAL    = 0x02800, /* Rx Descriptor Base Address Low - RW */
 	E1000_RDBAH    = 0x02804, /* Rx Descriptor Base Address High - RW */
 	E1000_RDLEN    = 0x02808, /* Rx Descriptor Length - RW */
@@ -101,6 +106,11 @@ enum e1e_registers {
 	E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
 #define E1000_RXDCTL(_n)   (E1000_RXDCTL_BASE + (_n << 8))
 	E1000_RADV     = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+	E1000_TDFH     = 0x03410, /* Tx Data FIFO Head - RW */
+	E1000_TDFT     = 0x03418, /* Tx Data FIFO Tail - RW */
+	E1000_TDFHS    = 0x03420, /* Tx Data FIFO Head Saved - RW */
+	E1000_TDFTS    = 0x03428, /* Tx Data FIFO Tail Saved - RW */
+	E1000_TDFPC    = 0x03430, /* Tx Data FIFO Packet Count - RW */
 
 /* Convenience macros
  *
@@ -219,6 +229,23 @@ enum e1e_registers {
 	E1000_HICR      = 0x08F00, /* Host Interface Control */
 };
 
+struct e1000_reg_info {
+	u32 reg;
+	char *name;
+	u32 (*get_regofs)(int);
+	void (*dump_reg)(struct e1000_hw *, u32, char *, u32 (*)(int));
+};
+
+#define E1000_GET_REGOFS_FUNC(name)				\
+static inline u32 get_regofs_##name(int n)			\
+{								\
+	return E1000_##name(n);						\
+}								\
+
+E1000_GET_REGOFS_FUNC(RXDCTL)
+E1000_GET_REGOFS_FUNC(TXDCTL)
+E1000_GET_REGOFS_FUNC(TARC)
+
 #define E1000_MAX_PHY_ADDR		4
 
 /* IGP01E1000 Specific Registers */
author
#4 lore raw

PATCH v2 2/3 igb: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/igb/e1000_hw.h   |    7 +
 drivers/net/igb/e1000_regs.h |   21 +++
 drivers/net/igb/igb_main.c   |  294 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 322 insertions(+)
drivers/net/igb/igb_main.c +294 -0
Index: net-next-2.6/drivers/net/igb/igb_main.c
===================================================================
@@ -60,6 +60,14 @@ static const struct e1000_info *igb_info
 	[board_82575] = &e1000_82575_info,
 };
 
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define IGB_DUMP_REGS		(1 << 0)
+#define IGB_DUMP_TX_RINGS	(1 << 1)
+#define IGB_DUMP_RX_RINGS	(1 << 2)
+#define IGB_DUMP_BUFFERS	(1 << 3)
+
 static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
@@ -189,6 +197,291 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Eth
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+/*
+ * igb_regdump - register printout routine
+ */
+static void igb_regdump(struct e1000_hw *hw, u32 reg,
+			char *name, u32 (*get_regofs)(int))
+{
+	printk(KERN_ERR "%-15s %08x\n", name, rd32(reg));
+}
+
+/*
+ * igb_regdump_n - register printout routine
+ */
+static void igb_regdump_n(struct e1000_hw *hw, u32 reg,
+			  char *name, u32 (*get_regofs)(int))
+{
+	int n = 0;
+	char rname[16];
+
+	if (!get_regofs)
+		return;
+
+	snprintf(rname, 16, "%s%s", name, "[0-3]");
+	printk(KERN_ERR "%-15s ", rname);
+	for (n = 0; n < 4; n++)
+		printk("%08x ", rd32(get_regofs(n)));
+	printk("\n");
+}
+
+static const struct igb_reg_info igb_reg_info_tbl[] = {
+
+	/* General Registers */
+	{E1000_CTRL, "CTRL", NULL, igb_regdump},
+	{E1000_STATUS, "STATUS", NULL, igb_regdump},
+	{E1000_CTRL_EXT, "CTRL_EXT", NULL, igb_regdump},
+
+	/* Interrupt Registers */
+	{E1000_ICR, "ICR", NULL, igb_regdump},
+
+	/* RX Registers */
+	{E1000_RCTL, "RCTL", NULL, igb_regdump},
+	{E1000_RDLEN(0), "RDLEN", get_regofs_RDLEN, igb_regdump_n},
+	{E1000_RDH(0), "RDH", get_regofs_RDH, igb_regdump_n},
+	{E1000_RDT(0), "RDT", get_regofs_RDT, igb_regdump_n},
+	{E1000_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, igb_regdump_n},
+	{E1000_RDBAL(0), "RDBAL", get_regofs_RDBAL, igb_regdump_n},
+	{E1000_RDBAH(0), "RDBAH", get_regofs_RDBAH, igb_regdump_n},
+
+	/* TX Registers */
+	{E1000_TCTL, "TCTL", NULL, igb_regdump},
+	{E1000_TDBAL(0), "TDBAL", get_regofs_TDBAL, igb_regdump_n},
+	{E1000_TDBAH(0), "TDBAH", get_regofs_TDBAH, igb_regdump_n},
+	{E1000_TDLEN(0), "TDLEN", get_regofs_TDLEN, igb_regdump_n},
+	{E1000_TDH(0), "TDH", get_regofs_TDH, igb_regdump_n},
+	{E1000_TDT(0), "TDT", get_regofs_TDT, igb_regdump_n},
+	{E1000_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, igb_regdump_n},
+	{E1000_TDFH, "TDFH", NULL, igb_regdump},
+	{E1000_TDFT, "TDFT", NULL, igb_regdump},
+	{E1000_TDFHS, "TDFHS", NULL, igb_regdump},
+	{E1000_TDFPC, "TDFPC", NULL, igb_regdump},
+
+	/* List Terminator */
+	{}
+};
+
+/*
+ * igb_dump - Print registers, tx-rings and rx-rings
+ */
+static void igb_dump(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct igb_reg_info *reginfo;
+	int n = 0;
+	struct igb_ring *tx_ring;
+	union e1000_adv_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct igb_buffer *buffer_info;
+	struct igb_ring *rx_ring;
+	union e1000_adv_rx_desc *rx_desc;
+	u32 staterr;
+	int i = 0;
+
+	/* Print netdevice Info */
+	if (netdev) {
+		dev_err(&adapter->pdev->dev, "Net device Info\n");
+		printk(KERN_ERR "Device Name     state            "
+			"trans_start      last_rx\n");
+		printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+		netdev->name,
+		netdev->state,
+		netdev->trans_start,
+		netdev->last_rx);
+	}
+
+	/* Print Registers */
+	if ((dump_flag & IGB_DUMP_REGS) == 0)
+		goto tx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "Register Dump\n");
+	printk(KERN_ERR " Register Name   [value ]\n");
+	for (reginfo = (struct igb_reg_info *)igb_reg_info_tbl;
+	     reginfo->name; reginfo++) {
+		reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+					reginfo->get_regofs);
+	}
+
+	/* Print TX Ring Summary */
+tx_ring_summary:
+	if (!netdev || !netif_running(netdev))
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+		" leng ntw timestamp\n");
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+		printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+			   n, tx_ring->next_to_use, tx_ring->next_to_clean,
+			   (u64)buffer_info->dma,
+			   buffer_info->length,
+			   buffer_info->next_to_watch,
+			   (u64)buffer_info->time_stamp);
+	}
+
+	/* Print TX Rings */
+	if ((dump_flag & IGB_DUMP_TX_RINGS) == 0)
+		goto rx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats
+	 *
+	 * Advanced Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0]                                |
+	 *   +--------------------------------------------------------------+
+	 * 8 | PAYLEN  | PORTS  |CC|IDX | STA | DCMD  |DTYP|MAC|RSV| DTALEN |
+	 *   +--------------------------------------------------------------+
+	 *   63      46 45    40 39 38 36 35 32 31   24             15       0
+	 */
+
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "T [desc]     [address 63:0  ] "
+			"[PlPOCIStDDM Ln] [bi->dma       ] "
+			"leng  ntw timestamp        bi->skb\n");
+
+		for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+			tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
+			buffer_info = &tx_ring->buffer_info[i];
+			u0 = (struct my_u0 *)tx_desc;
+			printk(KERN_ERR "T [0x%03X]    %016llX %016llX %016llX"
+				" %04X  %3X %016llX %p", i,
+				le64_to_cpu(u0->a),
+				le64_to_cpu(u0->b),
+				(u64)buffer_info->dma,
+				buffer_info->length,
+				buffer_info->next_to_watch,
+				(u64)buffer_info->time_stamp,
+				buffer_info->skb);
+			if (i == tx_ring->next_to_use &&
+				i == tx_ring->next_to_clean)
+				printk(" NTC/U\n");
+			else if (i == tx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == tx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+
+			if ((dump_flag & IGB_DUMP_BUFFERS) &&
+				buffer_info->dma != 0)
+				print_hex_dump(KERN_ERR, "",
+					DUMP_PREFIX_ADDRESS,
+					16, 1, phys_to_virt(buffer_info->dma),
+					buffer_info->length, true);
+		}
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC]\n");
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR " %5d %5X %5X\n", n,
+			   rx_ring->next_to_use, rx_ring->next_to_clean);
+	}
+
+	/* Print RX Rings */
+	if ((dump_flag & IGB_DUMP_RX_RINGS) == 0)
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+
+	/* Advanced Receive Descriptor (Read) Format
+	 *    63                                           1        0
+	 *    +-----------------------------------------------------+
+	 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+	 *    +----------------------------------------------+------+
+	 *  8 |       Header Buffer Address [63:1]           |  DD  |
+	 *    +-----------------------------------------------------+
+	 *
+	 *
+	 * Advanced Receive Descriptor (Write-Back) Format
+	 *
+	 *   63       48 47    32 31  30      21 20 17 16   4 3     0
+	 *   +------------------------------------------------------+
+	 * 0 | Packet     IP     |SPH| HDR_LEN   | RSV|Packet|  RSS |
+	 *   | Checksum   Ident  |   |           |    | Type | Type |
+	 *   +------------------------------------------------------+
+	 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+	 *   +------------------------------------------------------+
+	 *   63       48 47    32 31            20 19               0
+	 */
+
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "R  [desc]      [ PktBuf     A0] "
+			"[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+			"<-- Adv Rx Read format\n");
+		printk(KERN_ERR "RWB[desc]      [PcsmIpSHl PtRs] "
+			"[vl er S cks ln] ---------------- [bi->skb] "
+			"<-- Adv Rx Write-Back format\n");
+
+		for (i = 0; i < rx_ring->count; i++) {
+			buffer_info = &rx_ring->buffer_info[i];
+			rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+			u0 = (struct my_u0 *)rx_desc;
+			staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+			if (staterr & E1000_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk(KERN_ERR "RWB[0x%03X]     %016llX "
+					"%016llX ---------------- %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					buffer_info->skb);
+			} else {
+				printk(KERN_ERR "R  [0x%03X]     %016llX "
+					"%016llX %016llX %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					(u64)buffer_info->dma,
+					buffer_info->skb);
+
+				if (dump_flag & IGB_DUMP_BUFFERS) {
+					print_hex_dump(KERN_ERR, "",
+						DUMP_PREFIX_ADDRESS,
+						16, 1,
+						phys_to_virt(buffer_info->dma),
+						rx_ring->rx_buffer_len, true);
+					if (rx_ring->rx_buffer_len
+						< IGB_RXBUFFER_1024)
+						print_hex_dump(KERN_ERR, "",
+						  DUMP_PREFIX_ADDRESS,
+						  16, 1,
+						  phys_to_virt(
+						    buffer_info->page_dma +
+						    buffer_info->page_offset),
+						  PAGE_SIZE/2, true);
+				}
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+
+		}
+	}
+
+exit:
+	return;
+}
+
+
 /**
  * igb_read_clock - read raw cycle counter (to be used by time counter)
  */
@@ -3854,6 +4147,7 @@ static void igb_reset_task(struct work_s
 	struct igb_adapter *adapter;
 	adapter = container_of(work, struct igb_adapter, reset_task);
 
+	igb_dump(adapter);
 	igb_reinit_locked(adapter);
 }
 
drivers/net/igb/e1000_regs.h +21 -0
Index: net-next-2.6/drivers/net/igb/e1000_regs.h
===================================================================
@@ -322,4 +322,25 @@
 
 /* DMA Coalescing registers */
 #define E1000_PCIEMISC          0x05BB8 /* PCIE misc config register */
+
+
+#define IGB_GET_REGOFS_FUNC(name)				\
+static inline u32 get_regofs_##name(int n)			\
+{								\
+	return E1000_##name(n);					\
+}								\
+
+IGB_GET_REGOFS_FUNC(RDLEN)
+IGB_GET_REGOFS_FUNC(RDH)
+IGB_GET_REGOFS_FUNC(RDT)
+IGB_GET_REGOFS_FUNC(RXDCTL)
+IGB_GET_REGOFS_FUNC(RDBAL)
+IGB_GET_REGOFS_FUNC(RDBAH)
+IGB_GET_REGOFS_FUNC(TDBAL)
+IGB_GET_REGOFS_FUNC(TDBAH)
+IGB_GET_REGOFS_FUNC(TDLEN)
+IGB_GET_REGOFS_FUNC(TDH)
+IGB_GET_REGOFS_FUNC(TDT)
+IGB_GET_REGOFS_FUNC(TXDCTL)
+
 #endif
drivers/net/igb/e1000_hw.h +7 -0
Index: net-next-2.6/drivers/net/igb/e1000_hw.h
===================================================================
@@ -508,6 +508,13 @@ struct e1000_hw {
 	u8  revision_id;
 };
 
+struct igb_reg_info {
+	u32 reg;
+	char *name;
+	u32 (*get_regofs)(int);
+	void (*dump_reg)(struct e1000_hw *, u32, char *, u32 (*)(int));
+};
+
 #ifdef DEBUG
 extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
 #define hw_dbg(format, arg...) \
author
#6 lore raw

PATCH v2 3/3 ixgbe: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/ixgbe/ixgbe_main.c |  293 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_type.h |   29 ++++
 2 files changed, 322 insertions(+)
drivers/net/ixgbe/ixgbe_main.c +293 -0
Index: net-next-2.6/drivers/net/ixgbe/ixgbe_main.c
===================================================================
@@ -60,6 +60,15 @@ static const struct ixgbe_info *ixgbe_in
 	[board_82599] = &ixgbe_82599_info,
 };
 
+
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define IXGBE_DUMP_REGS		(1 << 0)
+#define IXGBE_DUMP_TX_RINGS	(1 << 1)
+#define IXGBE_DUMP_RX_RINGS	(1 << 2)
+#define IXGBE_DUMP_BUFFERS	(1 << 3)
+
 /* ixgbe_pci_tbl - PCI Device ID Table
  *
  * Wildcard entries (PCI_ANY_ID) should come last
@@ -174,6 +183,289 @@ static inline void ixgbe_disable_sriov(s
 	adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
 }
 
+/*
+ * ixgbe_regdump - register printout routine
+ */
+static void ixgbe_regdump(struct ixgbe_hw *hw, u32 reg,
+			  char *name, u32 (*get_regofs)(int))
+{
+	printk(KERN_ERR "%-15s %08x\n", name, IXGBE_READ_REG(hw, reg));
+}
+
+/*
+ * ixgbe_regdump_n - register printout routine
+ */
+static void ixgbe_regdump_n(struct ixgbe_hw *hw, u32 reg,
+			    char *name, u32 (*get_regofs)(int))
+{
+	int i = 0, j = 0;
+	char rname[16];
+
+	if (!get_regofs)
+		return;
+
+	for (i = 0; i < 8; i++) {
+		snprintf(rname, 16, "%s[%d-%d]", name, i*8, i*8+7);
+		printk(KERN_ERR "%-15s ", rname);
+		for (j = 0; j < 8; j++)
+			printk("%08x ", IXGBE_READ_REG(hw, get_regofs(i*8+j)));
+		printk("\n");
+	}
+}
+
+static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+
+	/* General Registers */
+	{IXGBE_CTRL, "CTRL", NULL, ixgbe_regdump},
+	{IXGBE_STATUS, "STATUS", NULL, ixgbe_regdump},
+	{IXGBE_CTRL_EXT, "CTRL_EXT", NULL, ixgbe_regdump},
+
+	/* Interrupt Registers */
+	{IXGBE_EICR, "EICR", NULL, ixgbe_regdump},
+
+	/* RX Registers */
+	{IXGBE_SRRCTL(0), "SRRCTL", get_regofs_SRRCTL, ixgbe_regdump_n},
+	{IXGBE_DCA_RXCTRL(0), "DRXCTL", get_regofs_DCA_RXCTRL, ixgbe_regdump_n},
+	{IXGBE_RDLEN(0), "RDLEN", get_regofs_RDLEN, ixgbe_regdump_n},
+	{IXGBE_RDH(0), "RDH", get_regofs_RDH, ixgbe_regdump_n},
+	{IXGBE_RDT(0), "RDT", get_regofs_RDT, ixgbe_regdump_n},
+	{IXGBE_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, ixgbe_regdump_n},
+	{IXGBE_RDBAL(0), "RDBAL", get_regofs_RDBAL, ixgbe_regdump_n},
+	{IXGBE_RDBAH(0), "RDBAH", get_regofs_RDBAH, ixgbe_regdump_n},
+
+	/* TX Registers */
+	{IXGBE_TDBAL(0), "TDBAL", get_regofs_TDBAL, ixgbe_regdump_n},
+	{IXGBE_TDBAH(0), "TDBAH", get_regofs_TDBAH, ixgbe_regdump_n},
+	{IXGBE_TDLEN(0), "TDLEN", get_regofs_TDLEN, ixgbe_regdump_n},
+	{IXGBE_TDH(0), "TDH", get_regofs_TDH, ixgbe_regdump_n},
+	{IXGBE_TDT(0), "TDT", get_regofs_TDT, ixgbe_regdump_n},
+	{IXGBE_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, ixgbe_regdump_n},
+
+	/* List Terminator */
+	{}
+};
+
+/*
+ * ixgbe_dump - Print registers, tx-rings and rx-rings
+ */
+static void ixgbe_dump(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct ixgbe_reg_info *reginfo;
+	int n = 0;
+	struct ixgbe_ring *tx_ring;
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	union ixgbe_adv_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct ixgbe_ring *rx_ring;
+	union ixgbe_adv_rx_desc *rx_desc;
+	struct ixgbe_rx_buffer *rx_buffer_info;
+	u32 staterr;
+	int i = 0;
+
+	/* Print netdevice Info */
+	dev_err(&adapter->pdev->dev, "Net device Info\n");
+	if (netdev) {
+		printk(KERN_ERR "Device Name     state            "
+			"trans_start      last_rx\n");
+		printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+		netdev->name,
+		netdev->state,
+		netdev->trans_start,
+		netdev->last_rx);
+	}
+
+	/* Print Registers */
+	if ((dump_flag & IXGBE_DUMP_REGS) == 0)
+		goto tx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "Register Dump\n");
+	printk(KERN_ERR " Register Name   [value ]\n");
+	for (reginfo = (struct ixgbe_reg_info *)ixgbe_reg_info_tbl;
+	     reginfo->name; reginfo++) {
+		reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+					reginfo->get_regofs);
+	}
+
+	/* Print TX Ring Summary */
+tx_ring_summary:
+	if (!netdev || !netif_running(netdev))
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ] "
+		"leng ntw timestamp\n");
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		tx_buffer_info =
+			&tx_ring->tx_buffer_info[tx_ring->next_to_clean];
+		printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+			   n, tx_ring->next_to_use, tx_ring->next_to_clean,
+			   (u64)tx_buffer_info->dma,
+			   tx_buffer_info->length,
+			   tx_buffer_info->next_to_watch,
+			   (u64)tx_buffer_info->time_stamp);
+	}
+
+	/* Print TX Rings */
+	if ((dump_flag & IXGBE_DUMP_TX_RINGS) == 0)
+		goto rx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats
+	 *
+	 * Advanced Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0]                                |
+	 *   +--------------------------------------------------------------+
+	 * 8 |  PAYLEN  | PORTS  | IDX | STA | DCMD  |DTYP |  RSV |  DTALEN |
+	 *   +--------------------------------------------------------------+
+	 *   63       46 45    40 39 36 35 32 31   24 23 20 19              0
+	 */
+
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "T [desc]     [address 63:0  ] "
+			"[PlPOIdStDDt Ln] [bi->dma       ] "
+			"leng  ntw timestamp        bi->skb\n");
+
+		for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+			tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+			tx_buffer_info = &tx_ring->tx_buffer_info[i];
+			u0 = (struct my_u0 *)tx_desc;
+			printk(KERN_ERR "T [0x%03X]    %016llX %016llX %016llX"
+				" %04X  %3X %016llX %p", i,
+				le64_to_cpu(u0->a),
+				le64_to_cpu(u0->b),
+				(u64)tx_buffer_info->dma,
+				tx_buffer_info->length,
+				tx_buffer_info->next_to_watch,
+				(u64)tx_buffer_info->time_stamp,
+				tx_buffer_info->skb);
+			if (i == tx_ring->next_to_use &&
+				i == tx_ring->next_to_clean)
+				printk(" NTC/U\n");
+			else if (i == tx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == tx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+
+			if ((dump_flag & IXGBE_DUMP_BUFFERS) &&
+				tx_buffer_info->dma != 0)
+				print_hex_dump(KERN_ERR, "",
+					DUMP_PREFIX_ADDRESS, 16, 1,
+					phys_to_virt(tx_buffer_info->dma),
+					tx_buffer_info->length, true);
+		}
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC]\n");
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR "%5d %5X %5X\n", n,
+			   rx_ring->next_to_use, rx_ring->next_to_clean);
+	}
+
+	/* Print RX Rings */
+	if ((dump_flag & IXGBE_DUMP_RX_RINGS) == 0)
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+
+	/* Advanced Receive Descriptor (Read) Format
+	 *    63                                           1        0
+	 *    +-----------------------------------------------------+
+	 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+	 *    +----------------------------------------------+------+
+	 *  8 |       Header Buffer Address [63:1]           |  DD  |
+	 *    +-----------------------------------------------------+
+	 *
+	 *
+	 * Advanced Receive Descriptor (Write-Back) Format
+	 *
+	 *   63       48 47    32 31  30      21 20 16 15   4 3     0
+	 *   +------------------------------------------------------+
+	 * 0 | Packet     IP     |SPH| HDR_LEN   | RSV|Packet|  RSS |
+	 *   | Checksum   Ident  |   |           |    | Type | Type |
+	 *   +------------------------------------------------------+
+	 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+	 *   +------------------------------------------------------+
+	 *   63       48 47    32 31            20 19               0
+	 */
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "R  [desc]      [ PktBuf     A0] "
+			"[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+			"<-- Adv Rx Read format\n");
+		printk(KERN_ERR "RWB[desc]      [PcsmIpSHl PtRs] "
+			"[vl er S cks ln] ---------------- [bi->skb] "
+			"<-- Adv Rx Write-Back format\n");
+
+		for (i = 0; i < rx_ring->count; i++) {
+			rx_buffer_info = &rx_ring->rx_buffer_info[i];
+			rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+			u0 = (struct my_u0 *)rx_desc;
+			staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+			if (staterr & IXGBE_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk(KERN_ERR "RWB[0x%03X]     %016llX "
+					"%016llX ---------------- %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					rx_buffer_info->skb);
+			} else {
+				printk(KERN_ERR "R  [0x%03X]     %016llX "
+					"%016llX %016llX %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					(u64)rx_buffer_info->dma,
+					rx_buffer_info->skb);
+
+				if (dump_flag & IXGBE_DUMP_BUFFERS) {
+					print_hex_dump(KERN_ERR, "",
+					   DUMP_PREFIX_ADDRESS, 16, 1,
+					   phys_to_virt(rx_buffer_info->dma),
+					   rx_ring->rx_buf_len, true);
+
+					if (rx_ring->rx_buf_len
+						< IXGBE_RXBUFFER_2048)
+						print_hex_dump(KERN_ERR, "",
+						  DUMP_PREFIX_ADDRESS, 16, 1,
+						  phys_to_virt(
+						    rx_buffer_info->page_dma +
+						    rx_buffer_info->page_offset
+						  ),
+						  PAGE_SIZE/2, true);
+				}
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+
+		}
+	}
+
+exit:
+	return;
+}
+
 static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
 {
 	u32 ctrl_ext;
@@ -3306,6 +3598,7 @@ static void ixgbe_reset_task(struct work
 
 	adapter->tx_timeout_count++;
 
+	ixgbe_dump(adapter);
 	ixgbe_reinit_locked(adapter);
 }
 
drivers/net/ixgbe/ixgbe_type.h +29 -0
Index: net-next-2.6/drivers/net/ixgbe/ixgbe_type.h
===================================================================
@@ -2568,4 +2568,33 @@ struct ixgbe_info {
 #define IXGBE_ERR_EEPROM_VERSION                -24
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
+
+struct ixgbe_reg_info {
+	u32 reg;
+	char *name;
+	u32 (*get_regofs)(int);
+	void (*dump_reg)(struct ixgbe_hw *, u32, char *, u32 (*)(int));
+};
+
+#define IXGBE_GET_REGOFS_FUNC(name)				\
+static inline u32 get_regofs_##name(int n)			\
+{								\
+	return IXGBE_##name(n);					\
+}								\
+
+IXGBE_GET_REGOFS_FUNC(SRRCTL)
+IXGBE_GET_REGOFS_FUNC(DCA_RXCTRL)
+IXGBE_GET_REGOFS_FUNC(RDLEN)
+IXGBE_GET_REGOFS_FUNC(RDH)
+IXGBE_GET_REGOFS_FUNC(RDT)
+IXGBE_GET_REGOFS_FUNC(RXDCTL)
+IXGBE_GET_REGOFS_FUNC(RDBAL)
+IXGBE_GET_REGOFS_FUNC(RDBAH)
+IXGBE_GET_REGOFS_FUNC(TDBAL)
+IXGBE_GET_REGOFS_FUNC(TDBAH)
+IXGBE_GET_REGOFS_FUNC(TDLEN)
+IXGBE_GET_REGOFS_FUNC(TDH)
+IXGBE_GET_REGOFS_FUNC(TDT)
+IXGBE_GET_REGOFS_FUNC(TXDCTL)
+
 #endif /* _IXGBE_TYPE_H_ */
#8 lore raw
In reply to Taku Izumi

Trivial:

All of the printks without KERN_<level> should be KERN_CONT

For example:

Review

Quoted 4 lines
(quoted diff) +4 -0
+	printk(KERN_ERR "%-15s ", rname);
+	for (n = 0; n < 2; n++)
+		printk("%08x ", __er32(hw, get_regofs(n)));
+	printk("\n");

This should be:

	printk(KERN_ERR etc...)
	for (n = 0...)
		printk(KERN_CONT "%08x ", etc...
	printk(KERN_CONT "\n")

or perhaps written without the for loop

	printk(KERN_ERR "%-15s %08x %08x\n",
	       name, __er32(hw, get_regofs(0)), __er32(hw, get_regofs(1)));
author
#9 lore raw
Quoted 18 lines · Joe Perches

Trivial:

All of the printks without KERN_<level> should be KERN_CONT

For example:

Review

Quoted 4 lines
(quoted diff) +4 -0
+	printk(KERN_ERR "%-15s ", rname);
+	for (n = 0; n<  2; n++)
+		printk("%08x ", __er32(hw, get_regofs(n)));
+	printk("\n");

This should be:

	printk(KERN_ERR etc...)
	for (n = 0...)
		printk(KERN_CONT "%08x ", etc...
	printk(KERN_CONT "\n")
Quoted 5 lines

or perhaps written without the for loop

	printk(KERN_ERR "%-15s %08x %08x\n",
	       name, __er32(hw, get_regofs(0)), __er32(hw, get_regofs(1)));

Thank you for good information! I didn't realize that. I'll rewrite all.

Best regards,
Taku Izumi

author
#2 lore raw

Re: [PATCH v2 1/3] e1000e: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/e1000e/hw.h     |   27 +++
 drivers/net/e1000e/netdev.c |  341 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 368 insertions(+)
drivers/net/e1000e/netdev.c +341 -0
Index: net-next-2.6/drivers/net/e1000e/netdev.c
===================================================================
@@ -52,6 +52,14 @@
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define E1000_DUMP_REGS		(1 << 0)
+#define E1000_DUMP_TX_RINGS	(1 << 1)
+#define E1000_DUMP_RX_RINGS	(1 << 2)
+#define E1000_DUMP_BUFFERS	(1 << 3)
+
 static const struct e1000_info *e1000_info_tbl[] = {
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
@@ -65,6 +73,338 @@ static const struct e1000_info *e1000_in
 	[board_pchlan]		= &e1000_pch_info,
 };
 
+/*
+ * e1000_regdump - register printout routine
+ */
+static void e1000_regdump(struct e1000_hw *hw, u32 reg,
+			  char *name, u32 (*get_regofs)(int))
+{
+	printk(KERN_ERR "%-15s %08x\n", name, __er32(hw, reg));
+}
+
+/*
+ * e1000_regdump_n - register printout routine
+ */
+static void e1000_regdump_n(struct e1000_hw *hw, u32 reg,
+			    char *name, u32 (*get_regofs)(int))
+{
+	int n = 0;
+	char rname[16];
+
+	if (!get_regofs)
+		return;
+
+	snprintf(rname, 16, "%s%s", name, "[0-1]");
+	printk(KERN_ERR "%-15s ", rname);
+	for (n = 0; n < 2; n++)
+		printk(KERN_CONT "%08x ", __er32(hw, get_regofs(n)));
+	printk(KERN_CONT "\n");
+}
+
+static const struct e1000_reg_info e1000_reg_info_tbl[] = {
+
+	/* General Registers */
+	{E1000_CTRL, "CTRL", NULL, e1000_regdump},
+	{E1000_STATUS, "STATUS", NULL, e1000_regdump},
+	{E1000_CTRL_EXT, "CTRL_EXT", NULL, e1000_regdump},
+
+	/* Interrupt Registers */
+	{E1000_ICR, "ICR", NULL, e1000_regdump},
+
+	/* RX Registers */
+	{E1000_RCTL, "RCTL", NULL, e1000_regdump},
+	{E1000_RDLEN, "RDLEN", NULL, e1000_regdump},
+	{E1000_RDH, "RDH", NULL, e1000_regdump},
+	{E1000_RDT, "RDT", NULL, e1000_regdump},
+	{E1000_RDTR, "RDTR", NULL, e1000_regdump},
+	{E1000_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, e1000_regdump_n},
+	{E1000_ERT, "ERT", NULL, e1000_regdump},
+	{E1000_RDBAL, "RDBAL", NULL, e1000_regdump},
+	{E1000_RDBAH, "RDBAH", NULL, e1000_regdump},
+	{E1000_RDFH, "RDFH", NULL, e1000_regdump},
+	{E1000_RDFT, "RDFT", NULL, e1000_regdump},
+	{E1000_RDFHS, "RDFHS", NULL, e1000_regdump},
+	{E1000_RDFTS, "RDFTS", NULL, e1000_regdump},
+	{E1000_RDFPC, "RDFPC", NULL, e1000_regdump},
+
+	/* TX Registers */
+	{E1000_TCTL, "TCTL", NULL, e1000_regdump},
+	{E1000_TDBAL, "TDBAL", NULL, e1000_regdump},
+	{E1000_TDBAH, "TDBAH", NULL, e1000_regdump},
+	{E1000_TDLEN, "TDLEN", NULL, e1000_regdump},
+	{E1000_TDH, "TDH", NULL, e1000_regdump},
+	{E1000_TDT, "TDT", NULL, e1000_regdump},
+	{E1000_TIDV, "TIDV", NULL, e1000_regdump},
+	{E1000_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, e1000_regdump_n},
+	{E1000_TADV, "TADV", NULL, e1000_regdump},
+	{E1000_TARC(0), "TARC", get_regofs_TARC, e1000_regdump_n},
+	{E1000_TDFH, "TDFH", NULL, e1000_regdump},
+	{E1000_TDFT, "TDFT", NULL, e1000_regdump},
+	{E1000_TDFHS, "TDFHS", NULL, e1000_regdump},
+	{E1000_TDFTS, "TDFTS", NULL, e1000_regdump},
+	{E1000_TDFPC, "TDFPC", NULL, e1000_regdump},
+
+	/* List Terminator */
+	{}
+};
+
+/*
+ * e1000e_dump - Print registers, tx-ring and rx-ring
+ */
+static void e1000e_dump(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_reg_info *reginfo;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct e1000_buffer *buffer_info;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	union e1000_rx_desc_packet_split *rx_desc_ps;
+	struct e1000_rx_desc *rx_desc;
+	struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+	u32 staterr;
+	int i = 0;
+
+	/* Print netdevice Info */
+	if (netdev) {
+		dev_err(&adapter->pdev->dev, "Net device Info\n");
+		printk(KERN_ERR "Device Name     state            "
+			"trans_start      last_rx\n");
+		printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+			netdev->name,
+			netdev->state,
+			netdev->trans_start,
+			netdev->last_rx);
+	}
+
+	/* Print Registers */
+	if ((dump_flag & E1000_DUMP_REGS) == 0)
+		goto tx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "Register Dump\n");
+	printk(KERN_ERR " Register Name   Value\n");
+	for (reginfo = (struct e1000_reg_info *)e1000_reg_info_tbl;
+	     reginfo->name; reginfo++) {
+		reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+					reginfo->get_regofs);
+	}
+
+	/* Print TX Ring Summary */
+tx_ring_summary:
+	if (!netdev || !netif_running(netdev))
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+		" leng ntw timestamp\n");
+	buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+	printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+		0, tx_ring->next_to_use, tx_ring->next_to_clean,
+		(u64)buffer_info->dma,
+		buffer_info->length,
+		buffer_info->next_to_watch,
+		(u64)buffer_info->time_stamp);
+
+	/* Print TX Rings */
+	if ((dump_flag & E1000_DUMP_TX_RINGS) == 0)
+		goto rx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
+	 *
+	 * Legacy Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0] (Reserved on Write Back)       |
+	 *   +--------------------------------------------------------------+
+	 * 8 | Special  |    CSS     | Status |  CMD    |  CSO   |  Length  |
+	 *   +--------------------------------------------------------------+
+	 *   63       48 47        36 35    32 31     24 23    16 15        0
+	 *
+	 * Extended Context Descriptor (DTYP=0x0) for TSO or checksum offload
+	 *   63      48 47    40 39       32 31             16 15    8 7      0
+	 *   +----------------------------------------------------------------+
+	 * 0 |  TUCSE  | TUCS0  |   TUCSS   |     IPCSE       | IPCS0 | IPCSS |
+	 *   +----------------------------------------------------------------+
+	 * 8 |   MSS   | HDRLEN | RSV | STA | TUCMD | DTYP |      PAYLEN      |
+	 *   +----------------------------------------------------------------+
+	 *   63      48 47    40 39 36 35 32 31   24 23  20 19                0
+	 *
+	 * Extended Data Descriptor (DTYP=0x1)
+	 *   +----------------------------------------------------------------+
+	 * 0 |                     Buffer Address [63:0]                      |
+	 *   +----------------------------------------------------------------+
+	 * 8 | VLAN tag |  POPTS  | Rsvd | Status | Command | DTYP |  DTALEN  |
+	 *   +----------------------------------------------------------------+
+	 *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
+	 */
+	printk(KERN_ERR "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
+		" [bi->dma       ] leng  ntw timestamp        bi->skb "
+		"<-- Legacy format\n");
+	printk(KERN_ERR "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
+		" [bi->dma       ] leng  ntw timestamp        bi->skb "
+		"<-- Ext Context format\n");
+	printk(KERN_ERR "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
+		" [bi->dma       ] leng  ntw timestamp        bi->skb "
+		"<-- Ext Data format\n");
+	for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+		tx_desc = E1000_TX_DESC(*tx_ring, i);
+		buffer_info = &tx_ring->buffer_info[i];
+		u0 = (struct my_u0 *)tx_desc;
+		printk(KERN_ERR "T%c[0x%03X]    %016llX %016llX %016llX "
+			"%04X  %3X %016llX %p",
+		       (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
+			((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+		       le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+		       (u64)buffer_info->dma, buffer_info->length,
+		       buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+		       buffer_info->skb);
+		if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
+			printk(KERN_CONT " NTC/U\n");
+		else if (i == tx_ring->next_to_use)
+			printk(KERN_CONT " NTU\n");
+		else if (i == tx_ring->next_to_clean)
+			printk(KERN_CONT " NTC\n");
+		else
+			printk(KERN_CONT "\n");
+
+		if ((dump_flag & E1000_DUMP_BUFFERS) && buffer_info->dma != 0)
+			print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS,
+					16, 1, phys_to_virt(buffer_info->dma),
+					buffer_info->length, true);
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC]\n");
+	printk(KERN_ERR " %5d %5X %5X\n", 0,
+		rx_ring->next_to_use, rx_ring->next_to_clean);
+
+	/* Print RX Rings */
+	if ((dump_flag & E1000_DUMP_RX_RINGS) == 0)
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+	switch (adapter->rx_ps_pages) {
+	case 1:
+	case 2:
+	case 3:
+		/* [Extended] Packet Split Receive Descriptor Format
+		 *
+		 *    +-----------------------------------------------------+
+		 *  0 |                Buffer Address 0 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 *  8 |                Buffer Address 1 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 * 16 |                Buffer Address 2 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 * 24 |                Buffer Address 3 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 */
+		printk(KERN_ERR "R  [desc]      [buffer 0 63:0 ] "
+			"[buffer 1 63:0 ] "
+		       "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
+		       "[bi->skb] <-- Ext Pkt Split format\n");
+		/* [Extended] Receive Descriptor (Write-Back) Format
+		 *
+		 *   63       48 47    32 31     13 12    8 7    4 3        0
+		 *   +------------------------------------------------------+
+		 * 0 | Packet   | IP     |  Rsvd   | MRQ   | Rsvd | MRQ RSS |
+		 *   | Checksum | Ident  |         | Queue |      |  Type   |
+		 *   +------------------------------------------------------+
+		 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+		 *   +------------------------------------------------------+
+		 *   63       48 47    32 31            20 19               0
+		 */
+		printk(KERN_ERR "RWB[desc]      [ck ipid mrqhsh] "
+			"[vl   l0 ee  es] "
+		       "[ l3  l2  l1 hs] [reserved      ] ---------------- "
+		       "[bi->skb] <-- Ext Rx Write-Back format\n");
+		for (i = 0; i < rx_ring->count; i++) {
+			buffer_info = &rx_ring->buffer_info[i];
+			rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
+			u1 = (struct my_u1 *)rx_desc_ps;
+			staterr =
+				le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+			if (staterr & E1000_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk(KERN_ERR "RWB[0x%03X]     %016llX "
+					"%016llX %016llX %016llX "
+					"---------------- %p", i,
+					le64_to_cpu(u1->a),
+					le64_to_cpu(u1->b),
+					le64_to_cpu(u1->c),
+					le64_to_cpu(u1->d),
+					buffer_info->skb);
+			} else {
+				printk(KERN_ERR "R  [0x%03X]     %016llX "
+					"%016llX %016llX %016llX %016llX %p", i,
+					le64_to_cpu(u1->a),
+					le64_to_cpu(u1->b),
+					le64_to_cpu(u1->c),
+					le64_to_cpu(u1->d),
+					(u64)buffer_info->dma,
+					buffer_info->skb);
+
+				if (dump_flag & E1000_DUMP_BUFFERS)
+					print_hex_dump(KERN_ERR, "",
+						DUMP_PREFIX_ADDRESS, 16, 1,
+						phys_to_virt(buffer_info->dma),
+						adapter->rx_ps_bsize0, true);
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(KERN_CONT " NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(KERN_CONT " NTC\n");
+			else
+				printk(KERN_CONT "\n");
+		}
+		break;
+	default:
+	case 0:
+		/* Legacy Receive Descriptor Format
+		 *
+		 * +-----------------------------------------------------+
+		 * |                Buffer Address [63:0]                |
+		 * +-----------------------------------------------------+
+		 * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
+		 * +-----------------------------------------------------+
+		 * 63       48 47    40 39      32 31         16 15      0
+		 */
+		printk(KERN_ERR "Rl[desc]     [address 63:0  ] "
+			"[vl er S cks ln] [bi->dma       ] [bi->skb] "
+			"<-- Legacy format\n");
+		for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
+			rx_desc = E1000_RX_DESC(*rx_ring, i);
+			buffer_info = &rx_ring->buffer_info[i];
+			u0 = (struct my_u0 *)rx_desc;
+			printk(KERN_ERR "Rl[0x%03X]    %016llX %016llX "
+				"%016llX %p",
+				i, le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+				(u64)buffer_info->dma, buffer_info->skb);
+			if (i == rx_ring->next_to_use)
+				printk(KERN_CONT " NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(KERN_CONT " NTC\n");
+			else
+				printk(KERN_CONT "\n");
+
+			if (dump_flag & E1000_DUMP_BUFFERS)
+				print_hex_dump(KERN_ERR, "",
+					DUMP_PREFIX_ADDRESS,
+					16, 1, phys_to_virt(buffer_info->dma),
+					adapter->rx_buffer_len, true);
+		}
+	}
+
+exit:
+	return;
+}
+
 /**
  * e1000_desc_unused - calculate if we have unused descriptors
  **/
@@ -4247,6 +4587,7 @@ static void e1000_reset_task(struct work
 	struct e1000_adapter *adapter;
 	adapter = container_of(work, struct e1000_adapter, reset_task);
 
+	e1000e_dump(adapter);
 	e1000e_reinit_locked(adapter);
 }
 
drivers/net/e1000e/hw.h +27 -0
Index: net-next-2.6/drivers/net/e1000e/hw.h
===================================================================
@@ -92,6 +92,11 @@ enum e1e_registers {
 	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
 	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
 	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
+	E1000_RDFH     = 0x02410, /* Rx Data FIFO Head - RW */
+	E1000_RDFT     = 0x02418, /* Rx Data FIFO Tail - RW */
+	E1000_RDFHS    = 0x02420, /* Rx Data FIFO Head Saved - RW */
+	E1000_RDFTS    = 0x02428, /* Rx Data FIFO Tail Saved - RW */
+	E1000_RDFPC    = 0x02430, /* Rx Data FIFO Packet Count - RW */
 	E1000_RDBAL    = 0x02800, /* Rx Descriptor Base Address Low - RW */
 	E1000_RDBAH    = 0x02804, /* Rx Descriptor Base Address High - RW */
 	E1000_RDLEN    = 0x02808, /* Rx Descriptor Length - RW */
@@ -101,6 +106,11 @@ enum e1e_registers {
 	E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
 #define E1000_RXDCTL(_n)   (E1000_RXDCTL_BASE + (_n << 8))
 	E1000_RADV     = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+	E1000_TDFH     = 0x03410, /* Tx Data FIFO Head - RW */
+	E1000_TDFT     = 0x03418, /* Tx Data FIFO Tail - RW */
+	E1000_TDFHS    = 0x03420, /* Tx Data FIFO Head Saved - RW */
+	E1000_TDFTS    = 0x03428, /* Tx Data FIFO Tail Saved - RW */
+	E1000_TDFPC    = 0x03430, /* Tx Data FIFO Packet Count - RW */
 
 /* Convenience macros
  *
@@ -219,6 +229,23 @@ enum e1e_registers {
 	E1000_HICR      = 0x08F00, /* Host Interface Control */
 };
 
+struct e1000_reg_info {
+	u32 reg;
+	char *name;
+	u32 (*get_regofs)(int);
+	void (*dump_reg)(struct e1000_hw *, u32, char *, u32 (*)(int));
+};
+
+#define E1000_GET_REGOFS_FUNC(name)				\
+static inline u32 get_regofs_##name(int n)			\
+{								\
+	return E1000_##name(n);					\
+}								\
+
+E1000_GET_REGOFS_FUNC(RXDCTL)
+E1000_GET_REGOFS_FUNC(TXDCTL)
+E1000_GET_REGOFS_FUNC(TARC)
+
 #define E1000_MAX_PHY_ADDR		4
 
 /* IGP01E1000 Specific Registers */
author
#5 lore raw

Re: [PATCH v2 2/3] igb: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/igb/e1000_hw.h   |    7 +
 drivers/net/igb/e1000_regs.h |   21 +++
 drivers/net/igb/igb_main.c   |  294 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 322 insertions(+)
drivers/net/igb/igb_main.c +294 -0
Index: net-next-2.6/drivers/net/igb/igb_main.c
===================================================================
@@ -60,6 +60,14 @@ static const struct e1000_info *igb_info
 	[board_82575] = &e1000_82575_info,
 };
 
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define IGB_DUMP_REGS		(1 << 0)
+#define IGB_DUMP_TX_RINGS	(1 << 1)
+#define IGB_DUMP_RX_RINGS	(1 << 2)
+#define IGB_DUMP_BUFFERS	(1 << 3)
+
 static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER), board_82575 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_FIBER), board_82575 },
@@ -189,6 +197,291 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Eth
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+/*
+ * igb_regdump - register printout routine
+ */
+static void igb_regdump(struct e1000_hw *hw, u32 reg,
+			char *name, u32 (*get_regofs)(int))
+{
+	printk(KERN_ERR "%-15s %08x\n", name, rd32(reg));
+}
+
+/*
+ * igb_regdump_n - register printout routine
+ */
+static void igb_regdump_n(struct e1000_hw *hw, u32 reg,
+			  char *name, u32 (*get_regofs)(int))
+{
+	int n = 0;
+	char rname[16];
+
+	if (!get_regofs)
+		return;
+
+	snprintf(rname, 16, "%s%s", name, "[0-3]");
+	printk(KERN_ERR "%-15s ", rname);
+	for (n = 0; n < 4; n++)
+		printk(KERN_CONT "%08x ", rd32(get_regofs(n)));
+	printk(KERN_CONT "\n");
+}
+
+static const struct igb_reg_info igb_reg_info_tbl[] = {
+
+	/* General Registers */
+	{E1000_CTRL, "CTRL", NULL, igb_regdump},
+	{E1000_STATUS, "STATUS", NULL, igb_regdump},
+	{E1000_CTRL_EXT, "CTRL_EXT", NULL, igb_regdump},
+
+	/* Interrupt Registers */
+	{E1000_ICR, "ICR", NULL, igb_regdump},
+
+	/* RX Registers */
+	{E1000_RCTL, "RCTL", NULL, igb_regdump},
+	{E1000_RDLEN(0), "RDLEN", get_regofs_RDLEN, igb_regdump_n},
+	{E1000_RDH(0), "RDH", get_regofs_RDH, igb_regdump_n},
+	{E1000_RDT(0), "RDT", get_regofs_RDT, igb_regdump_n},
+	{E1000_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, igb_regdump_n},
+	{E1000_RDBAL(0), "RDBAL", get_regofs_RDBAL, igb_regdump_n},
+	{E1000_RDBAH(0), "RDBAH", get_regofs_RDBAH, igb_regdump_n},
+
+	/* TX Registers */
+	{E1000_TCTL, "TCTL", NULL, igb_regdump},
+	{E1000_TDBAL(0), "TDBAL", get_regofs_TDBAL, igb_regdump_n},
+	{E1000_TDBAH(0), "TDBAH", get_regofs_TDBAH, igb_regdump_n},
+	{E1000_TDLEN(0), "TDLEN", get_regofs_TDLEN, igb_regdump_n},
+	{E1000_TDH(0), "TDH", get_regofs_TDH, igb_regdump_n},
+	{E1000_TDT(0), "TDT", get_regofs_TDT, igb_regdump_n},
+	{E1000_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, igb_regdump_n},
+	{E1000_TDFH, "TDFH", NULL, igb_regdump},
+	{E1000_TDFT, "TDFT", NULL, igb_regdump},
+	{E1000_TDFHS, "TDFHS", NULL, igb_regdump},
+	{E1000_TDFPC, "TDFPC", NULL, igb_regdump},
+
+	/* List Terminator */
+	{}
+};
+
+/*
+ * igb_dump - Print registers, tx-rings and rx-rings
+ */
+static void igb_dump(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct igb_reg_info *reginfo;
+	int n = 0;
+	struct igb_ring *tx_ring;
+	union e1000_adv_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct igb_buffer *buffer_info;
+	struct igb_ring *rx_ring;
+	union e1000_adv_rx_desc *rx_desc;
+	u32 staterr;
+	int i = 0;
+
+	/* Print netdevice Info */
+	if (netdev) {
+		dev_err(&adapter->pdev->dev, "Net device Info\n");
+		printk(KERN_ERR "Device Name     state            "
+			"trans_start      last_rx\n");
+		printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+		netdev->name,
+		netdev->state,
+		netdev->trans_start,
+		netdev->last_rx);
+	}
+
+	/* Print Registers */
+	if ((dump_flag & IGB_DUMP_REGS) == 0)
+		goto tx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "Register Dump\n");
+	printk(KERN_ERR " Register Name   Value \n");
+	for (reginfo = (struct igb_reg_info *)igb_reg_info_tbl;
+	     reginfo->name; reginfo++) {
+		reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+					reginfo->get_regofs);
+	}
+
+	/* Print TX Ring Summary */
+tx_ring_summary:
+	if (!netdev || !netif_running(netdev))
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+		" leng ntw timestamp\n");
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+		printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+			   n, tx_ring->next_to_use, tx_ring->next_to_clean,
+			   (u64)buffer_info->dma,
+			   buffer_info->length,
+			   buffer_info->next_to_watch,
+			   (u64)buffer_info->time_stamp);
+	}
+
+	/* Print TX Rings */
+	if ((dump_flag & IGB_DUMP_TX_RINGS) == 0)
+		goto rx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats
+	 *
+	 * Advanced Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0]                                |
+	 *   +--------------------------------------------------------------+
+	 * 8 | PAYLEN  | PORTS  |CC|IDX | STA | DCMD  |DTYP|MAC|RSV| DTALEN |
+	 *   +--------------------------------------------------------------+
+	 *   63      46 45    40 39 38 36 35 32 31   24             15       0
+	 */
+
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "T [desc]     [address 63:0  ] "
+			"[PlPOCIStDDM Ln] [bi->dma       ] "
+			"leng  ntw timestamp        bi->skb\n");
+
+		for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+			tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
+			buffer_info = &tx_ring->buffer_info[i];
+			u0 = (struct my_u0 *)tx_desc;
+			printk(KERN_ERR "T [0x%03X]    %016llX %016llX %016llX"
+				" %04X  %3X %016llX %p", i,
+				le64_to_cpu(u0->a),
+				le64_to_cpu(u0->b),
+				(u64)buffer_info->dma,
+				buffer_info->length,
+				buffer_info->next_to_watch,
+				(u64)buffer_info->time_stamp,
+				buffer_info->skb);
+			if (i == tx_ring->next_to_use &&
+				i == tx_ring->next_to_clean)
+				printk(KERN_CONT " NTC/U\n");
+			else if (i == tx_ring->next_to_use)
+				printk(KERN_CONT " NTU\n");
+			else if (i == tx_ring->next_to_clean)
+				printk(KERN_CONT " NTC\n");
+			else
+				printk(KERN_CONT "\n");
+
+			if ((dump_flag & IGB_DUMP_BUFFERS) &&
+				buffer_info->dma != 0)
+				print_hex_dump(KERN_ERR, "",
+					DUMP_PREFIX_ADDRESS,
+					16, 1, phys_to_virt(buffer_info->dma),
+					buffer_info->length, true);
+		}
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC]\n");
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR " %5d %5X %5X\n", n,
+			   rx_ring->next_to_use, rx_ring->next_to_clean);
+	}
+
+	/* Print RX Rings */
+	if ((dump_flag & IGB_DUMP_RX_RINGS) == 0)
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+
+	/* Advanced Receive Descriptor (Read) Format
+	 *    63                                           1        0
+	 *    +-----------------------------------------------------+
+	 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+	 *    +----------------------------------------------+------+
+	 *  8 |       Header Buffer Address [63:1]           |  DD  |
+	 *    +-----------------------------------------------------+
+	 *
+	 *
+	 * Advanced Receive Descriptor (Write-Back) Format
+	 *
+	 *   63       48 47    32 31  30      21 20 17 16   4 3     0
+	 *   +------------------------------------------------------+
+	 * 0 | Packet     IP     |SPH| HDR_LEN   | RSV|Packet|  RSS |
+	 *   | Checksum   Ident  |   |           |    | Type | Type |
+	 *   +------------------------------------------------------+
+	 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+	 *   +------------------------------------------------------+
+	 *   63       48 47    32 31            20 19               0
+	 */
+
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "R  [desc]      [ PktBuf     A0] "
+			"[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+			"<-- Adv Rx Read format\n");
+		printk(KERN_ERR "RWB[desc]      [PcsmIpSHl PtRs] "
+			"[vl er S cks ln] ---------------- [bi->skb] "
+			"<-- Adv Rx Write-Back format\n");
+
+		for (i = 0; i < rx_ring->count; i++) {
+			buffer_info = &rx_ring->buffer_info[i];
+			rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+			u0 = (struct my_u0 *)rx_desc;
+			staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+			if (staterr & E1000_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk(KERN_ERR "RWB[0x%03X]     %016llX "
+					"%016llX ---------------- %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					buffer_info->skb);
+			} else {
+				printk(KERN_ERR "R  [0x%03X]     %016llX "
+					"%016llX %016llX %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					(u64)buffer_info->dma,
+					buffer_info->skb);
+
+				if (dump_flag & IGB_DUMP_BUFFERS) {
+					print_hex_dump(KERN_ERR, "",
+						DUMP_PREFIX_ADDRESS,
+						16, 1,
+						phys_to_virt(buffer_info->dma),
+						rx_ring->rx_buffer_len, true);
+					if (rx_ring->rx_buffer_len
+						< IGB_RXBUFFER_1024)
+						print_hex_dump(KERN_ERR, "",
+						  DUMP_PREFIX_ADDRESS,
+						  16, 1,
+						  phys_to_virt(
+						    buffer_info->page_dma +
+						    buffer_info->page_offset),
+						  PAGE_SIZE/2, true);
+				}
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(KERN_CONT " NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(KERN_CONT " NTC\n");
+			else
+				printk(KERN_CONT "\n");
+
+		}
+	}
+
+exit:
+	return;
+}
+
+
 /**
  * igb_read_clock - read raw cycle counter (to be used by time counter)
  */
@@ -3854,6 +4147,7 @@ static void igb_reset_task(struct work_s
 	struct igb_adapter *adapter;
 	adapter = container_of(work, struct igb_adapter, reset_task);
 
+	igb_dump(adapter);
 	igb_reinit_locked(adapter);
 }
 
drivers/net/igb/e1000_regs.h +21 -0
Index: net-next-2.6/drivers/net/igb/e1000_regs.h
===================================================================
@@ -322,4 +322,25 @@
 
 /* DMA Coalescing registers */
 #define E1000_PCIEMISC          0x05BB8 /* PCIE misc config register */
+
+
+#define IGB_GET_REGOFS_FUNC(name)				\
+static inline u32 get_regofs_##name(int n)			\
+{								\
+	return E1000_##name(n);					\
+}								\
+
+IGB_GET_REGOFS_FUNC(RDLEN)
+IGB_GET_REGOFS_FUNC(RDH)
+IGB_GET_REGOFS_FUNC(RDT)
+IGB_GET_REGOFS_FUNC(RXDCTL)
+IGB_GET_REGOFS_FUNC(RDBAL)
+IGB_GET_REGOFS_FUNC(RDBAH)
+IGB_GET_REGOFS_FUNC(TDBAL)
+IGB_GET_REGOFS_FUNC(TDBAH)
+IGB_GET_REGOFS_FUNC(TDLEN)
+IGB_GET_REGOFS_FUNC(TDH)
+IGB_GET_REGOFS_FUNC(TDT)
+IGB_GET_REGOFS_FUNC(TXDCTL)
+
 #endif
drivers/net/igb/e1000_hw.h +7 -0
Index: net-next-2.6/drivers/net/igb/e1000_hw.h
===================================================================
@@ -508,6 +508,13 @@ struct e1000_hw {
 	u8  revision_id;
 };
 
+struct igb_reg_info {
+	u32 reg;
+	char *name;
+	u32 (*get_regofs)(int);
+	void (*dump_reg)(struct e1000_hw *, u32, char *, u32 (*)(int));
+};
+
 #ifdef DEBUG
 extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
 #define hw_dbg(format, arg...) \
author
#7 lore raw

Re: [PATCH v2 3/3] ixgbe: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/ixgbe/ixgbe_main.c |  294 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_type.h |   29 ++++
 2 files changed, 323 insertions(+)
drivers/net/ixgbe/ixgbe_main.c +294 -0
Index: net-next-2.6/drivers/net/ixgbe/ixgbe_main.c
===================================================================
@@ -60,6 +60,15 @@ static const struct ixgbe_info *ixgbe_in
 	[board_82599] = &ixgbe_82599_info,
 };
 
+
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define IXGBE_DUMP_REGS		(1 << 0)
+#define IXGBE_DUMP_TX_RINGS	(1 << 1)
+#define IXGBE_DUMP_RX_RINGS	(1 << 2)
+#define IXGBE_DUMP_BUFFERS	(1 << 3)
+
 /* ixgbe_pci_tbl - PCI Device ID Table
  *
  * Wildcard entries (PCI_ANY_ID) should come last
@@ -174,6 +183,290 @@ static inline void ixgbe_disable_sriov(s
 	adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
 }
 
+/*
+ * ixgbe_regdump - register printout routine
+ */
+static void ixgbe_regdump(struct ixgbe_hw *hw, u32 reg,
+			  char *name, u32 (*get_regofs)(int))
+{
+	printk(KERN_ERR "%-15s %08x\n", name, IXGBE_READ_REG(hw, reg));
+}
+
+/*
+ * ixgbe_regdump_n - register printout routine
+ */
+static void ixgbe_regdump_n(struct ixgbe_hw *hw, u32 reg,
+			    char *name, u32 (*get_regofs)(int))
+{
+	int i = 0, j = 0;
+	char rname[16];
+
+	if (!get_regofs)
+		return;
+
+	for (i = 0; i < 8; i++) {
+		snprintf(rname, 16, "%s[%d-%d]", name, i*8, i*8+7);
+		printk(KERN_ERR "%-15s ", rname);
+		for (j = 0; j < 8; j++)
+			printk(KERN_CONT "%08x ",
+				IXGBE_READ_REG(hw, get_regofs(i*8+j)));
+		printk(KERN_CONT "\n");
+	}
+}
+
+static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+
+	/* General Registers */
+	{IXGBE_CTRL, "CTRL", NULL, ixgbe_regdump},
+	{IXGBE_STATUS, "STATUS", NULL, ixgbe_regdump},
+	{IXGBE_CTRL_EXT, "CTRL_EXT", NULL, ixgbe_regdump},
+
+	/* Interrupt Registers */
+	{IXGBE_EICR, "EICR", NULL, ixgbe_regdump},
+
+	/* RX Registers */
+	{IXGBE_SRRCTL(0), "SRRCTL", get_regofs_SRRCTL, ixgbe_regdump_n},
+	{IXGBE_DCA_RXCTRL(0), "DRXCTL", get_regofs_DCA_RXCTRL, ixgbe_regdump_n},
+	{IXGBE_RDLEN(0), "RDLEN", get_regofs_RDLEN, ixgbe_regdump_n},
+	{IXGBE_RDH(0), "RDH", get_regofs_RDH, ixgbe_regdump_n},
+	{IXGBE_RDT(0), "RDT", get_regofs_RDT, ixgbe_regdump_n},
+	{IXGBE_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, ixgbe_regdump_n},
+	{IXGBE_RDBAL(0), "RDBAL", get_regofs_RDBAL, ixgbe_regdump_n},
+	{IXGBE_RDBAH(0), "RDBAH", get_regofs_RDBAH, ixgbe_regdump_n},
+
+	/* TX Registers */
+	{IXGBE_TDBAL(0), "TDBAL", get_regofs_TDBAL, ixgbe_regdump_n},
+	{IXGBE_TDBAH(0), "TDBAH", get_regofs_TDBAH, ixgbe_regdump_n},
+	{IXGBE_TDLEN(0), "TDLEN", get_regofs_TDLEN, ixgbe_regdump_n},
+	{IXGBE_TDH(0), "TDH", get_regofs_TDH, ixgbe_regdump_n},
+	{IXGBE_TDT(0), "TDT", get_regofs_TDT, ixgbe_regdump_n},
+	{IXGBE_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, ixgbe_regdump_n},
+
+	/* List Terminator */
+	{}
+};
+
+/*
+ * ixgbe_dump - Print registers, tx-rings and rx-rings
+ */
+static void ixgbe_dump(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct ixgbe_reg_info *reginfo;
+	int n = 0;
+	struct ixgbe_ring *tx_ring;
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	union ixgbe_adv_tx_desc *tx_desc;
+	struct my_u0 { u64 a; u64 b; } *u0;
+	struct ixgbe_ring *rx_ring;
+	union ixgbe_adv_rx_desc *rx_desc;
+	struct ixgbe_rx_buffer *rx_buffer_info;
+	u32 staterr;
+	int i = 0;
+
+	/* Print netdevice Info */
+	dev_err(&adapter->pdev->dev, "Net device Info\n");
+	if (netdev) {
+		printk(KERN_ERR "Device Name     state            "
+			"trans_start      last_rx\n");
+		printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+		netdev->name,
+		netdev->state,
+		netdev->trans_start,
+		netdev->last_rx);
+	}
+
+	/* Print Registers */
+	if ((dump_flag & IXGBE_DUMP_REGS) == 0)
+		goto tx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "Register Dump\n");
+	printk(KERN_ERR " Register Name   Value \n");
+	for (reginfo = (struct ixgbe_reg_info *)ixgbe_reg_info_tbl;
+	     reginfo->name; reginfo++) {
+		reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+					reginfo->get_regofs);
+	}
+
+	/* Print TX Ring Summary */
+tx_ring_summary:
+	if (!netdev || !netif_running(netdev))
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ] "
+		"leng ntw timestamp\n");
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		tx_buffer_info =
+			&tx_ring->tx_buffer_info[tx_ring->next_to_clean];
+		printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+			   n, tx_ring->next_to_use, tx_ring->next_to_clean,
+			   (u64)tx_buffer_info->dma,
+			   tx_buffer_info->length,
+			   tx_buffer_info->next_to_watch,
+			   (u64)tx_buffer_info->time_stamp);
+	}
+
+	/* Print TX Rings */
+	if ((dump_flag & IXGBE_DUMP_TX_RINGS) == 0)
+		goto rx_ring_summary;
+
+	dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+	/* Transmit Descriptor Formats
+	 *
+	 * Advanced Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0]                                |
+	 *   +--------------------------------------------------------------+
+	 * 8 |  PAYLEN  | PORTS  | IDX | STA | DCMD  |DTYP |  RSV |  DTALEN |
+	 *   +--------------------------------------------------------------+
+	 *   63       46 45    40 39 36 35 32 31   24 23 20 19              0
+	 */
+
+	for (n = 0; n < adapter->num_tx_queues; n++) {
+		tx_ring = &adapter->tx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "T [desc]     [address 63:0  ] "
+			"[PlPOIdStDDt Ln] [bi->dma       ] "
+			"leng  ntw timestamp        bi->skb\n");
+
+		for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+			tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+			tx_buffer_info = &tx_ring->tx_buffer_info[i];
+			u0 = (struct my_u0 *)tx_desc;
+			printk(KERN_ERR "T [0x%03X]    %016llX %016llX %016llX"
+				" %04X  %3X %016llX %p", i,
+				le64_to_cpu(u0->a),
+				le64_to_cpu(u0->b),
+				(u64)tx_buffer_info->dma,
+				tx_buffer_info->length,
+				tx_buffer_info->next_to_watch,
+				(u64)tx_buffer_info->time_stamp,
+				tx_buffer_info->skb);
+			if (i == tx_ring->next_to_use &&
+				i == tx_ring->next_to_clean)
+				printk(KERN_CONT " NTC/U\n");
+			else if (i == tx_ring->next_to_use)
+				printk(KERN_CONT " NTU\n");
+			else if (i == tx_ring->next_to_clean)
+				printk(KERN_CONT " NTC\n");
+			else
+				printk(KERN_CONT "\n");
+
+			if ((dump_flag & IXGBE_DUMP_BUFFERS) &&
+				tx_buffer_info->dma != 0)
+				print_hex_dump(KERN_ERR, "",
+					DUMP_PREFIX_ADDRESS, 16, 1,
+					phys_to_virt(tx_buffer_info->dma),
+					tx_buffer_info->length, true);
+		}
+	}
+
+	/* Print RX Rings Summary */
+rx_ring_summary:
+	dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+	printk(KERN_ERR "Queue [NTU] [NTC]\n");
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR "%5d %5X %5X\n", n,
+			   rx_ring->next_to_use, rx_ring->next_to_clean);
+	}
+
+	/* Print RX Rings */
+	if ((dump_flag & IXGBE_DUMP_RX_RINGS) == 0)
+		goto exit;
+
+	dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+
+	/* Advanced Receive Descriptor (Read) Format
+	 *    63                                           1        0
+	 *    +-----------------------------------------------------+
+	 *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+	 *    +----------------------------------------------+------+
+	 *  8 |       Header Buffer Address [63:1]           |  DD  |
+	 *    +-----------------------------------------------------+
+	 *
+	 *
+	 * Advanced Receive Descriptor (Write-Back) Format
+	 *
+	 *   63       48 47    32 31  30      21 20 16 15   4 3     0
+	 *   +------------------------------------------------------+
+	 * 0 | Packet     IP     |SPH| HDR_LEN   | RSV|Packet|  RSS |
+	 *   | Checksum   Ident  |   |           |    | Type | Type |
+	 *   +------------------------------------------------------+
+	 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+	 *   +------------------------------------------------------+
+	 *   63       48 47    32 31            20 19               0
+	 */
+	for (n = 0; n < adapter->num_rx_queues; n++) {
+		rx_ring = &adapter->rx_ring[n];
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+		printk(KERN_ERR "------------------------------------\n");
+		printk(KERN_ERR "R  [desc]      [ PktBuf     A0] "
+			"[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+			"<-- Adv Rx Read format\n");
+		printk(KERN_ERR "RWB[desc]      [PcsmIpSHl PtRs] "
+			"[vl er S cks ln] ---------------- [bi->skb] "
+			"<-- Adv Rx Write-Back format\n");
+
+		for (i = 0; i < rx_ring->count; i++) {
+			rx_buffer_info = &rx_ring->rx_buffer_info[i];
+			rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+			u0 = (struct my_u0 *)rx_desc;
+			staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+			if (staterr & IXGBE_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk(KERN_ERR "RWB[0x%03X]     %016llX "
+					"%016llX ---------------- %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					rx_buffer_info->skb);
+			} else {
+				printk(KERN_ERR "R  [0x%03X]     %016llX "
+					"%016llX %016llX %p", i,
+					le64_to_cpu(u0->a),
+					le64_to_cpu(u0->b),
+					(u64)rx_buffer_info->dma,
+					rx_buffer_info->skb);
+
+				if (dump_flag & IXGBE_DUMP_BUFFERS) {
+					print_hex_dump(KERN_ERR, "",
+					   DUMP_PREFIX_ADDRESS, 16, 1,
+					   phys_to_virt(rx_buffer_info->dma),
+					   rx_ring->rx_buf_len, true);
+
+					if (rx_ring->rx_buf_len
+						< IXGBE_RXBUFFER_2048)
+						print_hex_dump(KERN_ERR, "",
+						  DUMP_PREFIX_ADDRESS, 16, 1,
+						  phys_to_virt(
+						    rx_buffer_info->page_dma +
+						    rx_buffer_info->page_offset
+						  ),
+						  PAGE_SIZE/2, true);
+				}
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(KERN_CONT " NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(KERN_CONT " NTC\n");
+			else
+				printk(KERN_CONT "\n");
+
+		}
+	}
+
+exit:
+	return;
+}
+
 static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
 {
 	u32 ctrl_ext;
@@ -3306,6 +3599,7 @@ static void ixgbe_reset_task(struct work
 
 	adapter->tx_timeout_count++;
 
+	ixgbe_dump(adapter);
 	ixgbe_reinit_locked(adapter);
 }
 
drivers/net/ixgbe/ixgbe_type.h +29 -0
Index: net-next-2.6/drivers/net/ixgbe/ixgbe_type.h
===================================================================
@@ -2568,4 +2568,33 @@ struct ixgbe_info {
 #define IXGBE_ERR_EEPROM_VERSION                -24
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
+
+struct ixgbe_reg_info {
+	u32 reg;
+	char *name;
+	u32 (*get_regofs)(int);
+	void (*dump_reg)(struct ixgbe_hw *, u32, char *, u32 (*)(int));
+};
+
+#define IXGBE_GET_REGOFS_FUNC(name)				\
+static inline u32 get_regofs_##name(int n)			\
+{								\
+	return IXGBE_##name(n);					\
+}								\
+
+IXGBE_GET_REGOFS_FUNC(SRRCTL)
+IXGBE_GET_REGOFS_FUNC(DCA_RXCTRL)
+IXGBE_GET_REGOFS_FUNC(RDLEN)
+IXGBE_GET_REGOFS_FUNC(RDH)
+IXGBE_GET_REGOFS_FUNC(RDT)
+IXGBE_GET_REGOFS_FUNC(RXDCTL)
+IXGBE_GET_REGOFS_FUNC(RDBAL)
+IXGBE_GET_REGOFS_FUNC(RDBAH)
+IXGBE_GET_REGOFS_FUNC(TDBAL)
+IXGBE_GET_REGOFS_FUNC(TDBAH)
+IXGBE_GET_REGOFS_FUNC(TDLEN)
+IXGBE_GET_REGOFS_FUNC(TDH)
+IXGBE_GET_REGOFS_FUNC(TDT)
+IXGBE_GET_REGOFS_FUNC(TXDCTL)
+
 #endif /* _IXGBE_TYPE_H_ */
#10 lore raw

Re: [PATCH v2 0/3] e1000e, igb, ixgbe: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi
Quoted 8 lines · Taku Izumi

This patchset is the update version of "register etc. printout code" patch. (sorry for late reply)
The old one is http://marc.info/?l=linux-netdev&m=126286127208276&w=2

v1 -> v2:
- replaced hexdump() with print_hex_dump()
- changed the register printout inplementation (for-switch-case -> data-driven-table)

Quoted 5 lines

However the default value of "dump_flag" is not changed (still 1). The reason I didn't change is
- I think HW index (TDH,TDT..) and SW index (NTC,NTU) are at least necessary
- the amount of default output is not so large (see bellow)
- the adapter resetting problem doesn't happen frequently

Taku, thanks for these, we are talking the patches over and reviewing them. While I agree with the idea of these patches is good, I still don't agree with the default being enabled. Usually if someone is getting tx hangs they are repeatable and we can work with them to get the debug turned on. I DO think it is useful to have the feature available by default but NOT enabled.

If we wanted to enable something by default it might be useful to print something that actually draws some conclusions from known failure modes, like if TDH!=TDT after some amount of time. I think one or two lines maximum for default printing.

If you're working in this area I had an idea. I had wanted to be able to print the large amount of ring information (especially in the ixgbe case with many rings) to the ftrace buffers in order to not overrun the syslog daemon. Not sure if you're interested in more new features, it certainly is separate but related to this patch.

------------------------------------------------------------------------------
Throughout its 18-year history, RSA Conference consistently attracts the world's best and brightest in the field, creating opportunities for Conference attendees to learn about information security's most important issues through interactions with peers, luminaries and emerging and established companies.
http://p.sf.net/sfu/rsaconf-dev2dev
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

author
#11 lore raw

Hi Jesse,

Quoted 12 lines · Jesse

Taku, thanks for these, we are talking the patches over and reviewing them. While I agree with the idea of these patches is good, I still don't agree with the default being enabled. Usually if someone is getting tx hangs they are repeatable and we can work with them to get the debug turned on. I DO think it is useful to have the feature available by default but NOT enabled.

If we wanted to enable something by default it might be useful to print something that actually draws some conclusions from known failure modes, like if TDH!=TDT after some amount of time. I think one or two lines maximum for default printing.

Quoted 5 lines

If you're working in this area I had an idea. I had wanted to be able to print the large amount of ring information (especially in the ixgbe case with many rings) to the ftrace buffers in order to not overrun the syslog daemon. Not sure if you're interested in more new features, it certainly is separate but related to this patch.

I thought similar things, that is, all information should be dumped to the private ring buffer to avoid filling syslog up with driver messages. But I didn't have any good idea to extract information from ring buffers, so as the first step, I decided to printout it by using printk(). Is there the easy way to extract it from ring buffers?

Best regards,
Taku Izumi

#12 lore raw
Quoted 19 lines · Taku Izumi
Quoted 12 lines · Jesse

Taku, thanks for these, we are talking the patches over and reviewing them. While I agree with the idea of these patches is good, I still don't agree with the default being enabled. Usually if someone is getting tx hangs they are repeatable and we can work with them to get the debug turned on. I DO think it is useful to have the feature available by default but NOT enabled.

If we wanted to enable something by default it might be useful to print something that actually draws some conclusions from known failure modes, like if TDH!=TDT after some amount of time. I think one or two lines maximum for default printing.

Quoted 5 lines

If you're working in this area I had an idea. I had wanted to be able to print the large amount of ring information (especially in the ixgbe case with many rings) to the ftrace buffers in order to not overrun the syslog daemon. Not sure if you're interested in more new features, it certainly is separate but related to this patch.

Quoted 5 lines

I thought similar things, that is, all information should be dumped to the private ring buffer to avoid filling syslog up with driver messages. But I didn't have any good idea to extract information from ring buffers, so as the first step, I decided to printout it by using printk(). Is there the easy way to extract it from ring buffers?

First, I need to apologize for the delay, it's my fault.

I'm not sure about an easy way to use the private ring buffers yet, I know you can use the ftrace buffers directly, and then when someone read /sys/kernel/debug/tracing/trace they would get all the output.

Lets not do ftrace yet.

I have a counter proposal to make, here is a (incomplete) patch that we use all the time to debug tx hangs. This example is for e1000e. We are trying to avoid changes with other users' copyright to some of the files in our drivers so that we can ship them under multiple license. We would much prefer something like this to be used, can you review?

I also have another patch I made for ixgb to show the use of sysfs and a module parameter, I'll reply again with that next.

---
From: Jesse Brandeburg <[email protected]>

e1000e: dump code for descriptor rings

This is debug code for descriptor ring dumps, only enable if you really want a lot of stuff in your syslog/dmesg when you get NETDEV WATCHDOG or tx hang reports from the driver.

<not implemented> Code can be enabled at boot time with a module parameter or via sysfs at runtime.

---

 drivers/net/e1000e/ethtool.c |    4 +
 drivers/net/e1000e/hw.h      |   10 +
 drivers/net/e1000e/netdev.c  |  298 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 311 insertions(+), 1 deletions(-)
drivers/net/e1000e/ethtool.c +4 -0
index 0aa50c2..bbcf5c7 100644
@@ -434,6 +434,8 @@ static int e1000_get_regs_len(struct net_device *netdev)
 	return E1000_REGS_LEN * sizeof(u32);
 }
 
+extern void e1000e_dump(struct e1000_adapter *);
+
 static void e1000_get_regs(struct net_device *netdev,
 			   struct ethtool_regs *regs, void *p)
 {
@@ -443,6 +445,8 @@ static void e1000_get_regs(struct net_device *netdev,
 	u16 phy_data;
 	u8 revision_id;
 
+	e1000e_dump(adapter);
+
 	memset(p, 0, E1000_REGS_LEN * sizeof(u32));
 
 	pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);
drivers/net/e1000e/hw.h +10 -0
index eccf29b..d23501d 100644
@@ -92,6 +92,11 @@ enum e1e_registers {
 	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
 	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
 	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
+	E1000_RDFH     = 0x02410, /* Rx Data FIFO Head - RW */
+	E1000_RDFT     = 0x02418, /* Rx Data FIFO Tail - RW */
+	E1000_RDFHS    = 0x02420, /* Rx Data FIFO Head Saved - RW */
+	E1000_RDFTS    = 0x02428, /* Rx Data FIFO Tail Saved - RW */
+	E1000_RDFPC    = 0x02430, /* Rx Data FIFO Packet Count - RW */
 	E1000_RDBAL    = 0x02800, /* Rx Descriptor Base Address Low - RW */
 	E1000_RDBAH    = 0x02804, /* Rx Descriptor Base Address High - RW */
 	E1000_RDLEN    = 0x02808, /* Rx Descriptor Length - RW */
@@ -112,6 +117,11 @@ enum e1e_registers {
  */
 #define E1000_RDBAL_REG(_n)   (E1000_RDBAL + (_n << 8))
 	E1000_KABGTXD  = 0x03004, /* AFE Band Gap Transmit Ref Data */
+	E1000_TDFH     = 0x03410, /* TX Data FIFO Head - RW */
+	E1000_TDFT     = 0x03418, /* TX Data FIFO Tail - RW */
+	E1000_TDFHS    = 0x03420, /* TX Data FIFO Head Saved - RW */
+	E1000_TDFTS    = 0x03428, /* Tx Data FIFO Tail Saved - RW */
+	E1000_TDFPC    = 0x03430, /* TX Data FIFO Packet Count - RW */
 	E1000_TDBAL    = 0x03800, /* Tx Descriptor Base Address Low - RW */
 	E1000_TDBAH    = 0x03804, /* Tx Descriptor Base Address High - RW */
 	E1000_TDLEN    = 0x03808, /* Tx Descriptor Length - RW */
drivers/net/e1000e/netdev.c +297 -1

316 lines not on this page · raw message

#13 lore raw
Quoted 2 lines · Jesse

I also have another patch I made for ixgb to show the use of sysfs and a module parameter, I'll reply again with that next.

---

ixgb: debug dump patch

this patch helps us debug tx hangs and other issues by dumping the transmit and receive descriptor rings in the host memory upon a tx hang event. debug code is enabled with echo 1 > /sys/module/ixgb/parameters/debug_dump

and on the next tx hang you'll get a *massive* amount of data dumped into the kernel log. yeah debugfs would be perfect for this.

---

 drivers/net/ixgb/ixgb_ethtool.c |    6 ++
 drivers/net/ixgb/ixgb_hw.h      |   15 ++++
 drivers/net/ixgb/ixgb_main.c    |  140 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 159 insertions(+), 2 deletions(-)
drivers/net/ixgb/ixgb_ethtool.c +6 -0
index 288ee1d..607a71f 100644
@@ -258,6 +258,9 @@ ixgb_get_regs_len(struct net_device *netdev)
 	return IXGB_REG_DUMP_LEN;
 }
 
+extern void ixgb_dump(struct ixgb_adapter *);
+extern int debug_dump;
+
 static void
 ixgb_get_regs(struct net_device *netdev,
 		   struct ethtool_regs *regs, void *p)
@@ -268,6 +271,9 @@ ixgb_get_regs(struct net_device *netdev,
 	u32 *reg_start = reg;
 	u8 i;
 
+	if (debug_dump)
+		ixgb_dump(adapter);
+
 	/* the 1 (one) below indicates an attempt at versioning, if the
 	 * interface in ethtool or the driver changes, this 1 should be
 	 * incremented */
drivers/net/ixgb/ixgb_hw.h +15 -0
index 831fe0c..ac0f895 100644
@@ -243,6 +243,21 @@ typedef enum {
 #define IXGB_XOFFTXC 0x021D0	/* XOFF Transmitted Count */
 #define IXGB_RJC     0x021D8	/* Receive Jabber Count */
 
+/* Diagnostic */
+#define IXGB_RDFH    0x04000    /* RX Data FIFO Head - RO */
+#define IXGB_RDFT    0x04008    /* RX Data FIFO Tail - RO */
+#define IXGB_RDFTS   0x04018    /* RX Data FIFO Tail Saved - RO */
+#define IXGB_RDFPC   0x04020    /* RX Data Packet Count - RO */
+#define IXGB_TDFH    0x04028    /* TX Data FIFO Head - RO */
+#define IXGB_TDFT    0x04030    /* TX Data FIFO Tail - RO */
+#define IXGB_TDFTS   0x04040    /* TX Data FIFO Tail Saved - RO */
+#define IXGB_TDFPC   0x04048    /* TX Data FIFO Packet Count - RO */
+#define IXGB_TREG    0x04050    /* Test Register - RW */
+#define IXGB_RPR     0x04058    /* RX Page Register - RW */
+#define IXGB_TPR     0x04060    /* TX Page Register - RW */
+#define IXGB_RPDBM   0x05000    /* RX Packet or Descriptor Buffer Memory - RO */
+#define IXGB_TPDBM   0x06000    /* TX Packet or Descriptor Buffer Memory - RO */
+
 /* CTRL0 Bit Masks */
 #define IXGB_CTRL0_LRST     0x00000008
 #define IXGB_CTRL0_JFE      0x00000010
drivers/net/ixgb/ixgb_main.c +138 -2

170 lines not on this page · raw message

author
#14 lore raw
In reply to Brandeburg, Jesse

Hi Jesse,

Quoted 5 lines

I have a counter proposal to make, here is a (incomplete) patch that we use all the time to debug tx hangs. This example is for e1000e. We are trying to avoid changes with other users' copyright to some of the files in our drivers so that we can ship them under multiple license. We would much prefer something like this to be used, can you review?

I haven't understood yet about the reason we have to avoid changing some files. Are there any files (header files?) we can't modify?

Best regards,
Taku Izumi

#15 lore raw
Quoted 8 lines · Taku Izumi

Hi Jesse,

Quoted 5 lines

I have a counter proposal to make, here is a (incomplete) patch that we use all the time to debug tx hangs. This example is for e1000e. We are trying to avoid changes with other users' copyright to some of the files in our drivers so that we can ship them under multiple license. We would much prefer something like this to be used, can you review?

Quoted 6 lines

I haven't understood yet about the reason we have to avoid changing some files. Are there any files (header files?) we can't modify?

Best regards,
Taku Izumi

To answer your question, no there are no files you can't submit patches to. We do have some common files which are used/shared amongst all of our drivers which are used for initializing and/or bring up the hardware, so when a patch is submitted to our drivers which changes our "shared code" our first question is "Is this change necessary for all of our drivers?" and if the answer is no, then we take a look at what changes can be made in the code which is not shared among our other drivers.

Signature · 2 lines
Cheers,
Jeff
#3 lore raw

Re: [PATCH v2 1/3] e1000e: add registers etc. printout code just before resetting adapters

In reply to Taku Izumi

- are you sure you want KERN_ERR rather than KERN_DEBUG ?

2010/1/21 Taku Izumi <[email protected]>:

Quoted 436 lines

This patch adds registers (,tx/rx rings' status and so on) printout code just before resetting adapters. This will be helpful for detecting the root cause of adapters reset.

The default output is netdevice status (transstart, last_rx), registers, and tx/rx rings' simple information. TX/RX descriptors information and buffer_info  can be output by changing the dump_flag module option, but, of course, the amount of output becomes quite large.

---
 drivers/net/e1000e/hw.h     |   27 +++
 drivers/net/e1000e/netdev.c |  341 ++++++++++++++++++++++++++++++++++++++++++++

 2 files changed, 368 insertions(+)

Index: net-next-2.6/drivers/net/e1000e/netdev.c
===================================================================

drivers/net/e1000e/netdev.c +341 -0
@@ -52,6 +52,14 @@
  char e1000e_driver_name[] = "e1000e";
  const char e1000e_driver_version[] = DRV_VERSION;
 
+static unsigned int dump_flag = 1;
+module_param(dump_flag, uint, 0644);
+MODULE_PARM_DESC(dump_flag, "Dump Flag");
+#define E1000_DUMP_REGS                (1 << 0)
+#define E1000_DUMP_TX_RINGS    (1 << 1)
+#define E1000_DUMP_RX_RINGS    (1 << 2)
+#define E1000_DUMP_BUFFERS     (1 << 3)
+
  static const struct e1000_info *e1000_info_tbl[] = {
        [board_82571]           = &e1000_82571_info,
        [board_82572]           = &e1000_82572_info,
@@ -65,6 +73,338 @@ static const struct e1000_info *e1000_in
        [board_pchlan]          = &e1000_pch_info,
  };
 
+/*
+ * e1000_regdump - register printout routine
+ */
+static void e1000_regdump(struct e1000_hw *hw, u32 reg,
+                         char *name, u32 (*get_regofs)(int))
+{
+       printk(KERN_ERR "%-15s %08x\n", name, __er32(hw, reg));
+}
+
+/*
+ * e1000_regdump_n - register printout routine
+ */
+static void e1000_regdump_n(struct e1000_hw *hw, u32 reg,
+                           char *name, u32 (*get_regofs)(int))
+{
+       int n = 0;
+       char rname[16];
+
+       if (!get_regofs)
+               return;
+
+       snprintf(rname, 16, "%s%s", name, "[0-1]");
+       printk(KERN_ERR "%-15s ", rname);
+       for (n = 0; n < 2; n++)
+               printk("%08x ", __er32(hw, get_regofs(n)));
+       printk("\n");
+}
+
+static const struct e1000_reg_info e1000_reg_info_tbl[] = {
+
+       /* General Registers */
+       {E1000_CTRL, "CTRL", NULL, e1000_regdump},
+       {E1000_STATUS, "STATUS", NULL, e1000_regdump},
+       {E1000_CTRL_EXT, "CTRL_EXT", NULL, e1000_regdump},
+
+       /* Interrupt Registers */
+       {E1000_ICR, "ICR", NULL, e1000_regdump},
+
+       /* RX Registers */
+       {E1000_RCTL, "RCTL", NULL, e1000_regdump},
+       {E1000_RDLEN, "RDLEN", NULL, e1000_regdump},
+       {E1000_RDH, "RDH", NULL, e1000_regdump},
+       {E1000_RDT, "RDT", NULL, e1000_regdump},
+       {E1000_RDTR, "RDTR", NULL, e1000_regdump},
+       {E1000_RXDCTL(0), "RXDCTL", get_regofs_RXDCTL, e1000_regdump_n},
+       {E1000_ERT, "ERT", NULL, e1000_regdump},
+       {E1000_RDBAL, "RDBAL", NULL, e1000_regdump},
+       {E1000_RDBAH, "RDBAH", NULL, e1000_regdump},
+       {E1000_RDFH, "RDFH", NULL, e1000_regdump},
+       {E1000_RDFT, "RDFT", NULL, e1000_regdump},
+       {E1000_RDFHS, "RDFHS", NULL, e1000_regdump},
+       {E1000_RDFTS, "RDFTS", NULL, e1000_regdump},
+       {E1000_RDFPC, "RDFPC", NULL, e1000_regdump},
+
+       /* TX Registers */
+       {E1000_TCTL, "TCTL", NULL, e1000_regdump},
+       {E1000_TDBAL, "TDBAL", NULL, e1000_regdump},
+       {E1000_TDBAH, "TDBAH", NULL, e1000_regdump},
+       {E1000_TDLEN, "TDLEN", NULL, e1000_regdump},
+       {E1000_TDH, "TDH", NULL, e1000_regdump},
+       {E1000_TDT, "TDT", NULL, e1000_regdump},
+       {E1000_TIDV, "TIDV", NULL, e1000_regdump},
+       {E1000_TXDCTL(0), "TXDCTL", get_regofs_TXDCTL, e1000_regdump_n},
+       {E1000_TADV, "TADV", NULL, e1000_regdump},
+       {E1000_TARC(0), "TARC", get_regofs_TARC, e1000_regdump_n},
+       {E1000_TDFH, "TDFH", NULL, e1000_regdump},
+       {E1000_TDFT, "TDFT", NULL, e1000_regdump},
+       {E1000_TDFHS, "TDFHS", NULL, e1000_regdump},
+       {E1000_TDFTS, "TDFTS", NULL, e1000_regdump},
+       {E1000_TDFPC, "TDFPC", NULL, e1000_regdump},
+
+       /* List Terminator */
+       {}
+};
+
+/*
+ * e1000e_dump - Print registers, tx-ring and rx-ring
+ */
+static void e1000e_dump(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+       struct e1000_reg_info *reginfo;
+       struct e1000_ring *tx_ring = adapter->tx_ring;
+       struct e1000_tx_desc *tx_desc;
+       struct my_u0 { u64 a; u64 b; } *u0;
+       struct e1000_buffer *buffer_info;
+       struct e1000_ring *rx_ring = adapter->rx_ring;
+       union e1000_rx_desc_packet_split *rx_desc_ps;
+       struct e1000_rx_desc *rx_desc;
+       struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+       u32 staterr;
+       int i = 0;
+
+       /* Print netdevice Info */
+       if (netdev) {
+               dev_err(&adapter->pdev->dev, "Net device Info\n");
+               printk(KERN_ERR "Device Name     state            "
+                       "trans_start      last_rx\n");
+               printk(KERN_ERR "%-15s %016lX %016lX %016lX\n",
+                       netdev->name,
+                       netdev->state,
+                       netdev->trans_start,
+                       netdev->last_rx);
+       }
+
+       /* Print Registers */
+       if ((dump_flag & E1000_DUMP_REGS) == 0)
+               goto tx_ring_summary;
+
+       dev_err(&adapter->pdev->dev, "Register Dump\n");
+       printk(KERN_ERR " Register Name   Value\n");
+       for (reginfo = (struct e1000_reg_info *)e1000_reg_info_tbl;
+            reginfo->name; reginfo++) {
+               reginfo->dump_reg(hw, reginfo->reg, reginfo->name,
+                                       reginfo->get_regofs);
+       }
+
+       /* Print TX Ring Summary */
+tx_ring_summary:
+       if (!netdev || !netif_running(netdev))
+               goto exit;
+
+       dev_err(&adapter->pdev->dev, "TX Rings Summary\n");
+       printk(KERN_ERR "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+               " leng ntw timestamp\n");
+       buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+       printk(KERN_ERR " %5d %5X %5X %016llX %04X %3X %016llX\n",
+               0, tx_ring->next_to_use, tx_ring->next_to_clean,
+               (u64)buffer_info->dma,
+               buffer_info->length,
+               buffer_info->next_to_watch,
+               (u64)buffer_info->time_stamp);
+
+       /* Print TX Rings */
+       if ((dump_flag & E1000_DUMP_TX_RINGS) == 0)
+               goto rx_ring_summary;
+
+       dev_err(&adapter->pdev->dev, "TX Rings Dump\n");
+
+       /* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
+        *
+        * Legacy Transmit Descriptor
+        *   +--------------------------------------------------------------+
+        * 0 |         Buffer Address [63:0] (Reserved on Write Back)       |
+        *   +--------------------------------------------------------------+
+        * 8 | Special  |    CSS     | Status |  CMD    |  CSO   |  Length  |
+        *   +--------------------------------------------------------------+
+        *   63       48 47        36 35    32 31     24 23    16 15        0
+        *
+        * Extended Context Descriptor (DTYP=0x0) for TSO or checksum offload
+        *   63      48 47    40 39       32 31             16 15    8 7      0
+        *   +----------------------------------------------------------------+
+        * 0 |  TUCSE  | TUCS0  |   TUCSS   |     IPCSE       | IPCS0 | IPCSS |
+        *   +----------------------------------------------------------------+
+        * 8 |   MSS   | HDRLEN | RSV | STA | TUCMD | DTYP |      PAYLEN      |
+        *   +----------------------------------------------------------------+
+        *   63      48 47    40 39 36 35 32 31   24 23  20 19                0
+        *
+        * Extended Data Descriptor (DTYP=0x1)
+        *   +----------------------------------------------------------------+
+        * 0 |                     Buffer Address [63:0]                      |
+        *   +----------------------------------------------------------------+
+        * 8 | VLAN tag |  POPTS  | Rsvd | Status | Command | DTYP |  DTALEN  |
+        *   +----------------------------------------------------------------+
+        *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
+        */
+       printk(KERN_ERR "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
+               " [bi->dma       ] leng  ntw timestamp        bi->skb "
+               "<-- Legacy format\n");
+       printk(KERN_ERR "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
+               " [bi->dma       ] leng  ntw timestamp        bi->skb "
+               "<-- Ext Context format\n");
+       printk(KERN_ERR "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
+               " [bi->dma       ] leng  ntw timestamp        bi->skb "
+               "<-- Ext Data format\n");
+       for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+               tx_desc = E1000_TX_DESC(*tx_ring, i);
+               buffer_info = &tx_ring->buffer_info[i];
+               u0 = (struct my_u0 *)tx_desc;
+               printk(KERN_ERR "T%c[0x%03X]    %016llX %016llX %016llX "
+                       "%04X  %3X %016llX %p",
+                      (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
+                       ((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+                      le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+                      (u64)buffer_info->dma, buffer_info->length,
+                      buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+                      buffer_info->skb);
+               if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
+                       printk(" NTC/U\n");
+               else if (i == tx_ring->next_to_use)
+                       printk(" NTU\n");
+               else if (i == tx_ring->next_to_clean)
+                       printk(" NTC\n");
+               else
+                       printk("\n");
+
+               if ((dump_flag & E1000_DUMP_BUFFERS) && buffer_info->dma != 0)
+                       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS,
+                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       buffer_info->length, true);
+       }
+
+       /* Print RX Rings Summary */
+rx_ring_summary:
+       dev_err(&adapter->pdev->dev, "RX Rings Summary\n");
+       printk(KERN_ERR "Queue [NTU] [NTC]\n");
+       printk(KERN_ERR " %5d %5X %5X\n", 0,
+               rx_ring->next_to_use, rx_ring->next_to_clean);
+
+       /* Print RX Rings */
+       if ((dump_flag & E1000_DUMP_RX_RINGS) == 0)
+               goto exit;
+
+       dev_err(&adapter->pdev->dev, "RX Rings Dump\n");
+       switch (adapter->rx_ps_pages) {
+       case 1:
+       case 2:
+       case 3:
+               /* [Extended] Packet Split Receive Descriptor Format
+                *
+                *    +-----------------------------------------------------+
+                *  0 |                Buffer Address 0 [63:0]              |
+                *    +-----------------------------------------------------+
+                *  8 |                Buffer Address 1 [63:0]              |
+                *    +-----------------------------------------------------+
+                * 16 |                Buffer Address 2 [63:0]              |
+                *    +-----------------------------------------------------+
+                * 24 |                Buffer Address 3 [63:0]              |
+                *    +-----------------------------------------------------+
+                */
+               printk(KERN_ERR "R  [desc]      [buffer 0 63:0 ] "
+                       "[buffer 1 63:0 ] "
+                      "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
+                      "[bi->skb] <-- Ext Pkt Split format\n");
+               /* [Extended] Receive Descriptor (Write-Back) Format
+                *
+                *   63       48 47    32 31     13 12    8 7    4 3        0
+                *   +------------------------------------------------------+
+                * 0 | Packet   | IP     |  Rsvd   | MRQ   | Rsvd | MRQ RSS |
+                *   | Checksum | Ident  |         | Queue |      |  Type   |
+                *   +------------------------------------------------------+
+                * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+                *   +------------------------------------------------------+
+                *   63       48 47    32 31            20 19               0
+                */
+               printk(KERN_ERR "RWB[desc]      [ck ipid mrqhsh] "
+                       "[vl   l0 ee  es] "
+                      "[ l3  l2  l1 hs] [reserved      ] ---------------- "
+                      "[bi->skb] <-- Ext Rx Write-Back format\n");
+               for (i = 0; i < rx_ring->count; i++) {
+                       buffer_info = &rx_ring->buffer_info[i];
+                       rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
+                       u1 = (struct my_u1 *)rx_desc_ps;
+                       staterr =
+                               le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+                       if (staterr & E1000_RXD_STAT_DD) {
+                               /* Descriptor Done */
+                               printk(KERN_ERR "RWB[0x%03X]     %016llX "
+                                       "%016llX %016llX %016llX "
+                                       "---------------- %p", i,
+                                       le64_to_cpu(u1->a),
+                                       le64_to_cpu(u1->b),
+                                       le64_to_cpu(u1->c),
+                                       le64_to_cpu(u1->d),
+                                       buffer_info->skb);
+                       } else {
+                               printk(KERN_ERR "R  [0x%03X]     %016llX "
+                                       "%016llX %016llX %016llX %016llX %p", i,
+                                       le64_to_cpu(u1->a),
+                                       le64_to_cpu(u1->b),
+                                       le64_to_cpu(u1->c),
+                                       le64_to_cpu(u1->d),
+                                       (u64)buffer_info->dma,
+                                       buffer_info->skb);
+
+                               if (dump_flag & E1000_DUMP_BUFFERS)
+                                       print_hex_dump(KERN_ERR, "",
+                                               DUMP_PREFIX_ADDRESS, 16, 1,
+                                               phys_to_virt(buffer_info->dma),
+                                               adapter->rx_ps_bsize0, true);
+                       }
+
+                       if (i == rx_ring->next_to_use)
+                               printk(" NTU\n");
+                       else if (i == rx_ring->next_to_clean)
+                               printk(" NTC\n");
+                       else
+                               printk("\n");
+               }
+               break;
+       default:
+       case 0:
+               /* Legacy Receive Descriptor Format
+                *
+                * +-----------------------------------------------------+
+                * |                Buffer Address [63:0]                |
+                * +-----------------------------------------------------+
+                * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
+                * +-----------------------------------------------------+
+                * 63       48 47    40 39      32 31         16 15      0
+                */
+               printk(KERN_ERR "Rl[desc]     [address 63:0  ] "
+                       "[vl er S cks ln] [bi->dma       ] [bi->skb] "
+                       "<-- Legacy format\n");
+               for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
+                       rx_desc = E1000_RX_DESC(*rx_ring, i);
+                       buffer_info = &rx_ring->buffer_info[i];
+                       u0 = (struct my_u0 *)rx_desc;
+                       printk(KERN_ERR "Rl[0x%03X]    %016llX %016llX "
+                               "%016llX %p",
+                               i, le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+                               (u64)buffer_info->dma, buffer_info->skb);
+                       if (i == rx_ring->next_to_use)
+                               printk(" NTU\n");
+                       else if (i == rx_ring->next_to_clean)
+                               printk(" NTC\n");
+                       else
+                               printk("\n");
+
+                       if (dump_flag & E1000_DUMP_BUFFERS)
+                               print_hex_dump(KERN_ERR, "",
+                                       DUMP_PREFIX_ADDRESS,
+                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       adapter->rx_buffer_len, true);
+               }
+       }
+
+exit:
+       return;
+}
+
  /**
  * e1000_desc_unused - calculate if we have unused descriptors
  **/
@@ -4247,6 +4587,7 @@ static void e1000_reset_task(struct work
        struct e1000_adapter *adapter;
        adapter = container_of(work, struct e1000_adapter, reset_task);
 
+       e1000e_dump(adapter);
        e1000e_reinit_locked(adapter);
  }
 

Index: net-next-2.6/drivers/net/e1000e/hw.h
===================================================================

drivers/net/e1000e/hw.h +0 -0
@@ -92,6 +92,11 @@ enum e1e_registers {

       E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */ E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */ E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
+       E1000_RDFH     = 0x02410, /* Rx Data FIFO Head - RW */
+       E1000_RDFT     = 0x02418, /* Rx Data FIFO Tail - RW */
+       E1000_RDFHS    = 0x02420, /* Rx Data FIFO Head Saved - RW */
+       E1000_RDFTS    = 0x02428, /* Rx Data FIFO Tail Saved - RW */
+       E1000_RDFPC    = 0x02430, /* Rx Data FIFO Packet Count - RW */ E1000_RDBAL    = 0x02800, /* Rx Descriptor Base Address Low - RW */ E1000_RDBAH    = 0x02804, /* Rx Descriptor Base Address High - RW */ E1000_RDLEN    = 0x02808, /* Rx Descriptor Length - RW */

drivers/net/e1000e/hw.h +0 -0
@@ -101,6 +106,11 @@ enum e1e_registers {

       E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */ #define E1000_RXDCTL(_n)   (E1000_RXDCTL_BASE + (_n << 8)) E1000_RADV     = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+       E1000_TDFH     = 0x03410, /* Tx Data FIFO Head - RW */
+       E1000_TDFT     = 0x03418, /* Tx Data FIFO Tail - RW */
+       E1000_TDFHS    = 0x03420, /* Tx Data FIFO Head Saved - RW */
+       E1000_TDFTS    = 0x03428, /* Tx Data FIFO Tail Saved - RW */
+       E1000_TDFPC    = 0x03430, /* Tx Data FIFO Packet Count - RW */

 /* Convenience macros
 *

drivers/net/e1000e/hw.h +0 -0
@@ -219,6 +229,23 @@ enum e1e_registers {

       E1000_HICR      = 0x08F00, /* Host Interface Control */ };

drivers/net/e1000e/hw.h +17 -0
+struct e1000_reg_info {
+       u32 reg;
+       char *name;
+       u32 (*get_regofs)(int);
+       void (*dump_reg)(struct e1000_hw *, u32, char *, u32 (*)(int));
+};
+
+#define E1000_GET_REGOFS_FUNC(name)                            \
+static inline u32 get_regofs_##name(int n)                     \
+{                                                              \
+       return E1000_##name(n);                                         \
+}                                                              \
+
+E1000_GET_REGOFS_FUNC(RXDCTL)
+E1000_GET_REGOFS_FUNC(TXDCTL)
+E1000_GET_REGOFS_FUNC(TARC)
+

 #define E1000_MAX_PHY_ADDR             4

 /* IGP01E1000 Specific Registers */

#16 lore raw
In reply to Jeff Kirsher

Taku,

I like the idea of adding debugging support. While using syslog does provide a "easier" way to get the output out, I am wondering if it would be worse the while
to try to add a generic debug interface (via ethtool / netlink) that each driver would
then support.

If using syslog is the choosen way, then having the feature on by default may not
be wanted.

Quoted 30 lines · Jeff Kirsher
Quoted 8 lines · Taku Izumi

Hi Jesse,

Quoted 5 lines

I have a counter proposal to make, here is a (incomplete) patch that we use all the time to debug tx hangs.  This example is for e1000e.  We are trying to avoid changes with other users' copyright to some of the files in our drivers so that we can ship them under multiple license.  We would much prefer something like this to be used, can you review?

Quoted 6 lines

  I haven't understood yet about the reason we have to avoid changing some files. Are there any files (header files?) we can't modify?

Best regards,
Taku Izumi

To answer your question, no there are no files you can't submit patches to.  We do have some common files which are used/shared amongst all of our drivers which are used for initializing and/or bring up the hardware, so when a patch is submitted to our drivers which changes our "shared code" our first question is "Is this change necessary for all of our drivers?" and if the answer is no, then we take a look at what changes can be made in the code which is not shared among our other drivers.

--
Cheers,
Jeff

author
#17 lore raw

Hi Chavey,

Quoted 10 lines

I like the idea of adding debugging support. While using syslog does provide a "easier" way to get the output out, I am wondering if it would be worse the while
to try to add a generic debug interface (via ethtool / netlink) that each driver would
then support.

If using syslog is the choosen way, then having the feature on by default may not
be wanted.

I think these pritout messages are not only for debugging purpose but a kind of error notification, for adapter resetting is error.
I prefer that these messages are always output wheter debugging mode is enabled or not, but if it is not hoped to be always output to syslog, another place (like a private ring buffer) is also acceptable.
Now I'm considering to output to private pring buffer.

Taku Izumi

author
#18 lore raw
In reply to Jeff Kirsher

Hi Jeff,

Quoted 8 lines

To answer your question, no there are no files you can't submit patches to. We do have some common files which are used/shared amongst all of our drivers which are used for initializing and/or bring up the hardware, so when a patch is submitted to our drivers which changes our "shared code" our first question is "Is this change necessary for all of our drivers?" and if the answer is no, then we take a look at what changes can be made in the code which is not shared among our other drivers.

Please tell me concretely which part of my former submitted patchset is bad? Next time I'll create under that condition.

Best regards,
Taku Izumi

author
#19 lore raw

Re: [PATCH v2 0/3] e1000e, igb, ixgbe: add registers etc. printout code just before resetting adapters

In reply to Brandeburg, Jesse

Hi Jesse,

Quoted 207 lines · Jesse
Quoted 19 lines · Taku Izumi
Quoted 12 lines · Jesse

Taku, thanks for these, we are talking the patches over and reviewing them. While I agree with the idea of these patches is good, I still don't agree with the default being enabled. Usually if someone is getting tx hangs they are repeatable and we can work with them to get the debug turned on. I DO think it is useful to have the feature available by default but NOT enabled.

If we wanted to enable something by default it might be useful to print something that actually draws some conclusions from known failure modes, like if TDH!=TDT after some amount of time. I think one or two lines maximum for default printing.

Quoted 5 lines

If you're working in this area I had an idea. I had wanted to be able to print the large amount of ring information (especially in the ixgbe case with many rings) to the ftrace buffers in order to not overrun the syslog daemon. Not sure if you're interested in more new features, it certainly is separate but related to this patch.

Quoted 5 lines

I thought similar things, that is, all information should be dumped to the private ring buffer to avoid filling syslog up with driver messages. But I didn't have any good idea to extract information from ring buffers, so as the first step, I decided to printout it by using printk(). Is there the easy way to extract it from ring buffers?

First, I need to apologize for the delay, it's my fault.

I'm not sure about an easy way to use the private ring buffers yet, I know you can use the ftrace buffers directly, and then when someone read /sys/kernel/debug/tracing/trace they would get all the output.

Lets not do ftrace yet.

I have a counter proposal to make, here is a (incomplete) patch that we use all the time to debug tx hangs. This example is for e1000e. We are trying to avoid changes with other users' copyright to some of the files in our drivers so that we can ship them under multiple license. We would much prefer something like this to be used, can you review?

I also have another patch I made for ixgb to show the use of sysfs and a module parameter, I'll reply again with that next.

---
From: Jesse Brandeburg<[email protected]>

e1000e: dump code for descriptor rings

This is debug code for descriptor ring dumps, only enable if you really want a lot of stuff in your syslog/dmesg when you get NETDEV WATCHDOG or tx hang reports from the driver.

<not implemented> Code can be enabled at boot time with a module parameter or via sysfs at runtime.

---

  drivers/net/e1000e/ethtool.c |    4 +
  drivers/net/e1000e/hw.h      |   10 +
  drivers/net/e1000e/netdev.c  |  298 ++++++++++++++++++++++++++++++++++++++++++
  3 files changed, 311 insertions(+), 1 deletions(-)
drivers/net/e1000e/ethtool.c +4 -0
index 0aa50c2..bbcf5c7 100644
@@ -434,6 +434,8 @@ static int e1000_get_regs_len(struct net_device *netdev)
  	return E1000_REGS_LEN * sizeof(u32);
  }
 
+extern void e1000e_dump(struct e1000_adapter *);
+
  static void e1000_get_regs(struct net_device *netdev,
  			   struct ethtool_regs *regs, void *p)
  {
@@ -443,6 +445,8 @@ static void e1000_get_regs(struct net_device *netdev,
  	u16 phy_data;
  	u8 revision_id;
 
+	e1000e_dump(adapter);
+
  	memset(p, 0, E1000_REGS_LEN * sizeof(u32));
 
  	pci_read_config_byte(adapter->pdev, PCI_REVISION_ID,&revision_id);
drivers/net/e1000e/hw.h +10 -0
index eccf29b..d23501d 100644
@@ -92,6 +92,11 @@ enum e1e_registers {
  	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
  	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
  	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
+	E1000_RDFH     = 0x02410, /* Rx Data FIFO Head - RW */
+	E1000_RDFT     = 0x02418, /* Rx Data FIFO Tail - RW */
+	E1000_RDFHS    = 0x02420, /* Rx Data FIFO Head Saved - RW */
+	E1000_RDFTS    = 0x02428, /* Rx Data FIFO Tail Saved - RW */
+	E1000_RDFPC    = 0x02430, /* Rx Data FIFO Packet Count - RW */
  	E1000_RDBAL    = 0x02800, /* Rx Descriptor Base Address Low - RW */
  	E1000_RDBAH    = 0x02804, /* Rx Descriptor Base Address High - RW */
  	E1000_RDLEN    = 0x02808, /* Rx Descriptor Length - RW */
@@ -112,6 +117,11 @@ enum e1e_registers {
   */
  #define E1000_RDBAL_REG(_n)   (E1000_RDBAL + (_n<<  8))
  	E1000_KABGTXD  = 0x03004, /* AFE Band Gap Transmit Ref Data */
+	E1000_TDFH     = 0x03410, /* TX Data FIFO Head - RW */
+	E1000_TDFT     = 0x03418, /* TX Data FIFO Tail - RW */
+	E1000_TDFHS    = 0x03420, /* TX Data FIFO Head Saved - RW */
+	E1000_TDFTS    = 0x03428, /* Tx Data FIFO Tail Saved - RW */
+	E1000_TDFPC    = 0x03430, /* TX Data FIFO Packet Count - RW */
  	E1000_TDBAL    = 0x03800, /* Tx Descriptor Base Address Low - RW */
  	E1000_TDBAH    = 0x03804, /* Tx Descriptor Base Address High - RW */
  	E1000_TDLEN    = 0x03808, /* Tx Descriptor Length - RW */
drivers/net/e1000e/netdev.c +76 -1
index c45965a..c990341 100644
@@ -48,7 +48,7 @@
 
  #include "e1000.h"
 
-#define DRV_VERSION "1.0.2-k2"
+#define DRV_VERSION "1.0.2-k4"
  char e1000e_driver_name[] = "e1000e";
  const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -601,6 +601,301 @@ static void e1000_print_hw_hang(struct work_struct *work)
  	      pci_status);
  }
 
+#if 0
+static void hexdump(dma_addr_t dma, u16 len)
+{
+	u16 offset, i;
+	char str[80], byte[4];
+	void *va = phys_to_virt((unsigned long)dma);
+
+	printk("buffer at %016llX (%d)\n", (u64)dma, len);
+	for (offset = 0; offset<  len; offset += 16) {
+		sprintf(str, "%04x: ", offset);
+		for (i = 0; i<  16; i++) {
+			if ((offset + i)<  len)
+				sprintf(byte, "%02x ",
+				        ((unsigned char *)va)[offset + i]);
+			else
+				strcpy(byte, "   ");
+			strcat(str, byte);
+		}
+		printk("%s\n", str);
+	}
+}
+
+#endif
+void e1000e_dump(struct e1000_adapter *adapter)
+{
+	/* this code doesn't handle multiple rings */
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_hw *hw =&adapter->hw;
+	int i = 0;
+#define NUM_REGS 38 /* 1 based count */
+	u32 regs[NUM_REGS];
+	u32 *regs_buff = regs;
+
+	char *reg_name[] = {
+	"CTRL",  "STATUS",
+	"RCTL", "RDLEN", "RDH", "RDT", "RDTR",
+	"TCTL", "TDBAL", "TDBAH", "TDLEN", "TDH", "TDT",
+	"TIDV", "TXDCTL", "TADV", "TARC0",
+	"TDBAL1", "TDBAH1", "TDLEN1", "TDH1", "TDT1",
+	"TXDCTL1", "TARC1",
+	"CTRL_EXT", "ERT", "RDBAL", "RDBAH",
+	 "TDFH", "TDFT", "TDFHS", "TDFTS", "TDFPC",
+	 "RDFH", "RDFT", "RDFHS", "RDFTS", "RDFPC",
+	};
+
+	//if (!e1000e_debug_dump)
+		//return;
+
+	regs_buff[0]  = er32(CTRL);
+	regs_buff[1]  = er32(STATUS);
+
+	regs_buff[2]  = er32(RCTL);
+	regs_buff[3]  = er32(RDLEN);
+	regs_buff[4]  = er32(RDH);
+	regs_buff[5]  = er32(RDT);
+	regs_buff[6]  = er32(RDTR);
+
+	regs_buff[7]  = er32(TCTL);
+	regs_buff[8]  = er32(TDBAL);
+	regs_buff[9]  = er32(TDBAH);
+	regs_buff[10] = er32(TDLEN);
+	regs_buff[11] = er32(TDH);
+	regs_buff[12] = er32(TDT);
+	regs_buff[13] = er32(TIDV);
+	regs_buff[14] = er32(TXDCTL(0));
+	regs_buff[15] = er32(TADV);
+	regs_buff[16] = er32(TARC(0));
+
+	regs_buff[22] = er32(TXDCTL(1));
+	regs_buff[23] = er32(TARC(1));
+	regs_buff[24] = er32(CTRL_EXT);
+	regs_buff[25] = er32(ERT);
+	regs_buff[26] = er32(RDBAL);
+	regs_buff[27] = er32(RDBAH);

drivers/net/e1000e/netdev.c static void e1000_print_hw_hang(struct work_struct *work) · line 688

Quoted 10 lines
drivers/net/e1000e/netdev.c +10 -0
+	regs_buff[28] = er32(TDFH);
+	regs_buff[29] = er32(TDFT);
+	regs_buff[30] = er32(TDFHS);
+	regs_buff[31] = er32(TDFTS);
+	regs_buff[32] = er32(TDFPC);
+	regs_buff[33] = er32(RDFH);
+	regs_buff[34] = er32(RDFT);
+	regs_buff[35] = er32(RDFHS);
+	regs_buff[36] = er32(RDFTS);
+	regs_buff[37] = er32(RDFPC);

I think indexing is annoying especially when the number of registers is large for example in case of the ixgbe driver.

Quoted 214 lines
drivers/net/e1000e/netdev.c +210 -0
+
+	e_err("Register dump\n");
+	for (i = 0; i<  NUM_REGS; i++) {
+		printk("%-15s  %08x\n",
+		reg_name[i], regs_buff[i]);
+	}
+
+	/*
+	 * transmit dump
+	 */
+	printk(KERN_ERR"TX Desc ring0 dump\n");
+
+	/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
+	 *
+	 * Legacy Transmit Descriptor
+	 *   +--------------------------------------------------------------+
+	 * 0 |         Buffer Address [63:0] (Reserved on Write Back)       |
+	 *   +--------------------------------------------------------------+
+	 * 8 | Special  |    CSS     | Status |  CMD    |  CSO   |  Length  |
+	 *   +--------------------------------------------------------------+
+	 *   63       48 47        36 35    32 31     24 23    16 15        0
+	 *
+	 * Extended Context Descriptor (DTYP=0x0) for TSO or checksum offload
+	 *   63      48 47    40 39       32 31             16 15    8 7      0
+	 *   +----------------------------------------------------------------+
+	 * 0 |  TUCSE  | TUCS0  |   TUCSS   |     IPCSE       | IPCS0 | IPCSS |
+	 *   +----------------------------------------------------------------+
+	 * 8 |   MSS   | HDRLEN | RSV | STA | TUCMD | DTYP |      PAYLEN      |
+	 *   +----------------------------------------------------------------+
+	 *   63      48 47    40 39 36 35 32 31   24 23  20 19                0
+	 *
+	 * Extended Data Descriptor (DTYP=0x1)
+	 *   +----------------------------------------------------------------+
+	 * 0 |                     Buffer Address [63:0]                      |
+	 *   +----------------------------------------------------------------+
+	 * 8 | VLAN tag |  POPTS  | Rsvd | Status | Command | DTYP |  DTALEN  |
+	 *   +----------------------------------------------------------------+
+	 *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
+	 */
+	printk("Tl(Legacy)   [address 63:0  ] [SpeCssSCmCsLen] [buffer_info dma"
+	       " leng  ntw       time_stamp             skb]\n");
+	printk("Tc(ExtCont)  [Ce CoCsIpceCoS] [MssHlRSCm0Plen] [buffer_info dma"
+	       " leng  ntw       time_stamp             skb]\n");
+	printk("Td(ExtData)  [address 63:0  ] [VlaPoRSCm1Dlen] [buffer_info dma"
+	       " leng  ntw       time_stamp             skb]\n");
+	for (i = 0; tx_ring->desc&&  (i<  tx_ring->count); i++) {
+		struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+		struct e1000_buffer *buffer_info =&tx_ring->buffer_info[i];
+		struct my_u { u64 a; u64 b; };
+		struct my_u *u = (struct my_u *)tx_desc;
+		printk("T%c[0x%03X]    %016llX %016llX %016llX %04X  %3X "
+		       "%016llX %p",
+		       (!(le64_to_cpu(u->b)&  (1<<29)) ? 'l' :
+		         ((le64_to_cpu(u->b)&  (1<<20)) ? 'd' : 'c')), i,
+		       le64_to_cpu(u->a), le64_to_cpu(u->b),
+		       (u64)buffer_info->dma, buffer_info->length,
+		       buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+		       buffer_info->skb);
+		if (i == tx_ring->next_to_use&&  i == tx_ring->next_to_clean)
+			printk(" NTC/U\n");
+		else if (i == tx_ring->next_to_use)
+			printk(" NTU\n");
+		else if (i == tx_ring->next_to_clean)
+			printk(" NTC\n");
+		else
+			printk("\n");
+
+#if 0
+		if (adapter->dump_buffers&&  (buffer_info->dma != 0))
+			hexdump(buffer_info->dma, buffer_info->length);
+#endif
+	}
+
+	/*
+	 * receive dump
+	 */
+	printk(KERN_ERR"\nRX Desc ring dump\n");
+
+	switch (adapter->rx_ps_pages) {
+	case 1:
+	case 2:
+	case 3:
+		/* [Extended] Packet Split Receive Descriptor Format
+		 *
+		 *    +-----------------------------------------------------+
+		 *  0 |                Buffer Address 0 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 *  8 |                Buffer Address 1 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 * 16 |                Buffer Address 2 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 * 24 |                Buffer Address 3 [63:0]              |
+		 *    +-----------------------------------------------------+
+		 */
+		printk("R  [desc]      [buffer 0 63:0 ] [buffer 1 63:0 ] "
+		       "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
+		       "[bi->skb]<-- Ext Pkt Split format\n");
+		/* [Extended] Receive Descriptor (Write-Back) Format
+		 *
+		 *   63       48 47    32 31     13 12    8 7    4 3        0
+		 *   +------------------------------------------------------+
+		 * 0 | Packet   | IP     |  Rsvd   | MRQ   | Rsvd | MRQ RSS |
+		 *   | Checksum | Ident  |         | Queue |      |  Type   |
+		 *   +------------------------------------------------------+
+		 * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+		 *   +------------------------------------------------------+
+		 *   63       48 47    32 31            20 19               0
+		 */
+		printk("RWB[desc]      [ck ipid mrqhsh] [vl   l0 ee  es] "
+		       "[ l3  l2  l1 hs] [reserved      ] ---------------- "
+		       "[bi->skb]<-- Ext Rx Write-Back format\n");
+		for (i = 0; i<  rx_ring->count; i++) {
+			struct e1000_buffer *buffer_info =
+						&rx_ring->buffer_info[i];
+			union e1000_rx_desc_packet_split *rx_desc =
+						E1000_RX_DESC_PS(*rx_ring, i);
+			struct my_u { u64 a; u64 b; u64 c; u64 d; };
+			struct my_u *u = (struct my_u *)rx_desc;
+			u32 staterr;
+			staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+			if (staterr&  E1000_RXD_STAT_DD) {
+				/* Descriptor Done */
+				printk("RWB[0x%03X]     %016llX %016llX %016llX"
+				       " %016llX ---------------- %p",
+				       i, le64_to_cpu(u->a), le64_to_cpu(u->b),
+				       le64_to_cpu(u->c), le64_to_cpu(u->d),
+				       buffer_info->skb);
+			} else {
+				printk("R  [0x%03X]     %016llX %016llX %016llX"
+				       " %016llX %016llX %p",
+				       i, le64_to_cpu(u->a), le64_to_cpu(u->b),
+				       le64_to_cpu(u->c), le64_to_cpu(u->d),
+				       (u64)buffer_info->dma, buffer_info->skb);
+
+#if 0
+				if (adapter->dump_buffers)
+					hexdump(buffer_info->dma,
+					        adapter->rx_ps_bsize0);
+#endif
+			}
+
+			if (i == rx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+		}
+		break;
+	default:
+	case 0:
+		/* Legacy Receive Descriptor Format
+		 *
+		 * +-----------------------------------------------------+
+		 * |                Buffer Address [63:0]                |
+		 * +-----------------------------------------------------+
+		 * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
+		 * +-----------------------------------------------------+
+		 * 63       48 47    40 39      32 31         16 15      0
+		 */
+		printk("Rl[desc]     [address 63:0  ] [vl er S cks ln] "
+		       "[bi->dma       ] [bi->skb]<-- Legacy format\n");
+		for (i = 0; rx_ring->desc&&  (i<  rx_ring->count); i++) {
+			struct e1000_rx_desc *rx_desc =
+						E1000_RX_DESC(*rx_ring, i);
+			struct e1000_buffer *buffer_info =
+						&rx_ring->buffer_info[i];
+			struct my_u { u64 a; u64 b; };
+			struct my_u *u = (struct my_u *)rx_desc;
+			printk("Rl[0x%03X]    %016llX %016llX %016llX %p",
+				i, le64_to_cpu(u->a), le64_to_cpu(u->b),
+				(u64)buffer_info->dma, buffer_info->skb);
+			if (i == rx_ring->next_to_use)
+				printk(" NTU\n");
+			else if (i == rx_ring->next_to_clean)
+				printk(" NTC\n");
+			else
+				printk("\n");
+
+#if 0
+			if (adapter->dump_buffers)
+				hexdump(buffer_info->dma,
+				        adapter->rx_buffer_len);
+#endif
+		} /* for */
+	} /* switch */
+
+	/* dump the descriptor caches */
+	/* rx */
+	printk("Rx descriptor cache in 64bit format\n");
+	for (i = 0x6000; i<= 0x63FF ; i += 0x10) {
+		printk("R%04X: %08X|%08X %08X|%08X\n",
+				i,
+				readl(adapter->hw.hw_addr + i+4),
+				readl(adapter->hw.hw_addr + i),
+				readl(adapter->hw.hw_addr + i+12),
+				readl(adapter->hw.hw_addr + i+8));
+	}
+	/* tx */
+	printk("Tx descriptor cache in 64bit format\n");
+	for (i = 0x7000; i<= 0x73FF ; i += 0x10) {
+		printk("T%04X: %08X|%08X %08X|%08X\n",
+				i,
+				readl(adapter->hw.hw_addr + i+4),
+				readl(adapter->hw.hw_addr + i),
+				readl(adapter->hw.hw_addr + i+12),
+				readl(adapter->hw.hw_addr + i+8));
+	}
+}
+
  /**
   * e1000_clean_tx_irq - Reclaim resources after transmit completes
   * @adapter: board private structure

drivers/net/e1000e/netdev.c static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) · line 980

Quoted 4 lines
drivers/net/e1000e/netdev.c +1 -0
@@ -682,6 +977,7 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
  			       + (adapter->tx_timeout_factor * HZ))&&
  		!(er32(STATUS)&  E1000_STATUS_TXOFF)) {
  			schedule_work(&adapter->print_hang_task);
+			e1000e_dump(adapter);

I think it is not proper to invoke e1000e_dump() here because here is in interupt context and there is the case of resetting adapters without meeting the condition of "adapter->detect_tx_hung == true"

Quoted 9 lines
drivers/net/e1000e/netdev.c +0 -1
  			netif_stop_queue(netdev);
  		}
  	}
--

To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Best regards,
Taku Izumi

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired