// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2018 Intel Corporation */ #include "igc.h" struct igc_reg_info { u32 ofs; char *name; }; static const struct igc_reg_info igc_reg_info_tbl[] = { /* General Registers */ {IGC_CTRL, "CTRL"}, {IGC_STATUS, "STATUS"}, {IGC_CTRL_EXT, "CTRL_EXT"}, {IGC_MDIC, "MDIC"}, /* Interrupt Registers */ {IGC_ICR, "ICR"}, /* RX Registers */ {IGC_RCTL, "RCTL"}, {IGC_RDLEN(0), "RDLEN"}, {IGC_RDH(0), "RDH"}, {IGC_RDT(0), "RDT"}, {IGC_RXDCTL(0), "RXDCTL"}, {IGC_RDBAL(0), "RDBAL"}, {IGC_RDBAH(0), "RDBAH"}, /* TX Registers */ {IGC_TCTL, "TCTL"}, {IGC_TDBAL(0), "TDBAL"}, {IGC_TDBAH(0), "TDBAH"}, {IGC_TDLEN(0), "TDLEN"}, {IGC_TDH(0), "TDH"}, {IGC_TDT(0), "TDT"}, {IGC_TXDCTL(0), "TXDCTL"}, /* List Terminator */ {} }; /* igc_regdump - register printout routine */ static void igc_regdump(struct igc_hw *hw, struct igc_reg_info *reginfo) { struct net_device *dev = igc_get_hw_dev(hw); int n = 0; char rname[16]; u32 regs[8]; switch (reginfo->ofs) { case IGC_RDLEN(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RDLEN(n)); break; case IGC_RDH(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RDH(n)); break; case IGC_RDT(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RDT(n)); break; case IGC_RXDCTL(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RXDCTL(n)); break; case IGC_RDBAL(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RDBAL(n)); break; case IGC_RDBAH(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RDBAH(n)); break; case IGC_TDBAL(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_RDBAL(n)); break; case IGC_TDBAH(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_TDBAH(n)); break; case IGC_TDLEN(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_TDLEN(n)); break; case IGC_TDH(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_TDH(n)); break; case IGC_TDT(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_TDT(n)); break; case IGC_TXDCTL(0): for (n = 0; n < 4; n++) regs[n] = rd32(IGC_TXDCTL(n)); break; default: netdev_info(dev, "%-15s %08x\n", reginfo->name, rd32(reginfo->ofs)); return; } snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]"); netdev_info(dev, "%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1], regs[2], regs[3]); } /* igc_rings_dump - Tx-rings and Rx-rings */ void igc_rings_dump(struct igc_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct my_u0 { u64 a; u64 b; } *u0; union igc_adv_tx_desc *tx_desc; union igc_adv_rx_desc *rx_desc; struct igc_ring *tx_ring; struct igc_ring *rx_ring; u32 staterr; u16 i, n; if (!netif_msg_hw(adapter)) return; netdev_info(netdev, "Device info: state %016lX trans_start %016lX\n", netdev->state, dev_trans_start(netdev)); /* Print TX Ring Summary */ if (!netif_running(netdev)) goto exit; netdev_info(netdev, "TX Rings Summary\n"); netdev_info(netdev, "Queue [NTU] [NTC] [bi(ntc)->dma ] leng ntw timestamp\n"); for (n = 0; n < adapter->num_tx_queues; n++) { struct igc_tx_buffer *buffer_info; tx_ring = adapter->tx_ring[n]; buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean]; netdev_info(netdev, "%5d %5X %5X %016llX %04X %p %016llX\n", n, tx_ring->next_to_use, tx_ring->next_to_clean, (u64)dma_unmap_addr(buffer_info, dma), dma_unmap_len(buffer_info, len), buffer_info->next_to_watch, (u64)buffer_info->time_stamp); } /* Print TX Rings */ if (!netif_msg_tx_done(adapter)) goto rx_ring_summary; netdev_info(netdev, "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]; netdev_info(netdev, "------------------------------------\n"); netdev_info(netdev, "TX QUEUE INDEX = %d\n", tx_ring->queue_index); netdev_info(netdev, "------------------------------------\n"); netdev_info(netdev, "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++) { const char *next_desc; struct igc_tx_buffer *buffer_info; tx_desc = IGC_TX_DESC(tx_ring, i); buffer_info = &tx_ring->tx_buffer_info[i]; u0 = (struct my_u0 *)tx_desc; if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean) next_desc = " NTC/U"; else if (i == tx_ring->next_to_use) next_desc = " NTU"; else if (i == tx_ring->next_to_clean) next_desc = " NTC"; else next_desc = ""; netdev_info(netdev, "T [0x%03X] %016llX %016llX %016llX %04X %p %016llX %p%s\n", i, le64_to_cpu(u0->a), le64_to_cpu(u0->b), (u64)dma_unmap_addr(buffer_info, dma), dma_unmap_len(buffer_info, len), buffer_info->next_to_watch, (u64)buffer_info->time_stamp, buffer_info->skb, next_desc); if (netif_msg_pktdata(adapter) && buffer_info->skb) print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, buffer_info->skb->data, dma_unmap_len(buffer_info, len), true); } } /* Print RX Rings Summary */ rx_ring_summary: netdev_info(netdev, "RX Rings Summary\n"); netdev_info(netdev, "Queue [NTU] [NTC]\n"); for (n = 0; n < adapter->num_rx_queues; n++) { rx_ring = adapter->rx_ring[n]; netdev_info(netdev, "%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; netdev_info(netdev, "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]; netdev_info(netdev, "------------------------------------\n"); netdev_info(netdev, "RX QUEUE INDEX = %d\n", rx_ring->queue_index); netdev_info(netdev, "------------------------------------\n"); netdev_info(netdev, "R [desc] [ PktBuf A0] [ HeadBuf DD] [bi->dma ] [bi->skb] <-- Adv Rx Read format\n"); netdev_info(netdev, "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++) { const char *next_desc; struct igc_rx_buffer *buffer_info; buffer_info = &rx_ring->rx_buffer_info[i]; rx_desc = IGC_RX_DESC(rx_ring, i); u0 = (struct my_u0 *)rx_desc; staterr = le32_to_cpu(rx_desc->wb.upper.status_error); if (i == rx_ring->next_to_use) next_desc = " NTU"; else if (i == rx_ring->next_to_clean) next_desc = " NTC"; else next_desc = ""; if (staterr & IGC_RXD_STAT_DD) { /* Descriptor Done */ netdev_info(netdev, "%s[0x%03X] %016llX %016llX ---------------- %s\n", "RWB", i, le64_to_cpu(u0->a), le64_to_cpu(u0->b), next_desc); } else { netdev_info(netdev, "%s[0x%03X] %016llX %016llX %016llX %s\n", "R ", i, le64_to_cpu(u0->a), le64_to_cpu(u0->b), (u64)buffer_info->dma, next_desc); if (netif_msg_pktdata(adapter) && buffer_info->dma && buffer_info->page) { print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 1, page_address (buffer_info->page) + buffer_info->page_offset, igc_rx_bufsz(rx_ring), true); } } } } exit: return; } /* igc_regs_dump - registers dump */ void igc_regs_dump(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; struct igc_reg_info *reginfo; /* Print Registers */ netdev_info(adapter->netdev, "Register Dump\n"); netdev_info(adapter->netdev, "Register Name Value\n"); for (reginfo = (struct igc_reg_info *)igc_reg_info_tbl; reginfo->name; reginfo++) { igc_regdump(hw, reginfo); } }