diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/nvgpu/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c | 259 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h | 45 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c | 233 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h | 25 |
5 files changed, 306 insertions, 257 deletions
diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index e219df98..5c7bb767 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile | |||
@@ -166,6 +166,7 @@ nvgpu-$(CONFIG_TEGRA_GK20A) += \ | |||
166 | common/linux/module_usermode.o \ | 166 | common/linux/module_usermode.o \ |
167 | common/linux/soc.o \ | 167 | common/linux/soc.o \ |
168 | common/linux/fuse.o \ | 168 | common/linux/fuse.o \ |
169 | common/linux/platform_ecc_sysfs.o \ | ||
169 | common/linux/platform_gk20a_tegra.o \ | 170 | common/linux/platform_gk20a_tegra.o \ |
170 | common/linux/platform_gp10b_tegra.o \ | 171 | common/linux/platform_gp10b_tegra.o \ |
171 | common/linux/platform_gv11b_tegra.o | 172 | common/linux/platform_gv11b_tegra.o |
diff --git a/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c new file mode 100644 index 00000000..ee59e5de --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <nvgpu/kmem.h> | ||
18 | #include <nvgpu/bug.h> | ||
19 | #include <nvgpu/hashtable.h> | ||
20 | |||
21 | #include "os_linux.h" | ||
22 | |||
23 | #include "gk20a/gk20a.h" | ||
24 | |||
25 | #include "platform_gk20a.h" | ||
26 | #include "platform_gk20a_tegra.h" | ||
27 | #include "gp10b/platform_gp10b.h" | ||
28 | #include "platform_gp10b_tegra.h" | ||
29 | #include "platform_ecc_sysfs.h" | ||
30 | |||
31 | #define ECC_STAT_NAME_MAX_SIZE 100 | ||
32 | |||
33 | static DEFINE_HASHTABLE(ecc_hash_table, 5); | ||
34 | |||
35 | static u32 gen_ecc_hash_key(char *str) | ||
36 | { | ||
37 | int i = 0; | ||
38 | u32 hash_key = 0x811c9dc5; | ||
39 | |||
40 | while (str[i]) { | ||
41 | hash_key *= 0x1000193; | ||
42 | hash_key ^= (u32)(str[i]); | ||
43 | i++; | ||
44 | }; | ||
45 | |||
46 | return hash_key; | ||
47 | } | ||
48 | |||
49 | static ssize_t ecc_stat_show(struct device *dev, | ||
50 | struct device_attribute *attr, | ||
51 | char *buf) | ||
52 | { | ||
53 | const char *ecc_stat_full_name = attr->attr.name; | ||
54 | const char *ecc_stat_base_name; | ||
55 | unsigned int hw_unit; | ||
56 | unsigned int subunit; | ||
57 | struct gk20a_ecc_stat *ecc_stat; | ||
58 | u32 hash_key; | ||
59 | struct gk20a *g = get_gk20a(dev); | ||
60 | |||
61 | if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit, | ||
62 | &subunit) == 2) { | ||
63 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_lts0_")]); | ||
64 | hw_unit = g->gr.slices_per_ltc * hw_unit + subunit; | ||
65 | } else if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) { | ||
66 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]); | ||
67 | } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) { | ||
68 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]); | ||
69 | } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) { | ||
70 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]); | ||
71 | } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) { | ||
72 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]); | ||
73 | } else { | ||
74 | return snprintf(buf, | ||
75 | PAGE_SIZE, | ||
76 | "Error: Invalid ECC stat name!\n"); | ||
77 | } | ||
78 | |||
79 | hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name); | ||
80 | |||
81 | hash_for_each_possible(ecc_hash_table, | ||
82 | ecc_stat, | ||
83 | hash_node, | ||
84 | hash_key) { | ||
85 | if (hw_unit >= ecc_stat->count) | ||
86 | continue; | ||
87 | if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit])) | ||
88 | return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]); | ||
89 | } | ||
90 | |||
91 | return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n"); | ||
92 | } | ||
93 | |||
94 | int gr_gp10b_ecc_stat_create(struct device *dev, | ||
95 | int is_l2, | ||
96 | char *ecc_stat_name, | ||
97 | struct gk20a_ecc_stat *ecc_stat, | ||
98 | struct device_attribute **dev_attr_array) | ||
99 | { | ||
100 | struct gk20a *g = get_gk20a(dev); | ||
101 | char *ltc_unit_name = "ltc"; | ||
102 | char *gr_unit_name = "gpc0_tpc"; | ||
103 | char *lts_unit_name = "lts"; | ||
104 | int num_hw_units = 0; | ||
105 | int num_subunits = 0; | ||
106 | |||
107 | if (is_l2 == 1) | ||
108 | num_hw_units = g->ltc_count; | ||
109 | else if (is_l2 == 2) { | ||
110 | num_hw_units = g->ltc_count; | ||
111 | num_subunits = g->gr.slices_per_ltc; | ||
112 | } else | ||
113 | num_hw_units = g->gr.tpc_count; | ||
114 | |||
115 | |||
116 | return gp10b_ecc_stat_create(dev, num_hw_units, num_subunits, | ||
117 | is_l2 ? ltc_unit_name : gr_unit_name, | ||
118 | num_subunits ? lts_unit_name: NULL, | ||
119 | ecc_stat_name, | ||
120 | ecc_stat, | ||
121 | dev_attr_array); | ||
122 | } | ||
123 | |||
124 | int gp10b_ecc_stat_create(struct device *dev, | ||
125 | int num_hw_units, | ||
126 | int num_subunits, | ||
127 | char *ecc_unit_name, | ||
128 | char *ecc_subunit_name, | ||
129 | char *ecc_stat_name, | ||
130 | struct gk20a_ecc_stat *ecc_stat, | ||
131 | struct device_attribute **__dev_attr_array) | ||
132 | { | ||
133 | int error = 0; | ||
134 | struct gk20a *g = get_gk20a(dev); | ||
135 | int hw_unit = 0; | ||
136 | int subunit = 0; | ||
137 | int element = 0; | ||
138 | u32 hash_key = 0; | ||
139 | struct device_attribute *dev_attr_array; | ||
140 | |||
141 | int num_elements = num_subunits ? num_subunits*num_hw_units : | ||
142 | num_hw_units; | ||
143 | |||
144 | /* Allocate arrays */ | ||
145 | dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) * | ||
146 | num_elements); | ||
147 | ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements); | ||
148 | ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements); | ||
149 | for (hw_unit = 0; hw_unit < num_elements; hw_unit++) { | ||
150 | ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) * | ||
151 | ECC_STAT_NAME_MAX_SIZE); | ||
152 | } | ||
153 | ecc_stat->count = num_elements; | ||
154 | if (num_subunits) { | ||
155 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
156 | for (subunit = 0; subunit < num_subunits; subunit++) { | ||
157 | element = hw_unit*num_subunits + subunit; | ||
158 | |||
159 | snprintf(ecc_stat->names[element], | ||
160 | ECC_STAT_NAME_MAX_SIZE, | ||
161 | "%s%d_%s%d_%s", | ||
162 | ecc_unit_name, | ||
163 | hw_unit, | ||
164 | ecc_subunit_name, | ||
165 | subunit, | ||
166 | ecc_stat_name); | ||
167 | |||
168 | sysfs_attr_init(&dev_attr_array[element].attr); | ||
169 | dev_attr_array[element].attr.name = | ||
170 | ecc_stat->names[element]; | ||
171 | dev_attr_array[element].attr.mode = | ||
172 | VERIFY_OCTAL_PERMISSIONS(S_IRUGO); | ||
173 | dev_attr_array[element].show = ecc_stat_show; | ||
174 | dev_attr_array[element].store = NULL; | ||
175 | |||
176 | /* Create sysfs file */ | ||
177 | error |= device_create_file(dev, | ||
178 | &dev_attr_array[element]); | ||
179 | |||
180 | } | ||
181 | } | ||
182 | } else { | ||
183 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
184 | |||
185 | /* Fill in struct device_attribute members */ | ||
186 | snprintf(ecc_stat->names[hw_unit], | ||
187 | ECC_STAT_NAME_MAX_SIZE, | ||
188 | "%s%d_%s", | ||
189 | ecc_unit_name, | ||
190 | hw_unit, | ||
191 | ecc_stat_name); | ||
192 | |||
193 | sysfs_attr_init(&dev_attr_array[hw_unit].attr); | ||
194 | dev_attr_array[hw_unit].attr.name = | ||
195 | ecc_stat->names[hw_unit]; | ||
196 | dev_attr_array[hw_unit].attr.mode = | ||
197 | VERIFY_OCTAL_PERMISSIONS(S_IRUGO); | ||
198 | dev_attr_array[hw_unit].show = ecc_stat_show; | ||
199 | dev_attr_array[hw_unit].store = NULL; | ||
200 | |||
201 | /* Create sysfs file */ | ||
202 | error |= device_create_file(dev, | ||
203 | &dev_attr_array[hw_unit]); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | /* Add hash table entry */ | ||
208 | hash_key = gen_ecc_hash_key(ecc_stat_name); | ||
209 | hash_add(ecc_hash_table, | ||
210 | &ecc_stat->hash_node, | ||
211 | hash_key); | ||
212 | |||
213 | *__dev_attr_array = dev_attr_array; | ||
214 | |||
215 | return error; | ||
216 | } | ||
217 | |||
218 | void gr_gp10b_ecc_stat_remove(struct device *dev, | ||
219 | int is_l2, | ||
220 | struct gk20a_ecc_stat *ecc_stat, | ||
221 | struct device_attribute *dev_attr_array) | ||
222 | { | ||
223 | struct gk20a *g = get_gk20a(dev); | ||
224 | int num_hw_units = 0; | ||
225 | |||
226 | if (is_l2 == 1) | ||
227 | num_hw_units = g->ltc_count; | ||
228 | else if (is_l2 == 2) | ||
229 | num_hw_units = g->ltc_count * g->gr.slices_per_ltc; | ||
230 | else | ||
231 | num_hw_units = g->gr.tpc_count; | ||
232 | |||
233 | gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array); | ||
234 | } | ||
235 | |||
236 | void gp10b_ecc_stat_remove(struct device *dev, | ||
237 | int num_hw_units, | ||
238 | struct gk20a_ecc_stat *ecc_stat, | ||
239 | struct device_attribute *dev_attr_array) | ||
240 | { | ||
241 | struct gk20a *g = get_gk20a(dev); | ||
242 | int hw_unit = 0; | ||
243 | |||
244 | /* Remove sysfs files */ | ||
245 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
246 | device_remove_file(dev, &dev_attr_array[hw_unit]); | ||
247 | } | ||
248 | |||
249 | /* Remove hash table entry */ | ||
250 | hash_del(&ecc_stat->hash_node); | ||
251 | |||
252 | /* Free arrays */ | ||
253 | nvgpu_kfree(g, ecc_stat->counters); | ||
254 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
255 | nvgpu_kfree(g, ecc_stat->names[hw_unit]); | ||
256 | } | ||
257 | nvgpu_kfree(g, ecc_stat->names); | ||
258 | nvgpu_kfree(g, dev_attr_array); | ||
259 | } | ||
diff --git a/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h new file mode 100644 index 00000000..d5622757 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef _NVGPU_PLATFORM_SYSFS_H_ | ||
18 | #define _NVGPU_PLATFORM_SYSFS_H_ | ||
19 | |||
20 | #include "gp10b/gr_gp10b.h" | ||
21 | |||
22 | int gr_gp10b_ecc_stat_create(struct device *dev, | ||
23 | int is_l2, | ||
24 | char *ecc_stat_name, | ||
25 | struct gk20a_ecc_stat *ecc_stat, | ||
26 | struct device_attribute **dev_attr_array); | ||
27 | int gp10b_ecc_stat_create(struct device *dev, | ||
28 | int num_hw_units, | ||
29 | int num_subunits, | ||
30 | char *ecc_unit_name, | ||
31 | char *ecc_subunit_name, | ||
32 | char *ecc_stat_name, | ||
33 | struct gk20a_ecc_stat *ecc_stat, | ||
34 | struct device_attribute **__dev_attr_array); | ||
35 | |||
36 | void gr_gp10b_ecc_stat_remove(struct device *dev, | ||
37 | int is_l2, | ||
38 | struct gk20a_ecc_stat *ecc_stat, | ||
39 | struct device_attribute *dev_attr_array); | ||
40 | |||
41 | void gp10b_ecc_stat_remove(struct device *dev, | ||
42 | int hw_units, | ||
43 | struct gk20a_ecc_stat *ecc_stat, | ||
44 | struct device_attribute *dev_attr_array); | ||
45 | #endif | ||
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c index a2506341..6f8cc507 100644 --- a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c +++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c | |||
@@ -446,12 +446,6 @@ struct gk20a_platform gp10b_tegra_platform = { | |||
446 | .secure_buffer_size = 401408, | 446 | .secure_buffer_size = 401408, |
447 | }; | 447 | }; |
448 | 448 | ||
449 | |||
450 | #define ECC_STAT_NAME_MAX_SIZE 100 | ||
451 | |||
452 | |||
453 | static DEFINE_HASHTABLE(ecc_hash_table, 5); | ||
454 | |||
455 | static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array; | 449 | static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array; |
456 | static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array; | 450 | static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array; |
457 | 451 | ||
@@ -471,233 +465,6 @@ static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe1_count_array; | |||
471 | static struct device_attribute *dev_attr_l2_ecc_sec_count_array; | 465 | static struct device_attribute *dev_attr_l2_ecc_sec_count_array; |
472 | static struct device_attribute *dev_attr_l2_ecc_ded_count_array; | 466 | static struct device_attribute *dev_attr_l2_ecc_ded_count_array; |
473 | 467 | ||
474 | |||
475 | static u32 gen_ecc_hash_key(char *str) | ||
476 | { | ||
477 | int i = 0; | ||
478 | u32 hash_key = 0x811c9dc5; | ||
479 | |||
480 | while (str[i]) { | ||
481 | hash_key *= 0x1000193; | ||
482 | hash_key ^= (u32)(str[i]); | ||
483 | i++; | ||
484 | }; | ||
485 | |||
486 | return hash_key; | ||
487 | } | ||
488 | |||
489 | static ssize_t ecc_stat_show(struct device *dev, | ||
490 | struct device_attribute *attr, | ||
491 | char *buf) | ||
492 | { | ||
493 | const char *ecc_stat_full_name = attr->attr.name; | ||
494 | const char *ecc_stat_base_name; | ||
495 | unsigned int hw_unit; | ||
496 | unsigned int subunit; | ||
497 | struct gk20a_ecc_stat *ecc_stat; | ||
498 | u32 hash_key; | ||
499 | struct gk20a *g = get_gk20a(dev); | ||
500 | |||
501 | if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit, | ||
502 | &subunit) == 2) { | ||
503 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_lts0_")]); | ||
504 | hw_unit = g->gr.slices_per_ltc * hw_unit + subunit; | ||
505 | } else if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) { | ||
506 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]); | ||
507 | } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) { | ||
508 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]); | ||
509 | } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) { | ||
510 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]); | ||
511 | } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) { | ||
512 | ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]); | ||
513 | } else { | ||
514 | return snprintf(buf, | ||
515 | PAGE_SIZE, | ||
516 | "Error: Invalid ECC stat name!\n"); | ||
517 | } | ||
518 | |||
519 | hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name); | ||
520 | |||
521 | hash_for_each_possible(ecc_hash_table, | ||
522 | ecc_stat, | ||
523 | hash_node, | ||
524 | hash_key) { | ||
525 | if (hw_unit >= ecc_stat->count) | ||
526 | continue; | ||
527 | if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit])) | ||
528 | return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]); | ||
529 | } | ||
530 | |||
531 | return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n"); | ||
532 | } | ||
533 | |||
534 | int gr_gp10b_ecc_stat_create(struct device *dev, | ||
535 | int is_l2, | ||
536 | char *ecc_stat_name, | ||
537 | struct gk20a_ecc_stat *ecc_stat, | ||
538 | struct device_attribute **dev_attr_array) | ||
539 | { | ||
540 | struct gk20a *g = get_gk20a(dev); | ||
541 | char *ltc_unit_name = "ltc"; | ||
542 | char *gr_unit_name = "gpc0_tpc"; | ||
543 | char *lts_unit_name = "lts"; | ||
544 | int num_hw_units = 0; | ||
545 | int num_subunits = 0; | ||
546 | |||
547 | if (is_l2 == 1) | ||
548 | num_hw_units = g->ltc_count; | ||
549 | else if (is_l2 == 2) { | ||
550 | num_hw_units = g->ltc_count; | ||
551 | num_subunits = g->gr.slices_per_ltc; | ||
552 | } else | ||
553 | num_hw_units = g->gr.tpc_count; | ||
554 | |||
555 | |||
556 | return gp10b_ecc_stat_create(dev, num_hw_units, num_subunits, | ||
557 | is_l2 ? ltc_unit_name : gr_unit_name, | ||
558 | num_subunits ? lts_unit_name: NULL, | ||
559 | ecc_stat_name, | ||
560 | ecc_stat, | ||
561 | dev_attr_array); | ||
562 | } | ||
563 | |||
564 | int gp10b_ecc_stat_create(struct device *dev, | ||
565 | int num_hw_units, | ||
566 | int num_subunits, | ||
567 | char *ecc_unit_name, | ||
568 | char *ecc_subunit_name, | ||
569 | char *ecc_stat_name, | ||
570 | struct gk20a_ecc_stat *ecc_stat, | ||
571 | struct device_attribute **__dev_attr_array) | ||
572 | { | ||
573 | int error = 0; | ||
574 | struct gk20a *g = get_gk20a(dev); | ||
575 | int hw_unit = 0; | ||
576 | int subunit = 0; | ||
577 | int element = 0; | ||
578 | u32 hash_key = 0; | ||
579 | struct device_attribute *dev_attr_array; | ||
580 | |||
581 | int num_elements = num_subunits ? num_subunits*num_hw_units : | ||
582 | num_hw_units; | ||
583 | |||
584 | /* Allocate arrays */ | ||
585 | dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) * | ||
586 | num_elements); | ||
587 | ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements); | ||
588 | ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements); | ||
589 | for (hw_unit = 0; hw_unit < num_elements; hw_unit++) { | ||
590 | ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) * | ||
591 | ECC_STAT_NAME_MAX_SIZE); | ||
592 | } | ||
593 | ecc_stat->count = num_elements; | ||
594 | if (num_subunits) { | ||
595 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
596 | for (subunit = 0; subunit < num_subunits; subunit++) { | ||
597 | element = hw_unit*num_subunits + subunit; | ||
598 | |||
599 | snprintf(ecc_stat->names[element], | ||
600 | ECC_STAT_NAME_MAX_SIZE, | ||
601 | "%s%d_%s%d_%s", | ||
602 | ecc_unit_name, | ||
603 | hw_unit, | ||
604 | ecc_subunit_name, | ||
605 | subunit, | ||
606 | ecc_stat_name); | ||
607 | |||
608 | sysfs_attr_init(&dev_attr_array[element].attr); | ||
609 | dev_attr_array[element].attr.name = | ||
610 | ecc_stat->names[element]; | ||
611 | dev_attr_array[element].attr.mode = | ||
612 | VERIFY_OCTAL_PERMISSIONS(S_IRUGO); | ||
613 | dev_attr_array[element].show = ecc_stat_show; | ||
614 | dev_attr_array[element].store = NULL; | ||
615 | |||
616 | /* Create sysfs file */ | ||
617 | error |= device_create_file(dev, | ||
618 | &dev_attr_array[element]); | ||
619 | |||
620 | } | ||
621 | } | ||
622 | } else { | ||
623 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
624 | |||
625 | /* Fill in struct device_attribute members */ | ||
626 | snprintf(ecc_stat->names[hw_unit], | ||
627 | ECC_STAT_NAME_MAX_SIZE, | ||
628 | "%s%d_%s", | ||
629 | ecc_unit_name, | ||
630 | hw_unit, | ||
631 | ecc_stat_name); | ||
632 | |||
633 | sysfs_attr_init(&dev_attr_array[hw_unit].attr); | ||
634 | dev_attr_array[hw_unit].attr.name = | ||
635 | ecc_stat->names[hw_unit]; | ||
636 | dev_attr_array[hw_unit].attr.mode = | ||
637 | VERIFY_OCTAL_PERMISSIONS(S_IRUGO); | ||
638 | dev_attr_array[hw_unit].show = ecc_stat_show; | ||
639 | dev_attr_array[hw_unit].store = NULL; | ||
640 | |||
641 | /* Create sysfs file */ | ||
642 | error |= device_create_file(dev, | ||
643 | &dev_attr_array[hw_unit]); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | /* Add hash table entry */ | ||
648 | hash_key = gen_ecc_hash_key(ecc_stat_name); | ||
649 | hash_add(ecc_hash_table, | ||
650 | &ecc_stat->hash_node, | ||
651 | hash_key); | ||
652 | |||
653 | *__dev_attr_array = dev_attr_array; | ||
654 | |||
655 | return error; | ||
656 | } | ||
657 | |||
658 | void gr_gp10b_ecc_stat_remove(struct device *dev, | ||
659 | int is_l2, | ||
660 | struct gk20a_ecc_stat *ecc_stat, | ||
661 | struct device_attribute *dev_attr_array) | ||
662 | { | ||
663 | struct gk20a *g = get_gk20a(dev); | ||
664 | int num_hw_units = 0; | ||
665 | |||
666 | if (is_l2 == 1) | ||
667 | num_hw_units = g->ltc_count; | ||
668 | else if (is_l2 == 2) | ||
669 | num_hw_units = g->ltc_count * g->gr.slices_per_ltc; | ||
670 | else | ||
671 | num_hw_units = g->gr.tpc_count; | ||
672 | |||
673 | gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array); | ||
674 | } | ||
675 | |||
676 | void gp10b_ecc_stat_remove(struct device *dev, | ||
677 | int num_hw_units, | ||
678 | struct gk20a_ecc_stat *ecc_stat, | ||
679 | struct device_attribute *dev_attr_array) | ||
680 | { | ||
681 | struct gk20a *g = get_gk20a(dev); | ||
682 | int hw_unit = 0; | ||
683 | |||
684 | /* Remove sysfs files */ | ||
685 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
686 | device_remove_file(dev, &dev_attr_array[hw_unit]); | ||
687 | } | ||
688 | |||
689 | /* Remove hash table entry */ | ||
690 | hash_del(&ecc_stat->hash_node); | ||
691 | |||
692 | /* Free arrays */ | ||
693 | nvgpu_kfree(g, ecc_stat->counters); | ||
694 | for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { | ||
695 | nvgpu_kfree(g, ecc_stat->names[hw_unit]); | ||
696 | } | ||
697 | nvgpu_kfree(g, ecc_stat->names); | ||
698 | nvgpu_kfree(g, dev_attr_array); | ||
699 | } | ||
700 | |||
701 | void gr_gp10b_create_sysfs(struct gk20a *g) | 468 | void gr_gp10b_create_sysfs(struct gk20a *g) |
702 | { | 469 | { |
703 | int error = 0; | 470 | int error = 0; |
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h index 725bd0cf..6de90275 100644 --- a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h +++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h | |||
@@ -18,29 +18,6 @@ | |||
18 | #define _PLATFORM_GP10B_TEGRA_H_ | 18 | #define _PLATFORM_GP10B_TEGRA_H_ |
19 | 19 | ||
20 | #include "gp10b/gr_gp10b.h" | 20 | #include "gp10b/gr_gp10b.h" |
21 | 21 | #include "platform_ecc_sysfs.h" | |
22 | int gr_gp10b_ecc_stat_create(struct device *dev, | ||
23 | int is_l2, | ||
24 | char *ecc_stat_name, | ||
25 | struct gk20a_ecc_stat *ecc_stat, | ||
26 | struct device_attribute **dev_attr_array); | ||
27 | int gp10b_ecc_stat_create(struct device *dev, | ||
28 | int num_hw_units, | ||
29 | int num_subunits, | ||
30 | char *ecc_unit_name, | ||
31 | char *ecc_subunit_name, | ||
32 | char *ecc_stat_name, | ||
33 | struct gk20a_ecc_stat *ecc_stat, | ||
34 | struct device_attribute **__dev_attr_array); | ||
35 | |||
36 | void gr_gp10b_ecc_stat_remove(struct device *dev, | ||
37 | int is_l2, | ||
38 | struct gk20a_ecc_stat *ecc_stat, | ||
39 | struct device_attribute *dev_attr_array); | ||
40 | |||
41 | void gp10b_ecc_stat_remove(struct device *dev, | ||
42 | int hw_units, | ||
43 | struct gk20a_ecc_stat *ecc_stat, | ||
44 | struct device_attribute *dev_attr_array); | ||
45 | 22 | ||
46 | #endif | 23 | #endif |