igb: add registers etc. printout code just before resetting adapters
authorTaku Izumi <izumi.taku@jp.fujitsu.com>
Tue, 27 Apr 2010 14:39:30 +0000 (14:39 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Apr 2010 00:46:56 +0000 (17:46 -0700)
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.

Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
Signed-off-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/igb/igb_main.c

index 9d042fe..438737d 100644 (file)
@@ -201,6 +201,336 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+struct igb_reg_info {
+       u32 ofs;
+       char *name;
+};
+
+static const struct igb_reg_info igb_reg_info_tbl[] = {
+
+       /* General Registers */
+       {E1000_CTRL, "CTRL"},
+       {E1000_STATUS, "STATUS"},
+       {E1000_CTRL_EXT, "CTRL_EXT"},
+
+       /* Interrupt Registers */
+       {E1000_ICR, "ICR"},
+
+       /* RX Registers */
+       {E1000_RCTL, "RCTL"},
+       {E1000_RDLEN(0), "RDLEN"},
+       {E1000_RDH(0), "RDH"},
+       {E1000_RDT(0), "RDT"},
+       {E1000_RXDCTL(0), "RXDCTL"},
+       {E1000_RDBAL(0), "RDBAL"},
+       {E1000_RDBAH(0), "RDBAH"},
+
+       /* TX Registers */
+       {E1000_TCTL, "TCTL"},
+       {E1000_TDBAL(0), "TDBAL"},
+       {E1000_TDBAH(0), "TDBAH"},
+       {E1000_TDLEN(0), "TDLEN"},
+       {E1000_TDH(0), "TDH"},
+       {E1000_TDT(0), "TDT"},
+       {E1000_TXDCTL(0), "TXDCTL"},
+       {E1000_TDFH, "TDFH"},
+       {E1000_TDFT, "TDFT"},
+       {E1000_TDFHS, "TDFHS"},
+       {E1000_TDFPC, "TDFPC"},
+
+       /* List Terminator */
+       {}
+};
+
+/*
+ * igb_regdump - register printout routine
+ */
+static void igb_regdump(struct e1000_hw *hw, struct igb_reg_info *reginfo)
+{
+       int n = 0;
+       char rname[16];
+       u32 regs[8];
+
+       switch (reginfo->ofs) {
+       case E1000_RDLEN(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDLEN(n));
+               break;
+       case E1000_RDH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDH(n));
+               break;
+       case E1000_RDT(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDT(n));
+               break;
+       case E1000_RXDCTL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RXDCTL(n));
+               break;
+       case E1000_RDBAL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDBAL(n));
+               break;
+       case E1000_RDBAH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDBAH(n));
+               break;
+       case E1000_TDBAL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDBAL(n));
+               break;
+       case E1000_TDBAH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDBAH(n));
+               break;
+       case E1000_TDLEN(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDLEN(n));
+               break;
+       case E1000_TDH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDH(n));
+               break;
+       case E1000_TDT(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDT(n));
+               break;
+       case E1000_TXDCTL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TXDCTL(n));
+               break;
+       default:
+               printk(KERN_INFO "%-15s %08x\n",
+                       reginfo->name, rd32(reginfo->ofs));
+               return;
+       }
+
+       snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
+       printk(KERN_INFO "%-15s ", rname);
+       for (n = 0; n < 4; n++)
+               printk(KERN_CONT "%08x ", regs[n]);
+       printk(KERN_CONT "\n");
+}
+
+/*
+ * 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;
+
+       if (!netif_msg_hw(adapter))
+               return;
+
+       /* Print netdevice Info */
+       if (netdev) {
+               dev_info(&adapter->pdev->dev, "Net device Info\n");
+               printk(KERN_INFO "Device Name     state            "
+                       "trans_start      last_rx\n");
+               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
+               netdev->name,
+               netdev->state,
+               netdev->trans_start,
+               netdev->last_rx);
+       }
+
+       /* Print Registers */
+       dev_info(&adapter->pdev->dev, "Register Dump\n");
+       printk(KERN_INFO " Register Name   Value\n");
+       for (reginfo = (struct igb_reg_info *)igb_reg_info_tbl;
+            reginfo->name; reginfo++) {
+               igb_regdump(hw, reginfo);
+       }
+
+       /* Print TX Ring Summary */
+       if (!netdev || !netif_running(netdev))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+       printk(KERN_INFO "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_INFO " %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 (!netif_msg_tx_done(adapter))
+               goto rx_ring_summary;
+
+       dev_info(&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_INFO "------------------------------------\n");
+               printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "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_INFO "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 (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+                               print_hex_dump(KERN_INFO, "",
+                                       DUMP_PREFIX_ADDRESS,
+                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       buffer_info->length, true);
+               }
+       }
+
+       /* Print RX Rings Summary */
+rx_ring_summary:
+       dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               printk(KERN_INFO " %5d %5X %5X\n", n,
+                          rx_ring->next_to_use, rx_ring->next_to_clean);
+       }
+
+       /* Print RX Rings */
+       if (!netif_msg_rx_status(adapter))
+               goto exit;
+
+       dev_info(&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_INFO "------------------------------------\n");
+               printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "R  [desc]      [ PktBuf     A0] "
+                       "[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+                       "<-- Adv Rx Read format\n");
+               printk(KERN_INFO "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_INFO "RWB[0x%03X]     %016llX "
+                                       "%016llX ---------------- %p", i,
+                                       le64_to_cpu(u0->a),
+                                       le64_to_cpu(u0->b),
+                                       buffer_info->skb);
+                       } else {
+                               printk(KERN_INFO "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 (netif_msg_pktdata(adapter)) {
+                                       print_hex_dump(KERN_INFO, "",
+                                               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_INFO, "",
+                                                 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)
  */
@@ -3858,6 +4188,8 @@ static void igb_reset_task(struct work_struct *work)
        struct igb_adapter *adapter;
        adapter = container_of(work, struct igb_adapter, reset_task);
 
+       igb_dump(adapter);
+       netdev_err(adapter->netdev, "Reset adapter\n");
        igb_reinit_locked(adapter);
 }