aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Hadad IV <bh4@unc.edu>2023-07-13 12:13:17 -0400
committerBenjamin Hadad IV <bh4@unc.edu>2023-07-13 12:13:17 -0400
commitbfb4dcf0e78954c0163f3a06a5a088c4d1b437a8 (patch)
tree5288dc03523647f01d9952557b282b1019daa774
parent068e7f4e7208d6c9250ad72208e0b36fd9fdf2f6 (diff)
This commit is to update the repo for display during a meeting.
- Added an Ampere version of the device info data. - Added Ampere versions of auxillary functions. - Modified display functions to accommodate Ampere data. - Made other various small modifications.
-rw-r--r--device_info_procfs.c140
-rw-r--r--nvdebug.h37
-rw-r--r--nvdebug_entry.c41
3 files changed, 179 insertions, 39 deletions
diff --git a/device_info_procfs.c b/device_info_procfs.c
index 1fc0586..b1e58b1 100644
--- a/device_info_procfs.c
+++ b/device_info_procfs.c
@@ -31,7 +31,7 @@ struct file_operations nvdebug_read_reg32_file_ops = {
31 31
32// Called to start or resume a sequence. Prior to 4.19, *pos is unreliable. 32// Called to start or resume a sequence. Prior to 4.19, *pos is unreliable.
33// Initializes iterator `idx` state and returns it. Ends sequence on NULL. 33// Initializes iterator `idx` state and returns it. Ends sequence on NULL.
34static void* device_info_file_seq_start(struct seq_file *s, loff_t *pos) { 34static void* device_info_file_seq_start_previous(struct seq_file *s, loff_t *pos) {
35 static int idx; 35 static int idx;
36 // If start of sequence, reset `idx` 36 // If start of sequence, reset `idx`
37 if (*pos == 0) 37 if (*pos == 0)
@@ -42,9 +42,21 @@ static void* device_info_file_seq_start(struct seq_file *s, loff_t *pos) {
42 return &idx; 42 return &idx;
43} 43}
44 44
45static void* device_info_file_seq_start_ampere(struct seq_file *s, loff_t *pos) {
46 static int idx;
47 // If start of sequence, reset `idx`
48 if (*pos == 0)
49 idx = 0;
50 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)];
51 // Number of possible info entries is fixed, and list is sparse
52 if (idx >= (nvdebug_readl(g, 0x0224fc) >> 20))
53 return NULL;
54 return &idx;
55}
56
45// Steps to next record. Returns new value of `idx`. 57// Steps to next record. Returns new value of `idx`.
46// Calls show() on non-NULL return 58// Calls show() on non-NULL return
47static void* device_info_file_seq_next(struct seq_file *s, void *idx, 59static void* device_info_file_seq_next_previous(struct seq_file *s, void *idx,
48 loff_t *pos) { 60 loff_t *pos) {
49 (*pos)++; // Required by seq interface 61 (*pos)++; // Required by seq interface
50 // Number of possible info entries is fixed, and list is sparse 62 // Number of possible info entries is fixed, and list is sparse
@@ -53,12 +65,50 @@ static void* device_info_file_seq_next(struct seq_file *s, void *idx,
53 return idx; 65 return idx;
54} 66}
55 67
68// Steps to next record. Returns new value of `idx`.
69// Calls show() on non-NULL return
70static void* device_info_file_seq_next_ampere(struct seq_file *s, void *idx,
71 loff_t *pos) {
72 (*pos)++; // Required by seq interface
73 // Number of possible info entries is fixed, and list is sparse
74 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)];
75 if ((*(int*)idx)++ >= (nvdebug_readl(g, 0x0224fc) >> 20))
76 return NULL;
77 return idx;
78}
79/*
80// Steps to next record on Ampere GPUs. Returns new value of `idx`.
81static void* device_info_file_seq_next_ampere(struct seq_file *s, void *idx,
82 loff_t *pos) {
83 (*pos)++; // Required by seq interface
84 // Number of possible info entries is fixed, and list is sparse
85 while(1) {
86 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)];
87 if ((*(int*)idx)++ >= (nvdebug_readl(g, 0x0224fc) >> 20))
88 return NULL;
89 ptop_device_info_t curr_info;
90 curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx));
91 if(!curr_info.raw && !*info_type) continue;
92 (*info_type)++;
93 break;
94 }
95 while(1) {
96 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)];
97 if ((*(int*)idx)++ >= (nvdebug_readl(g, 0x0224fc) >> 20))
98 return NULL;
99 ptop_device_info_t curr_info;
100 curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx));
101 if(curr_info.raw & 0x80000000) continue;
102 break;
103 }
104 return idx;
105}
106*/
56// Print info at index *idx. Returns non-zero on error. 107// Print info at index *idx. Returns non-zero on error.
57static int device_info_file_seq_show(struct seq_file *s, void *idx) { 108static int device_info_file_seq_show_previous(struct seq_file *s, void *idx) {
58 ptop_device_info_t curr_info; 109 ptop_device_info_t curr_info;
59 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)]; 110 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)];
60 111 curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_PREVIOUS(*(int*)idx));
61 curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO(*(int*)idx));
62 // Check for read errors 112 // Check for read errors
63 if (curr_info.raw == -1) 113 if (curr_info.raw == -1)
64 return -EIO; 114 return -EIO;
@@ -104,24 +154,88 @@ static int device_info_file_seq_show(struct seq_file *s, void *idx) {
104 return 0; 154 return 0;
105} 155}
106 156
157// Print info at index *idx for Ampere GPUs. Returns non-zero on error.
158static int device_info_file_seq_show_ampere(struct seq_file *s, void *idx) {
159 ptop_device_info_t curr_info;
160 struct nvdebug_state *g = &g_nvdebug_state[seq2gpuidx(s)];
161 curr_info.raw = nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx));
162 // Check for read errors
163 if (curr_info.raw == -1)
164 return -EIO;
165 int info_type = -1;
166 if(curr_info.raw) {
167 if(*(int*)idx < 1 || !nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx) - 1)) info_type = 0;
168 if(*(int*)idx < 2 || !nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx) - 2)) info_type = 1;
169 if(*(int*)idx < 3 || !nvdebug_readl(g, NV_PTOP_DEVICE_INFO_AMPERE(*(int*)idx) - 3)) info_type = 2;
170 }
171 // Parse and print the data
172 switch(info_type) {
173 case 0:
174 seq_printf(s, "| instance %d\n", curr_info.inst_id_ampere);
175 seq_printf(s, "| Fault ID: %3d\n", curr_info.fault_id_ampere);
176 seq_printf(s, "| Engine Type: %2d (", curr_info.engine_type_ampere);
177 if (curr_info.engine_type_ampere < ENGINE_TYPES_LEN)
178 seq_printf(s, "%s)\n", ENGINE_TYPES_NAMES[curr_info.engine_type_ampere]);
179 else
180 seq_printf(s, "Unknown Engine, introduced post-Ampere)\n");
181 break;
182 case 1:
183 seq_printf(s, "| BAR0 Base %#.8x\n", curr_info.pri_base_ampere << 12);
184 seq_printf(s, "| Reset ID: %2d\n", curr_info.reset_enum_ampere);
185 break;
186 case 2:
187 seq_printf(s, "| Host's Engine ID: %2d\n", curr_info.engine_enum_ampere);
188 seq_printf(s, "| Runlist ID: %2d\n", curr_info.runlist_enum_ampere);
189 break;
190 default:
191 // Device info records are sparse, so skip unset or unknown ones
192 return 0;
193 }
194
195 // Draw a line between each device entry
196 if (!curr_info.has_next_entry_ampere) {
197 seq_printf(s, "+---------------------+\n");
198 }
199 return 0;
200}
201
202
107static void device_info_file_seq_stop(struct seq_file *s, void *idx) { 203static void device_info_file_seq_stop(struct seq_file *s, void *idx) {
108 // No cleanup needed 204 // No cleanup needed
109} 205}
110 206
111static const struct seq_operations device_info_file_seq_ops = { 207static const struct seq_operations device_info_file_seq_ops_previous = {
112 .start = device_info_file_seq_start, 208 .start = device_info_file_seq_start_previous,
113 .next = device_info_file_seq_next, 209 .next = device_info_file_seq_next_previous,
114 .stop = device_info_file_seq_stop, 210 .stop = device_info_file_seq_stop,
115 .show = device_info_file_seq_show, 211 .show = device_info_file_seq_show_previous,
212};
213
214static const struct seq_operations device_info_file_seq_ops_ampere = {
215 .start = device_info_file_seq_start_ampere,
216 .next = device_info_file_seq_next_ampere,
217 .stop = device_info_file_seq_stop,
218 .show = device_info_file_seq_show_ampere,
116}; 219};
117 220
118static int device_info_file_open(struct inode *inode, struct file *f) { 221static int device_info_file_open_previous(struct inode *inode, struct file *f) {
119 return seq_open(f, &device_info_file_seq_ops); 222 return seq_open(f, &device_info_file_seq_ops_previous);
120} 223}
121 224
122struct file_operations device_info_file_ops = { 225static int device_info_file_open_ampere(struct inode *inode, struct file *f) {
123 .open = device_info_file_open, 226 return seq_open(f, &device_info_file_seq_ops_ampere);
227}
228
229struct file_operations device_info_file_ops_previous = {
230 .open = device_info_file_open_previous,
124 .read = seq_read, 231 .read = seq_read,
125 .llseek = seq_lseek, 232 .llseek = seq_lseek,
126 .release = seq_release, 233 .release = seq_release,
127}; 234};
235
236struct file_operations device_info_file_ops_ampere = {
237 .open = device_info_file_open_ampere,
238 .read = seq_read,
239 .llseek = seq_lseek,
240 .release = seq_release,
241};
diff --git a/nvdebug.h b/nvdebug.h
index f6e057e..3ccdcfe 100644
--- a/nvdebug.h
+++ b/nvdebug.h
@@ -554,34 +554,30 @@ static const char* const ENGINE_TYPES_NAMES[ENGINE_TYPES_LEN] = {
554 See dev_top.ref.txt of NVIDIA's open-gpu-doc for more info. 554 See dev_top.ref.txt of NVIDIA's open-gpu-doc for more info.
555*/ 555*/
556 556
557#ifdef NV_BUILD_FOR_AMPERE 557#define NV_PTOP_DEVICE_INFO_AMPERE(i) (0x00022800+(i)*4)
558#define NV_PTOP_DEVICE_INFO(i) (0x00022800+(i)*4) 558#define NV_PTOP_DEVICE_INFO_PREVIOUS(i) (0x00022700+(i)*4)
559#define NV_PTOP_DEVICE_INFO__SIZE_1 64 559#define NV_PTOP_DEVICE_INFO__SIZE_1 64
560typedef union { 560typedef union {
561 struct { 561 struct {
562 uint32_t fault_id:7; 562 uint32_t fault_id_ampere:7;
563 uint32_t padding0:9; 563 uint32_t padding0_ampere:9;
564 uint32_t inst_id:4; 564 uint32_t inst_id_ampere:4;
565 uint32_t padding1:4; 565 uint32_t padding1_ampere:4;
566 enum ENGINE_TYPES engine_type:7; 566 enum ENGINE_TYPES engine_type_ampere:7;
567 bool has_next_entry:1; 567 bool has_next_entry_ampere:1;
568 } __attribute__((packed)); 568 } __attribute__((packed));
569 struct { 569 struct {
570 uint32_t reset_enum:5; 570 uint32_t reset_enum_ampere:5;
571 uint32_t padding2:7; 571 uint32_t padding2_ampere:7;
572 uint32_t pri_base:12; 572 uint32_t pri_base_ampere:12;
573 uint32_t padding3_ampere:8;
573 } __attribute__((packed)); 574 } __attribute__((packed));
574 struct { 575 struct {
575 uint32_t engine_enum:2; 576 uint32_t engine_enum_ampere:2;
576 uint32_t padding3:4; 577 uint32_t padding4_ampere:4;
577 uint32_t runlist_enum:14; 578 uint32_t runlist_enum_ampere:14;
579 uint32_t padding5_ampere:12;
578 } __attribute__((packed)); 580 } __attribute__((packed));
579 uint32_t raw;
580} ptop_device_info_t;
581#else
582#define NV_PTOP_DEVICE_INFO(i) (0x00022700+(i)*4)
583#define NV_PTOP_DEVICE_INFO__SIZE_1 64
584typedef union {
585 // DATA type fields 581 // DATA type fields
586 struct { 582 struct {
587 enum DEVICE_INFO_TYPE info_type:2; 583 enum DEVICE_INFO_TYPE info_type:2;
@@ -619,7 +615,6 @@ typedef union {
619 } __attribute__((packed)); 615 } __attribute__((packed));
620 uint32_t raw; 616 uint32_t raw;
621} ptop_device_info_t; 617} ptop_device_info_t;
622#endif
623 618
624#define NV_PTOP_SCAL_NUM_GPCS 0x00022430 619#define NV_PTOP_SCAL_NUM_GPCS 0x00022430
625#define NV_PTOP_SCAL_NUM_TPC_PER_GPC 0x00022434 620#define NV_PTOP_SCAL_NUM_TPC_PER_GPC 0x00022434
diff --git a/nvdebug_entry.c b/nvdebug_entry.c
index 8e8266c..d82c648 100644
--- a/nvdebug_entry.c
+++ b/nvdebug_entry.c
@@ -23,12 +23,14 @@ extern struct file_operations preempt_tsg_file_ops;
23extern struct file_operations disable_channel_file_ops; 23extern struct file_operations disable_channel_file_ops;
24extern struct file_operations enable_channel_file_ops; 24extern struct file_operations enable_channel_file_ops;
25extern struct file_operations switch_to_tsg_file_ops; 25extern struct file_operations switch_to_tsg_file_ops;
26extern struct file_operations device_info_file_ops; 26extern struct file_operations device_info_file_ops_previous;
27extern struct file_operations device_info_file_ops_ampere;
27extern struct file_operations nvdebug_read_reg32_file_ops; 28extern struct file_operations nvdebug_read_reg32_file_ops;
28 29
29// Bus types are global symbols in the kernel 30// Bus types are global symbols in the kernel
30extern struct bus_type platform_bus_type; 31extern struct bus_type platform_bus_type;
31struct nvdebug_state g_nvdebug_state[NVDEBUG_MAX_DEVICES]; 32struct nvdebug_state g_nvdebug_state[NVDEBUG_MAX_DEVICES];
33int g_architectures[NVDEBUG_MAX_DEVICES];
32unsigned int g_nvdebug_devices = 0; 34unsigned int g_nvdebug_devices = 0;
33 35
34// Starting in Kernel 5.6, proc_ops is required instead of file_operations 36// Starting in Kernel 5.6, proc_ops is required instead of file_operations
@@ -123,6 +125,7 @@ int probe_and_cache_device(void) {
123 return -EADDRNOTAVAIL; 125 return -EADDRNOTAVAIL;
124 } 126 }
125 g_nvdebug_state[i].chip_id = ids.chip_id; 127 g_nvdebug_state[i].chip_id = ids.chip_id;
128 g_architectures[i] = ids.architecture;
126 printk(KERN_INFO "[nvdebug] Chip ID %x (architecture %s) detected on PCI bus and initialized.", 129 printk(KERN_INFO "[nvdebug] Chip ID %x (architecture %s) detected on PCI bus and initialized.",
127 ids.chip_id, ARCH2NAME(ids.architecture)); 130 ids.chip_id, ARCH2NAME(ids.architecture));
128 // TEMP 131 // TEMP
@@ -138,7 +141,7 @@ int probe_and_cache_device(void) {
138} 141}
139 142
140// Create files `/proc/gpu#/runlist#`, world readable 143// Create files `/proc/gpu#/runlist#`, world readable
141int create_runlist_files(int device_id, struct proc_dir_entry *dir) { 144int create_runlist_files_previous(int device_id, struct proc_dir_entry *dir) {
142 ptop_device_info_t info; 145 ptop_device_info_t info;
143 struct proc_dir_entry *rl_entry; 146 struct proc_dir_entry *rl_entry;
144 int i, rl_id; 147 int i, rl_id;
@@ -148,7 +151,7 @@ int create_runlist_files(int device_id, struct proc_dir_entry *dir) {
148 // registers. Runlists are always numbered sequentially, so we just have 151 // registers. Runlists are always numbered sequentially, so we just have
149 // to find the highest-valued one and add 1 to get the number of runlists. 152 // to find the highest-valued one and add 1 to get the number of runlists.
150 for (i = 0; i < NV_PTOP_DEVICE_INFO__SIZE_1; i++) { 153 for (i = 0; i < NV_PTOP_DEVICE_INFO__SIZE_1; i++) {
151 info.raw = nvdebug_readl(&g_nvdebug_state[device_id], NV_PTOP_DEVICE_INFO(i)); 154 info.raw = nvdebug_readl(&g_nvdebug_state[device_id], NV_PTOP_DEVICE_INFO_PREVIOUS(i));
152 if (info.info_type != INFO_TYPE_ENUM || !info.runlist_is_valid) 155 if (info.info_type != INFO_TYPE_ENUM || !info.runlist_is_valid)
153 continue; 156 continue;
154 if (info.runlist_enum > max_rl_id) 157 if (info.runlist_enum > max_rl_id)
@@ -167,6 +170,34 @@ int create_runlist_files(int device_id, struct proc_dir_entry *dir) {
167 return 0; 170 return 0;
168} 171}
169 172
173// Create files `/proc/gpu#/runlist#`, world readable
174int create_runlist_files_ampere(int device_id, struct proc_dir_entry *dir) {
175 ptop_device_info_t info;
176 struct proc_dir_entry *rl_entry;
177 int i, rl_id;
178 char runlist_name[12];
179 int max_rl_id = 0; // Always at least one runlist
180 // Figure out how many runlists there are by checking the device info
181 // registers. Runlists are always numbered sequentially, so we just have
182 // to find the highest-valued one and add 1 to get the number of runlists.
183 for (i = 0; i < (nvdebug_readl(&g_nvdebug_state[device_id], 0x0224fc) >> 20); i++) {
184 info.raw = nvdebug_readl(&g_nvdebug_state[device_id], NV_PTOP_DEVICE_INFO_AMPERE(i));
185 if (info.runlist_enum_ampere > max_rl_id)
186 max_rl_id = info.runlist_enum;
187 }
188 // Create files to read each runlist. The read handling code looks at the
189 // PDE_DATA associated with the file to determine what the runlist ID is.
190 for (rl_id = 0; rl_id <= max_rl_id; rl_id++) {
191 snprintf(runlist_name, 12, "runlist%d", rl_id);
192 rl_entry = proc_create_data(
193 runlist_name, 0444, dir, compat_ops(&runlist_file_ops),
194 (void*)(uintptr_t)rl_id);
195 if (!rl_entry)
196 return -ENOMEM;
197 }
198 return 0;
199}
200
170// Create files /proc/gpu# 201// Create files /proc/gpu#
171// TODO: Don't run this on unsupported GPUs 202// TODO: Don't run this on unsupported GPUs
172int create_tpc_mask_files(int device_id, struct proc_dir_entry *dir) { 203int create_tpc_mask_files(int device_id, struct proc_dir_entry *dir) {
@@ -212,7 +243,7 @@ int __init nvdebug_init(void) {
212 if (!(dir = proc_mkdir_data(device_id_str, 0555, NULL, (void*)device_id))) 243 if (!(dir = proc_mkdir_data(device_id_str, 0555, NULL, (void*)device_id)))
213 goto out_nomem; 244 goto out_nomem;
214 // Create files `/proc/gpu#/runlist#`, world readable 245 // Create files `/proc/gpu#/runlist#`, world readable
215 rl_create_err = create_runlist_files(device_id, dir); 246 rl_create_err = g_architectures[device_id] == 0x17 ? create_runlist_files_ampere(device_id, dir) : create_runlist_files_previous(device_id, dir);
216 // Create files `/proc/gpu#/gpc#_tpc_mask`, world readable 247 // Create files `/proc/gpu#/gpc#_tpc_mask`, world readable
217 tpc_masks_create_err = create_tpc_mask_files(device_id, dir); 248 tpc_masks_create_err = create_tpc_mask_files(device_id, dir);
218 // Create file `/proc/gpu#/preempt_tsg`, world writable 249 // Create file `/proc/gpu#/preempt_tsg`, world writable
@@ -233,7 +264,7 @@ int __init nvdebug_init(void) {
233 (void*)device_id); 264 (void*)device_id);
234 // Create file `/proc/gpu#/device_info`, world readable 265 // Create file `/proc/gpu#/device_info`, world readable
235 device_info_entry = proc_create_data( 266 device_info_entry = proc_create_data(
236 "device_info", 0444, dir, compat_ops(&device_info_file_ops), 267 "device_info", 0444, dir, compat_ops(g_architectures[device_id] == 0x17 ? &device_info_file_ops_previous : &device_info_file_ops_ampere),
237 (void*)device_id); 268 (void*)device_id);
238 // Create file `/proc/gpu#/num_gpcs`, world readable 269 // Create file `/proc/gpu#/num_gpcs`, world readable
239 num_gpcs_entry = proc_create_data( 270 num_gpcs_entry = proc_create_data(