From 845960fc1b15995fdbd6d61c384567652a150bc4 Mon Sep 17 00:00:00 2001 From: Benjamin Hadad IV Date: Fri, 28 Jul 2023 11:39:28 -0400 Subject: Refactored various systems and debugged minor issues - Added device_info_iter - Merged functions in device_info_procfs.c - Separated device_info data structs by version in nvdebug.h - Fixed issue with device_info runlist ID data --- device_info_procfs.c | 110 ++++++++++++++++++++++----------------------------- nvdebug.h | 34 +++++++++------- nvdebug_entry.c | 6 +-- 3 files changed, 69 insertions(+), 81 deletions(-) diff --git a/device_info_procfs.c b/device_info_procfs.c index 3cf4bc9..5ddf240 100644 --- a/device_info_procfs.c +++ b/device_info_procfs.c @@ -27,61 +27,57 @@ struct file_operations nvdebug_read_reg32_file_ops = { .llseek = default_llseek, }; +typedef struct { + int total_entries; + int index; + int type_of_next_entry; +} device_info_iter; + //// ==v== PTOP_DEVICE_INFO ==v== //// +static void* device_info_seq_start_backend(struct seq_file *s, loff_t *pos, int initial_entry_value, int total_entries) { + static device_info_iter idx; + // If start of sequence, reset `idx` + if (*pos == 0) { + idx.index = 0; + idx.type_of_next_entry = initial_entry_value; + } + idx.total_entries = total_entries; + // Number of possible info entries is fixed, and list is sparse + if (idx.index >= idx.total_entries) + return NULL; + return &idx; +} + // Called to start or resume a sequence. Prior to 4.19, *pos is unreliable. // Initializes iterator `idx` state and returns it. Ends sequence on NULL. static void* device_info_file_seq_start_previous(struct seq_file *s, loff_t *pos) { - static int idx; - // If start of sequence, reset `idx` - if (*pos == 0) - idx = 0; - // Number of possible info entries is fixed, and list is sparse - if (idx >= NV_PTOP_DEVICE_INFO__SIZE_1_PREVIOUS) - return NULL; - return &idx; + return device_info_seq_start_backend(s, pos, -1, NV_PTOP_DEVICE_INFO__SIZE_1_PREVIOUS); } static void* device_info_file_seq_start_ampere(struct seq_file *s, loff_t *pos) { - static int idx; - // If start of sequence, reset `idx` - if (*pos == 0) - idx = 0; - struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)]; - // Number of possible info entries is fixed, and list is sparse - if (idx >= NV_PTOP_DEVICE_INFO__SIZE_1_AMPERE(g)) - return NULL; - return &idx; + struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)]; + return device_info_seq_start_backend(s, pos, 0, NV_PTOP_DEVICE_INFO__SIZE_1_AMPERE(g)); } // Steps to next record. Returns new value of `idx`. // Calls show() on non-NULL return -static void* device_info_file_seq_next_previous(struct seq_file *s, void *idx, +static void* device_info_file_seq_next(struct seq_file *s, void *idx, loff_t *pos) { + device_info_iter *idx_iter = (device_info_iter*)idx; (*pos)++; // Required by seq interface // Number of possible info entries is fixed, and list is sparse - if ((*(int*)idx)++ >= NV_PTOP_DEVICE_INFO__SIZE_1_PREVIOUS) + if (idx_iter->index++ >= idx_iter->total_entries) return NULL; return idx; } -// Steps to next record. Returns new value of `idx`. -// Calls show() on non-NULL return -static void* device_info_file_seq_next_ampere(struct seq_file *s, void *idx, - loff_t *pos) { - (*pos)++; // Required by seq interface - // Number of possible info entries is fixed, and list is sparse - struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)]; - if ((*(int*)idx)++ >= NV_PTOP_DEVICE_INFO__SIZE_1_AMPERE(g)) - return NULL; - return idx; -} - // Print info at index *idx. Returns non-zero on error. static int device_info_file_seq_show_previous(struct seq_file *s, void *idx) { - ptop_device_info_t curr_info; + device_info_iter *idx_iter = (device_info_iter*)idx; + ptop_device_info_previous_t curr_info; struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)]; - curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_PREVIOUS(*(int*)idx)); + curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_PREVIOUS(idx_iter->index)); // Check for read errors if (curr_info.raw == -1) return -EIO; @@ -129,54 +125,42 @@ static int device_info_file_seq_show_previous(struct seq_file *s, void *idx) { // Print info at index *idx for Ampere GPUs. Returns non-zero on error. static int device_info_file_seq_show_ampere(struct seq_file *s, void *idx) { - ptop_device_info_t curr_info; + device_info_iter *idx_iter = (device_info_iter*)idx; + ptop_device_info_ampere_t curr_info; struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)]; - curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx)); + curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(idx_iter->index)); // Check for read errors if (curr_info.raw == -1) return -EIO; // The info_type field is not available in the Ampere device_info data, so it must be inferred - int info_type = -1; - if(curr_info.raw) { - for(int i = 0; i < NV_PTOP_DEVICE_INFO_TYPE_COUNT; i++) { - if(*(int*)idx == i) { - info_type = i; - break; - } - ptop_device_info_t prev_info; - prev_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx - i - 1)); - if(!prev_info.raw || !prev_info.has_next_entry_ampere) { - info_type = i; - break; - } - } - } + int info_type = curr_info.raw ? idx_iter->type_of_next_entry : -1; // Parse and print the data switch(info_type) { case 0: - seq_printf(s, "| instance %d\n", curr_info.inst_id_ampere); - seq_printf(s, "| Fault ID: %3d\n", curr_info.fault_id_ampere); - seq_printf(s, "| Engine Type: %2d (", curr_info.engine_type_ampere); - if (curr_info.engine_type_ampere < ENGINE_TYPES_LEN) - seq_printf(s, "%s)\n", ENGINE_TYPES_NAMES[curr_info.engine_type_ampere]); + seq_printf(s, "| instance %d\n", curr_info.inst_id); + seq_printf(s, "| Fault ID: %3d\n", curr_info.fault_id); + seq_printf(s, "| Engine Type: %2d (", curr_info.engine_type); + if (curr_info.engine_type < ENGINE_TYPES_LEN) + seq_printf(s, "%s)\n", ENGINE_TYPES_NAMES[curr_info.engine_type]); else seq_printf(s, "Unknown Engine, introduced post-Ampere)\n"); break; case 1: - seq_printf(s, "| BAR0 Base %#.8x\n", curr_info.pri_base_ampere << 12); - seq_printf(s, "| Reset ID: %2d\n", curr_info.reset_enum_ampere); + seq_printf(s, "| BAR0 Base %#.8x\n", curr_info.pri_base << 12); + seq_printf(s, "| Reset ID: %2d\n", curr_info.reset_enum); break; case 2: - seq_printf(s, "| Host's Engine ID: %2d\n", curr_info.engine_enum_ampere); - seq_printf(s, "| Runlist ID: %2d\n", curr_info.runlist_enum_ampere); + seq_printf(s, "| Host's Engine ID: %2d\n", curr_info.engine_enum); + seq_printf(s, "| Runlist ID: %2d\n", curr_info.runlist_enum); break; default: // Device info records are sparse, so skip unset or unknown ones return 0; } - + if(info_type != -1) idx_iter->type_of_next_entry++; // Draw a line between each device entry - if (!curr_info.has_next_entry_ampere) { + if (!curr_info.has_next_entry) { + idx_iter->type_of_next_entry = 0; seq_printf(s, "+---------------------+\n"); } return 0; @@ -189,14 +173,14 @@ static void device_info_file_seq_stop(struct seq_file *s, void *idx) { static const struct seq_operations device_info_file_seq_ops_previous = { .start = device_info_file_seq_start_previous, - .next = device_info_file_seq_next_previous, + .next = device_info_file_seq_next, .stop = device_info_file_seq_stop, .show = device_info_file_seq_show_previous, }; static const struct seq_operations device_info_file_seq_ops_ampere = { .start = device_info_file_seq_start_ampere, - .next = device_info_file_seq_next_ampere, + .next = device_info_file_seq_next, .stop = device_info_file_seq_stop, .show = device_info_file_seq_show_ampere, }; diff --git a/nvdebug.h b/nvdebug.h index d6b7358..c45e460 100644 --- a/nvdebug.h +++ b/nvdebug.h @@ -567,25 +567,29 @@ static const char* const ENGINE_TYPES_NAMES[ENGINE_TYPES_LEN] = { #define NV_PTOP_DEVICE_INFO_TYPE_COUNT 3 typedef union { struct { - uint32_t fault_id_ampere:7; - uint32_t padding0_ampere:9; - uint32_t inst_id_ampere:4; - uint32_t padding1_ampere:4; - enum ENGINE_TYPES engine_type_ampere:7; - bool has_next_entry_ampere:1; + uint32_t fault_id:7; + uint32_t padding0:9; + uint32_t inst_id:4; + uint32_t padding1:4; + enum ENGINE_TYPES engine_type:7; + bool has_next_entry:1; } __attribute__((packed)); struct { - uint32_t reset_enum_ampere:5; - uint32_t padding2_ampere:7; - uint32_t pri_base_ampere:12; - uint32_t padding3_ampere:8; + uint32_t reset_enum:5; + uint32_t padding2:7; + uint32_t pri_base:12; + uint32_t padding3:8; } __attribute__((packed)); struct { - uint32_t engine_enum_ampere:2; - uint32_t padding4_ampere:4; - uint32_t runlist_enum_ampere:14; - uint32_t padding5_ampere:12; + uint32_t engine_enum:2; + uint32_t padding4:8; + uint32_t runlist_enum:14; + uint32_t padding5:8; } __attribute__((packed)); + uint32_t raw; +} ptop_device_info_ampere_t; + +typedef union { // DATA type fields struct { enum DEVICE_INFO_TYPE info_type:2; @@ -622,7 +626,7 @@ typedef union { uint32_t padding9:1; } __attribute__((packed)); uint32_t raw; -} ptop_device_info_t; +} ptop_device_info_previous_t; #define NV_PTOP_SCAL_NUM_GPCS 0x00022430 #define NV_PTOP_SCAL_NUM_TPC_PER_GPC 0x00022434 diff --git a/nvdebug_entry.c b/nvdebug_entry.c index 3dfe1e8..d3d934e 100644 --- a/nvdebug_entry.c +++ b/nvdebug_entry.c @@ -142,7 +142,7 @@ int probe_and_cache_device(void) { // Create files `/proc/gpu#/runlist#`, world readable int create_runlist_files_previous(int device_id, struct proc_dir_entry *dir) { - ptop_device_info_t info; + ptop_device_info_previous_t info; struct proc_dir_entry *rl_entry; int i, rl_id; char runlist_name[12]; @@ -172,7 +172,7 @@ int create_runlist_files_previous(int device_id, struct proc_dir_entry *dir) { // Create files `/proc/gpu#/runlist#`, world readable int create_runlist_files_ampere(int device_id, struct proc_dir_entry *dir) { - ptop_device_info_t info; + ptop_device_info_ampere_t info; struct proc_dir_entry *rl_entry; int i, rl_id; char runlist_name[12]; @@ -182,7 +182,7 @@ int create_runlist_files_ampere(int device_id, struct proc_dir_entry *dir) { // to find the highest-valued one and add 1 to get the number of runlists. for (i = 0; i < NV_PTOP_DEVICE_INFO__SIZE_1_AMPERE(&g_nvdebug_state[device_id]); i++) { info.raw = nvdebug_readl(&g_nvdebug_state[device_id], NV_PTOP_DEVICE_INFO_AMPERE(i)); - if (info.runlist_enum_ampere > max_rl_id) + if (info.runlist_enum > max_rl_id) max_rl_id = info.runlist_enum; } // Create files to read each runlist. The read handling code looks at the -- cgit v1.2.2