Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c +9 −0 Original line number Diff line number Diff line Loading @@ -973,6 +973,15 @@ int atl2_fw_init(struct atl_hw *hw) atl2_get_fw_version(hw); /* Warn if FW is lower than 1.3.1 */ if (((mcp->fw_rev >> 24) < 1) || (((mcp->fw_rev >> 16) & 0xFFU) < 3) || ((mcp->fw_rev & 0xFFFFU) < 1)) atl_dev_warn("FW_version: %u.%u.%u, is not stable version", (mcp->fw_rev >> 24), ((mcp->fw_rev >> 16) & 0xFFU), (mcp->fw_rev & 0xFFFFU)); mcp->ops = &atl2_fw_ops; atl_dev_dbg("Detect ATL2FW %x\n", mcp->fw_rev); Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +2 −15 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ #include <linux/netdevice.h> #include <linux/moduleparam.h> #define ATL_VERSION "1.1.18" #define ATL_VERSION "1.1.22" struct atl_nic; Loading @@ -32,8 +32,6 @@ struct atl_nic; #define ATL_MAX_QUEUES 8 #include "atl_fwd.h" struct atl_ptp; enum { Loading Loading @@ -414,6 +412,7 @@ void atl_update_global_stats(struct atl_nic *nic); void atl_set_loopback(struct atl_nic *nic, int idx, bool on); void atl_set_intr_mod(struct atl_nic *nic); void atl_update_ntuple_flt(struct atl_nic *nic, int idx); int atl_vlan_promisc_status(struct net_device *ndev); void atl_set_vlan_promisc(struct atl_hw *hw, int promisc); int atl_hwsem_get(struct atl_hw *hw, int idx); void atl_hwsem_put(struct atl_hw *hw, int idx); Loading @@ -424,18 +423,6 @@ int atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val); int atl_update_eth_stats(struct atl_nic *nic); void atl_adjust_eth_stats(struct atl_ether_stats *stats, struct atl_ether_stats *base, bool add); void atl_fwd_release_rings(struct atl_nic *nic); #if IS_ENABLED(CONFIG_ATLFWD_FWD) enum atl_fwd_notify; int atl_fwd_suspend_rings(struct atl_nic *nic); int atl_fwd_resume_rings(struct atl_nic *nic); void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data); #else static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; } static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } static inline void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data) {} #endif int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay); void atl_refresh_rxfs(struct atl_nic *nic); void atl_schedule_work(struct atl_nic *nic); Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump.h 0 → 100644 +123 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Atlantic Network Driver * * Copyright (C) 2021 Marvell International Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef _ATL_DUMP_H_ #define _ATL_DUMP_H_ enum atl_crash_dump_types { atl_crash_dump_type_regs = 0, atl_crash_dump_type_fwiface = 1, atl_crash_dump_type_act_res = 2, atl_crash_dump_type_ring = 3, }; /** Some of the registers we can not read safely from the device. * Those will not be read, with value 0xFFFFFFFF stored instead. */ struct atl_crash_dump_regs { u32 type; u32 length; union { u32 regs_data[0x9000/4]; struct{ u32 mif[0x1000/4]; u32 pci[0x1000/4]; u32 itr[0x1000/4]; u32 com[0x1000/4]; u32 mac_phy[0x1000/4]; union { u32 rx[0x2000/4]; struct{ u32 res1[0x700/4]; u32 pb_ctrl; u32 res2; u32 pb_status; u32 res3; /* 0x5710 */ struct{ u32 pb_reg1; u32 pb_reg2; u32 pb_reg3; } pb[8]; u32 res4[0x100]; /* TODO */ /* 0x5B00 */ struct{ u32 base_lo; u32 base_hi; u32 ctrl; u32 head; u32 tail; u32 status; u32 size; u32 threshold; } dma_desc[32]; } layout; }; u32 tx[0x2000/4]; } layout; }; }; struct atl_crash_dump_fwiface { u32 type; u32 length; /* struct fw_interface_in */ u32 fw_interface_in[0x1000/4]; /* struct fw_interface_out */ u32 fw_interface_out[0x1000/4]; }; /* Record table size of 128 with each entry holding (tag, mask, action) */ #define ATL_ACT_RES_TABLE_SIZE 384 struct atl_crash_dump_act_res { u32 type; u32 length; u32 act_res_data[ATL_ACT_RES_TABLE_SIZE]; }; /* max_size = 'ring_size * (tx + rx) * 16 byte raw descriptor data' */ #define ATL_MAX_RING_DESC_SIZE ATL_MAX_RING_SIZE * 32 struct atl_crash_dump_ring { u32 type; u32 length; u32 index; u32 rx_head; u32 rx_tail; u32 tx_head; u32 tx_tail; u32 rx_ring_size; u32 tx_ring_size; u8 ring_data[ATL_MAX_RING_DESC_SIZE]; }; /* This is an extensible structure to collect various debug data from * AQC device */ struct atl_crash_dump { u32 length; /* total crash structure length, in bytes */ u32 sections_count; /* number of sections of type atl_crash_dump* following */ u8 drv_version[16]; u8 fw_version[16]; union { struct { struct atl_crash_dump_regs regs; struct atl_crash_dump_fwiface fwiface; struct atl_crash_dump_act_res act_res; struct atl_crash_dump_ring ring[ATL_MAX_QUEUES]; } antigua; struct { struct atl_crash_dump_regs regs; struct atl_crash_dump_ring ring[ATL_MAX_QUEUES]; } atlantic; }; }; #endif drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/README 0 → 100644 +21 −0 Original line number Diff line number Diff line The tool atl_dump_parser is used to parse the register/device dump collected using "ethtool -d" command. Parser accepts dump in the binary format, hence the dump must be collected using 'raw' option i.e., 'ethtool -d <device> raw on' Use gcc to build the binary from sources, gcc -o atl_dump_parser atl_dump_parser.c Example: -------- 1. Collect ethtool dump from SUT machine #ethtool -d enp1s0 raw on > ethd_dump 2. Parse the dump #ls atl_dump_parser ethd_dump #./atl_dump_parser ethd_dump Parsing is completed successfully #ls ethd_dump_parsed action_resolver.txt atl_dump_parser ethd_dump fw_interface.txt registers.txt rings.txt # Parsed data will be copied to the text files under <input_file>_parsed folder. drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.c 0 → 100644 +296 −0 Original line number Diff line number Diff line #include <stdio.h> #include <stddef.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #include "atl_dump_parser.h" #include "../atl_dump.h" #define DEV_FILE "device.txt" #define REG_FILE "registers.txt" #define FW_IFACE_FILE "fw_interface.txt" #define ACT_RES_FILE "action_resolver.txt" #define RING_FILE "rings.txt" struct section_header { u32 type; u32 length; }; char out_folder[64]; int dump_device_info(struct atl_crash_dump *crash_dump) { char file_name[64]; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, DEV_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "Driver version: %s\n", crash_dump->drv_version); fprintf(file, "FW version: %s\n", crash_dump->fw_version); fclose(file); return 0; } int dump_registers(struct atl_crash_dump_regs *reg) { int block = 0x1000/4, i, offset; char file_name[64]; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, REG_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } /* Skip MIF block */ offset = block * 4; fprintf(file, "PCI Registers\n"); fprintf(file, "=============\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.pci[i]); offset += block * 4; fprintf(file, "\n\nInterrupt Registers\n"); fprintf(file, "=====================\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.itr[i]); offset += block * 4; fprintf(file, "\n\nCOM Registers\n"); fprintf(file, "===============\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.com[i]); offset += block * 4; fprintf(file, "\n\nMac Phy Registers\n"); fprintf(file, "=====================\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.mac_phy[i]); offset += block * 4; fprintf(file, "\n\nRx Registers\n"); fprintf(file, "===============\n"); /* Rx block size is 0x2000 */ for (i = 0; i < block * 2; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.rx[i]); offset += block * 2 * 4; fprintf(file, "\n\nTx Registers\n"); fprintf(file, "===============\n"); /* Tx block size is 0x2000 */ for (i = 0; i < block * 2; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.tx[i]); fclose(file); return 0; } int dump_fwiface(struct atl_crash_dump_fwiface *fwiface) { int block = 0x1000/4, i; char file_name[64]; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, FW_IFACE_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "FW input interface\n"); fprintf(file, "==================\n"); for (i = 0; i < block; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, fwiface->fw_interface_in[i], fwiface->fw_interface_in[i + 1], fwiface->fw_interface_in[i + 2], fwiface->fw_interface_in[i + 3]); fprintf(file, "\n\nFW output interface\n"); fprintf(file, "=======================\n"); for (i = 0; i < block; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, fwiface->fw_interface_out[i], fwiface->fw_interface_out[i + 1], fwiface->fw_interface_out[i + 2], fwiface->fw_interface_out[i + 3]); fclose(file); return 0; } int dump_act_res(struct atl_crash_dump_act_res *act_res) { char file_name[64]; int i, idx; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, ACT_RES_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "RECORD RESOLVER TAG TAG Mask Action\n"); fprintf(file, "==================================================\n"); for (i = 0, idx = 0; i < ATL_ACT_RES_TABLE_SIZE / 3; i++) { fprintf(file, "%d\t0x%08x\t0x%08x\t0x%08x\n", i, act_res->act_res_data[idx++], act_res->act_res_data[idx++], act_res->act_res_data[idx++]); } fclose(file); return 0; } int dump_ring(struct atl_crash_dump_ring *ring) { char file_name[64]; FILE *file; u32 *data; int i; /* Assumption - file 'rings.txt' shouldn't exists */ snprintf(file_name, 64, "%s/%s", out_folder, RING_FILE); file = fopen(file_name, "a+"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "Ring Index %d\n", ring->index); fprintf(file, "==============\n"); fprintf(file, "Rx head = 0x%08x tail = 0x%08x\n", ring->rx_head, ring->rx_tail); fprintf(file, "Tx head = 0x%08x tail = 0x%08x\n", ring->tx_head, ring->tx_tail); fprintf(file, "HW Ring rx_size = %d tx_size = %d\n", ring->rx_ring_size, ring->tx_ring_size); fprintf(file, "Rx Ring descriptor:\n"); fprintf(file, "-------------------\n"); data = (u32 *)ring->ring_data; for (i = 0; i < ring->rx_ring_size; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1], data[i + 2], data[i + 3]); fprintf(file, "Tx Ring descriptor:\n"); fprintf(file, "-------------------\n"); data = (u32 *)ring->ring_data + ring->rx_ring_size; for (i = 0; i < ring->tx_ring_size; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1], data[i + 2], data[i + 3]); fprintf(file, "\n"); fclose(file); return 0; } int main(int argc, char *argv[]) { struct atl_crash_dump *crash_dump; struct section_header *header; int i, offset, ret = 0; time_t t = time(NULL); struct tm *tm_val; FILE *input_file; struct stat st; char *buffer; if (argc < 2) { printf("No intput file\n"); return -1; } if (stat(argv[1], &st) == -1) { printf("File stat error\n"); return -1; } buffer = malloc(st.st_size); if (!buffer) { printf("Mem alloc error\n"); return -1; } /* open the source file for reading */ input_file = fopen(argv[1],"rb"); if (input_file == NULL) { ret = -1; printf("Error opening file %s\n", argv[1]); goto err; } fread(buffer, sizeof(char), st.st_size, input_file); fclose(input_file); tm_val = localtime(&t); tm_val = NULL; if (tm_val) snprintf(out_folder, 64, "%s_%02d-%02d-%02d_%02d-%02d-%02d", argv[1], tm_val->tm_mon + 1, (int) tm_val->tm_mday, 1900 + tm_val->tm_year, tm_val->tm_hour, tm_val->tm_min, tm_val->tm_sec); else snprintf(out_folder, 64, "%s_parsed", argv[1]); if (stat(out_folder, &st) == -1) { if (mkdir(out_folder, 0644) == -1) { ret = -1; printf("Failed to creat folder` %s\n", out_folder); goto err; } } crash_dump = (struct atl_crash_dump *)buffer; ret = dump_device_info(crash_dump); if (ret) goto err; offset = offsetof(struct atl_crash_dump, antigua); for (i = 0; i < crash_dump->sections_count; i++) { header = (struct section_header *)(buffer + offset); switch (header->type) { case atl_crash_dump_type_regs: ret = dump_registers((struct atl_crash_dump_regs *)(buffer + offset)); if (ret) goto err; break; case atl_crash_dump_type_fwiface: ret = dump_fwiface((struct atl_crash_dump_fwiface *)(buffer + offset)); if (ret) goto err; break; case atl_crash_dump_type_act_res: ret = dump_act_res((struct atl_crash_dump_act_res *)(buffer + offset)); if (ret) goto err; break; case atl_crash_dump_type_ring: ret = dump_ring((struct atl_crash_dump_ring *)(buffer + offset)); if (ret) goto err; break; default: printf("Parsing Error - invalid section\n"); goto err; } offset += header->length; } err: free(buffer); if (ret) printf("Failed to parse the dump\n"); else printf("Parsing is completed successfully\n"); return 0; } Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c +9 −0 Original line number Diff line number Diff line Loading @@ -973,6 +973,15 @@ int atl2_fw_init(struct atl_hw *hw) atl2_get_fw_version(hw); /* Warn if FW is lower than 1.3.1 */ if (((mcp->fw_rev >> 24) < 1) || (((mcp->fw_rev >> 16) & 0xFFU) < 3) || ((mcp->fw_rev & 0xFFFFU) < 1)) atl_dev_warn("FW_version: %u.%u.%u, is not stable version", (mcp->fw_rev >> 24), ((mcp->fw_rev >> 16) & 0xFFU), (mcp->fw_rev & 0xFFFFU)); mcp->ops = &atl2_fw_ops; atl_dev_dbg("Detect ATL2FW %x\n", mcp->fw_rev); Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +2 −15 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ #include <linux/netdevice.h> #include <linux/moduleparam.h> #define ATL_VERSION "1.1.18" #define ATL_VERSION "1.1.22" struct atl_nic; Loading @@ -32,8 +32,6 @@ struct atl_nic; #define ATL_MAX_QUEUES 8 #include "atl_fwd.h" struct atl_ptp; enum { Loading Loading @@ -414,6 +412,7 @@ void atl_update_global_stats(struct atl_nic *nic); void atl_set_loopback(struct atl_nic *nic, int idx, bool on); void atl_set_intr_mod(struct atl_nic *nic); void atl_update_ntuple_flt(struct atl_nic *nic, int idx); int atl_vlan_promisc_status(struct net_device *ndev); void atl_set_vlan_promisc(struct atl_hw *hw, int promisc); int atl_hwsem_get(struct atl_hw *hw, int idx); void atl_hwsem_put(struct atl_hw *hw, int idx); Loading @@ -424,18 +423,6 @@ int atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val); int atl_update_eth_stats(struct atl_nic *nic); void atl_adjust_eth_stats(struct atl_ether_stats *stats, struct atl_ether_stats *base, bool add); void atl_fwd_release_rings(struct atl_nic *nic); #if IS_ENABLED(CONFIG_ATLFWD_FWD) enum atl_fwd_notify; int atl_fwd_suspend_rings(struct atl_nic *nic); int atl_fwd_resume_rings(struct atl_nic *nic); void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data); #else static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; } static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } static inline void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data) {} #endif int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay); void atl_refresh_rxfs(struct atl_nic *nic); void atl_schedule_work(struct atl_nic *nic); Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump.h 0 → 100644 +123 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* Atlantic Network Driver * * Copyright (C) 2021 Marvell International Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef _ATL_DUMP_H_ #define _ATL_DUMP_H_ enum atl_crash_dump_types { atl_crash_dump_type_regs = 0, atl_crash_dump_type_fwiface = 1, atl_crash_dump_type_act_res = 2, atl_crash_dump_type_ring = 3, }; /** Some of the registers we can not read safely from the device. * Those will not be read, with value 0xFFFFFFFF stored instead. */ struct atl_crash_dump_regs { u32 type; u32 length; union { u32 regs_data[0x9000/4]; struct{ u32 mif[0x1000/4]; u32 pci[0x1000/4]; u32 itr[0x1000/4]; u32 com[0x1000/4]; u32 mac_phy[0x1000/4]; union { u32 rx[0x2000/4]; struct{ u32 res1[0x700/4]; u32 pb_ctrl; u32 res2; u32 pb_status; u32 res3; /* 0x5710 */ struct{ u32 pb_reg1; u32 pb_reg2; u32 pb_reg3; } pb[8]; u32 res4[0x100]; /* TODO */ /* 0x5B00 */ struct{ u32 base_lo; u32 base_hi; u32 ctrl; u32 head; u32 tail; u32 status; u32 size; u32 threshold; } dma_desc[32]; } layout; }; u32 tx[0x2000/4]; } layout; }; }; struct atl_crash_dump_fwiface { u32 type; u32 length; /* struct fw_interface_in */ u32 fw_interface_in[0x1000/4]; /* struct fw_interface_out */ u32 fw_interface_out[0x1000/4]; }; /* Record table size of 128 with each entry holding (tag, mask, action) */ #define ATL_ACT_RES_TABLE_SIZE 384 struct atl_crash_dump_act_res { u32 type; u32 length; u32 act_res_data[ATL_ACT_RES_TABLE_SIZE]; }; /* max_size = 'ring_size * (tx + rx) * 16 byte raw descriptor data' */ #define ATL_MAX_RING_DESC_SIZE ATL_MAX_RING_SIZE * 32 struct atl_crash_dump_ring { u32 type; u32 length; u32 index; u32 rx_head; u32 rx_tail; u32 tx_head; u32 tx_tail; u32 rx_ring_size; u32 tx_ring_size; u8 ring_data[ATL_MAX_RING_DESC_SIZE]; }; /* This is an extensible structure to collect various debug data from * AQC device */ struct atl_crash_dump { u32 length; /* total crash structure length, in bytes */ u32 sections_count; /* number of sections of type atl_crash_dump* following */ u8 drv_version[16]; u8 fw_version[16]; union { struct { struct atl_crash_dump_regs regs; struct atl_crash_dump_fwiface fwiface; struct atl_crash_dump_act_res act_res; struct atl_crash_dump_ring ring[ATL_MAX_QUEUES]; } antigua; struct { struct atl_crash_dump_regs regs; struct atl_crash_dump_ring ring[ATL_MAX_QUEUES]; } atlantic; }; }; #endif
drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/README 0 → 100644 +21 −0 Original line number Diff line number Diff line The tool atl_dump_parser is used to parse the register/device dump collected using "ethtool -d" command. Parser accepts dump in the binary format, hence the dump must be collected using 'raw' option i.e., 'ethtool -d <device> raw on' Use gcc to build the binary from sources, gcc -o atl_dump_parser atl_dump_parser.c Example: -------- 1. Collect ethtool dump from SUT machine #ethtool -d enp1s0 raw on > ethd_dump 2. Parse the dump #ls atl_dump_parser ethd_dump #./atl_dump_parser ethd_dump Parsing is completed successfully #ls ethd_dump_parsed action_resolver.txt atl_dump_parser ethd_dump fw_interface.txt registers.txt rings.txt # Parsed data will be copied to the text files under <input_file>_parsed folder.
drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.c 0 → 100644 +296 −0 Original line number Diff line number Diff line #include <stdio.h> #include <stddef.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <time.h> #include "atl_dump_parser.h" #include "../atl_dump.h" #define DEV_FILE "device.txt" #define REG_FILE "registers.txt" #define FW_IFACE_FILE "fw_interface.txt" #define ACT_RES_FILE "action_resolver.txt" #define RING_FILE "rings.txt" struct section_header { u32 type; u32 length; }; char out_folder[64]; int dump_device_info(struct atl_crash_dump *crash_dump) { char file_name[64]; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, DEV_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "Driver version: %s\n", crash_dump->drv_version); fprintf(file, "FW version: %s\n", crash_dump->fw_version); fclose(file); return 0; } int dump_registers(struct atl_crash_dump_regs *reg) { int block = 0x1000/4, i, offset; char file_name[64]; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, REG_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } /* Skip MIF block */ offset = block * 4; fprintf(file, "PCI Registers\n"); fprintf(file, "=============\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.pci[i]); offset += block * 4; fprintf(file, "\n\nInterrupt Registers\n"); fprintf(file, "=====================\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.itr[i]); offset += block * 4; fprintf(file, "\n\nCOM Registers\n"); fprintf(file, "===============\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.com[i]); offset += block * 4; fprintf(file, "\n\nMac Phy Registers\n"); fprintf(file, "=====================\n"); for (i = 0; i < block; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.mac_phy[i]); offset += block * 4; fprintf(file, "\n\nRx Registers\n"); fprintf(file, "===============\n"); /* Rx block size is 0x2000 */ for (i = 0; i < block * 2; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.rx[i]); offset += block * 2 * 4; fprintf(file, "\n\nTx Registers\n"); fprintf(file, "===============\n"); /* Tx block size is 0x2000 */ for (i = 0; i < block * 2; i++) fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.tx[i]); fclose(file); return 0; } int dump_fwiface(struct atl_crash_dump_fwiface *fwiface) { int block = 0x1000/4, i; char file_name[64]; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, FW_IFACE_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "FW input interface\n"); fprintf(file, "==================\n"); for (i = 0; i < block; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, fwiface->fw_interface_in[i], fwiface->fw_interface_in[i + 1], fwiface->fw_interface_in[i + 2], fwiface->fw_interface_in[i + 3]); fprintf(file, "\n\nFW output interface\n"); fprintf(file, "=======================\n"); for (i = 0; i < block; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, fwiface->fw_interface_out[i], fwiface->fw_interface_out[i + 1], fwiface->fw_interface_out[i + 2], fwiface->fw_interface_out[i + 3]); fclose(file); return 0; } int dump_act_res(struct atl_crash_dump_act_res *act_res) { char file_name[64]; int i, idx; FILE *file; snprintf(file_name, 64, "%s/%s", out_folder, ACT_RES_FILE); file = fopen(file_name, "w"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "RECORD RESOLVER TAG TAG Mask Action\n"); fprintf(file, "==================================================\n"); for (i = 0, idx = 0; i < ATL_ACT_RES_TABLE_SIZE / 3; i++) { fprintf(file, "%d\t0x%08x\t0x%08x\t0x%08x\n", i, act_res->act_res_data[idx++], act_res->act_res_data[idx++], act_res->act_res_data[idx++]); } fclose(file); return 0; } int dump_ring(struct atl_crash_dump_ring *ring) { char file_name[64]; FILE *file; u32 *data; int i; /* Assumption - file 'rings.txt' shouldn't exists */ snprintf(file_name, 64, "%s/%s", out_folder, RING_FILE); file = fopen(file_name, "a+"); if (file == NULL) { printf("Error opening file %s\n", file_name); return -1; } fprintf(file, "Ring Index %d\n", ring->index); fprintf(file, "==============\n"); fprintf(file, "Rx head = 0x%08x tail = 0x%08x\n", ring->rx_head, ring->rx_tail); fprintf(file, "Tx head = 0x%08x tail = 0x%08x\n", ring->tx_head, ring->tx_tail); fprintf(file, "HW Ring rx_size = %d tx_size = %d\n", ring->rx_ring_size, ring->tx_ring_size); fprintf(file, "Rx Ring descriptor:\n"); fprintf(file, "-------------------\n"); data = (u32 *)ring->ring_data; for (i = 0; i < ring->rx_ring_size; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1], data[i + 2], data[i + 3]); fprintf(file, "Tx Ring descriptor:\n"); fprintf(file, "-------------------\n"); data = (u32 *)ring->ring_data + ring->rx_ring_size; for (i = 0; i < ring->tx_ring_size; i += 4) fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1], data[i + 2], data[i + 3]); fprintf(file, "\n"); fclose(file); return 0; } int main(int argc, char *argv[]) { struct atl_crash_dump *crash_dump; struct section_header *header; int i, offset, ret = 0; time_t t = time(NULL); struct tm *tm_val; FILE *input_file; struct stat st; char *buffer; if (argc < 2) { printf("No intput file\n"); return -1; } if (stat(argv[1], &st) == -1) { printf("File stat error\n"); return -1; } buffer = malloc(st.st_size); if (!buffer) { printf("Mem alloc error\n"); return -1; } /* open the source file for reading */ input_file = fopen(argv[1],"rb"); if (input_file == NULL) { ret = -1; printf("Error opening file %s\n", argv[1]); goto err; } fread(buffer, sizeof(char), st.st_size, input_file); fclose(input_file); tm_val = localtime(&t); tm_val = NULL; if (tm_val) snprintf(out_folder, 64, "%s_%02d-%02d-%02d_%02d-%02d-%02d", argv[1], tm_val->tm_mon + 1, (int) tm_val->tm_mday, 1900 + tm_val->tm_year, tm_val->tm_hour, tm_val->tm_min, tm_val->tm_sec); else snprintf(out_folder, 64, "%s_parsed", argv[1]); if (stat(out_folder, &st) == -1) { if (mkdir(out_folder, 0644) == -1) { ret = -1; printf("Failed to creat folder` %s\n", out_folder); goto err; } } crash_dump = (struct atl_crash_dump *)buffer; ret = dump_device_info(crash_dump); if (ret) goto err; offset = offsetof(struct atl_crash_dump, antigua); for (i = 0; i < crash_dump->sections_count; i++) { header = (struct section_header *)(buffer + offset); switch (header->type) { case atl_crash_dump_type_regs: ret = dump_registers((struct atl_crash_dump_regs *)(buffer + offset)); if (ret) goto err; break; case atl_crash_dump_type_fwiface: ret = dump_fwiface((struct atl_crash_dump_fwiface *)(buffer + offset)); if (ret) goto err; break; case atl_crash_dump_type_act_res: ret = dump_act_res((struct atl_crash_dump_act_res *)(buffer + offset)); if (ret) goto err; break; case atl_crash_dump_type_ring: ret = dump_ring((struct atl_crash_dump_ring *)(buffer + offset)); if (ret) goto err; break; default: printf("Parsing Error - invalid section\n"); goto err; } offset += header->length; } err: free(buffer); if (ret) printf("Failed to parse the dump\n"); else printf("Parsing is completed successfully\n"); return 0; }