summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c259
1 files changed, 259 insertions, 0 deletions
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
33static DEFINE_HASHTABLE(ecc_hash_table, 5);
34
35static 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
49static 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
94int 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
124int 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
218void 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
236void 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}