summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c')
-rw-r--r--drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c b/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c
new file mode 100644
index 00000000..2a6ace37
--- /dev/null
+++ b/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c
@@ -0,0 +1,269 @@
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 <linux/hashtable.h>
18
19#include <nvgpu/kmem.h>
20#include <nvgpu/bug.h>
21#include <nvgpu/hashtable.h>
22
23#include "os_linux.h"
24
25#include "gk20a/gk20a.h"
26
27#include "platform_gk20a.h"
28#include "platform_gk20a_tegra.h"
29#include "platform_gp10b.h"
30#include "platform_gp10b_tegra.h"
31#include "platform_ecc_sysfs.h"
32
33static u32 gen_ecc_hash_key(char *str)
34{
35 int i = 0;
36 u32 hash_key = 0x811c9dc5;
37
38 while (str[i]) {
39 hash_key *= 0x1000193;
40 hash_key ^= (u32)(str[i]);
41 i++;
42 };
43
44 return hash_key;
45}
46
47static ssize_t ecc_stat_show(struct device *dev,
48 struct device_attribute *attr,
49 char *buf)
50{
51 const char *ecc_stat_full_name = attr->attr.name;
52 const char *ecc_stat_base_name;
53 unsigned int hw_unit;
54 unsigned int subunit;
55 struct gk20a_ecc_stat *ecc_stat;
56 u32 hash_key;
57 struct gk20a *g = get_gk20a(dev);
58 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
59
60 if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit,
61 &subunit) == 2) {
62 ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_lts0_")]);
63 hw_unit = g->gr.slices_per_ltc * hw_unit + subunit;
64 } else if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) {
65 ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]);
66 } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) {
67 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]);
68 } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) {
69 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]);
70 } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) {
71 ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]);
72 } else {
73 return snprintf(buf,
74 PAGE_SIZE,
75 "Error: Invalid ECC stat name!\n");
76 }
77
78 hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name);
79
80 hash_for_each_possible(l->ecc_sysfs_stats_htable,
81 ecc_stat,
82 hash_node,
83 hash_key) {
84 if (hw_unit >= ecc_stat->count)
85 continue;
86 if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit]))
87 return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]);
88 }
89
90 return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n");
91}
92
93int nvgpu_gr_ecc_stat_create(struct device *dev,
94 int is_l2, char *ecc_stat_name,
95 struct gk20a_ecc_stat *ecc_stat)
96{
97 struct gk20a *g = get_gk20a(dev);
98 char *ltc_unit_name = "ltc";
99 char *gr_unit_name = "gpc0_tpc";
100 char *lts_unit_name = "lts";
101 int num_hw_units = 0;
102 int num_subunits = 0;
103
104 if (is_l2 == 1)
105 num_hw_units = g->ltc_count;
106 else if (is_l2 == 2) {
107 num_hw_units = g->ltc_count;
108 num_subunits = g->gr.slices_per_ltc;
109 } else
110 num_hw_units = g->gr.tpc_count;
111
112
113 return nvgpu_ecc_stat_create(dev, num_hw_units, num_subunits,
114 is_l2 ? ltc_unit_name : gr_unit_name,
115 num_subunits ? lts_unit_name: NULL,
116 ecc_stat_name,
117 ecc_stat);
118}
119
120int nvgpu_ecc_stat_create(struct device *dev,
121 int num_hw_units, int num_subunits,
122 char *ecc_unit_name, char *ecc_subunit_name,
123 char *ecc_stat_name,
124 struct gk20a_ecc_stat *ecc_stat)
125{
126 int error = 0;
127 struct gk20a *g = get_gk20a(dev);
128 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
129 int hw_unit = 0;
130 int subunit = 0;
131 int element = 0;
132 u32 hash_key = 0;
133 struct device_attribute *dev_attr_array;
134
135 int num_elements = num_subunits ? num_subunits * num_hw_units :
136 num_hw_units;
137
138 /* Allocate arrays */
139 dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) *
140 num_elements);
141 ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements);
142 ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements);
143
144 for (hw_unit = 0; hw_unit < num_elements; hw_unit++) {
145 ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) *
146 ECC_STAT_NAME_MAX_SIZE);
147 }
148 ecc_stat->count = num_elements;
149 if (num_subunits) {
150 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
151 for (subunit = 0; subunit < num_subunits; subunit++) {
152 element = hw_unit*num_subunits + subunit;
153
154 snprintf(ecc_stat->names[element],
155 ECC_STAT_NAME_MAX_SIZE,
156 "%s%d_%s%d_%s",
157 ecc_unit_name,
158 hw_unit,
159 ecc_subunit_name,
160 subunit,
161 ecc_stat_name);
162
163 sysfs_attr_init(&dev_attr_array[element].attr);
164 dev_attr_array[element].attr.name =
165 ecc_stat->names[element];
166 dev_attr_array[element].attr.mode =
167 VERIFY_OCTAL_PERMISSIONS(S_IRUGO);
168 dev_attr_array[element].show = ecc_stat_show;
169 dev_attr_array[element].store = NULL;
170
171 /* Create sysfs file */
172 error |= device_create_file(dev,
173 &dev_attr_array[element]);
174
175 }
176 }
177 } else {
178 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
179
180 /* Fill in struct device_attribute members */
181 snprintf(ecc_stat->names[hw_unit],
182 ECC_STAT_NAME_MAX_SIZE,
183 "%s%d_%s",
184 ecc_unit_name,
185 hw_unit,
186 ecc_stat_name);
187
188 sysfs_attr_init(&dev_attr_array[hw_unit].attr);
189 dev_attr_array[hw_unit].attr.name =
190 ecc_stat->names[hw_unit];
191 dev_attr_array[hw_unit].attr.mode =
192 VERIFY_OCTAL_PERMISSIONS(S_IRUGO);
193 dev_attr_array[hw_unit].show = ecc_stat_show;
194 dev_attr_array[hw_unit].store = NULL;
195
196 /* Create sysfs file */
197 error |= device_create_file(dev,
198 &dev_attr_array[hw_unit]);
199 }
200 }
201
202 /* Add hash table entry */
203 hash_key = gen_ecc_hash_key(ecc_stat_name);
204 hash_add(l->ecc_sysfs_stats_htable,
205 &ecc_stat->hash_node,
206 hash_key);
207
208 ecc_stat->attr_array = dev_attr_array;
209
210 return error;
211}
212
213void nvgpu_gr_ecc_stat_remove(struct device *dev,
214 int is_l2, struct gk20a_ecc_stat *ecc_stat)
215{
216 struct gk20a *g = get_gk20a(dev);
217 int num_hw_units = 0;
218 int num_subunits = 0;
219
220 if (is_l2 == 1)
221 num_hw_units = g->ltc_count;
222 else if (is_l2 == 2) {
223 num_hw_units = g->ltc_count;
224 num_subunits = g->gr.slices_per_ltc;
225 } else
226 num_hw_units = g->gr.tpc_count;
227
228 nvgpu_ecc_stat_remove(dev, num_hw_units, num_subunits, ecc_stat);
229}
230
231void nvgpu_ecc_stat_remove(struct device *dev,
232 int num_hw_units, int num_subunits,
233 struct gk20a_ecc_stat *ecc_stat)
234{
235 struct gk20a *g = get_gk20a(dev);
236 struct device_attribute *dev_attr_array = ecc_stat->attr_array;
237 int hw_unit = 0;
238 int subunit = 0;
239 int element = 0;
240 int num_elements = num_subunits ? num_subunits * num_hw_units :
241 num_hw_units;
242
243 /* Remove sysfs files */
244 if (num_subunits) {
245 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
246 for (subunit = 0; subunit < num_subunits; subunit++) {
247 element = hw_unit * num_subunits + subunit;
248
249 device_remove_file(dev,
250 &dev_attr_array[element]);
251 }
252 }
253 } else {
254 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++)
255 device_remove_file(dev, &dev_attr_array[hw_unit]);
256 }
257
258 /* Remove hash table entry */
259 hash_del(&ecc_stat->hash_node);
260
261 /* Free arrays */
262 nvgpu_kfree(g, ecc_stat->counters);
263
264 for (hw_unit = 0; hw_unit < num_elements; hw_unit++)
265 nvgpu_kfree(g, ecc_stat->names[hw_unit]);
266
267 nvgpu_kfree(g, ecc_stat->names);
268 nvgpu_kfree(g, dev_attr_array);
269}