diff options
author | Richard Zhao <rizhao@nvidia.com> | 2018-06-26 20:37:40 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-07-19 19:43:58 -0400 |
commit | 7f14aafc2c02eb0fab458324d0ba91a7fdea3086 (patch) | |
tree | cda9f48839fbde3444fde521a9b0069eb06cd81a /drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c | |
parent | 5ff1b3fe5a30c926e59a55ad25dd4daf430c8579 (diff) |
gpu: nvgpu: rework ecc structure and sysfs
- create common file common/ecc.c which include common functions for add
ecc counters and remove counters.
- common code will create a list of all counter which make it easier to
iterate all counters.
- Add chip specific file for adding ecc counters.
- add linux specific file os/linux/ecc_sysfs.c to export counters to
sysfs.
- remove obsolete code
- MISRA violation for using snprintf is not solved, tracking with
jira NVGPU-859
Jira NVGPUT-115
Change-Id: I1905c43c5c9b2b131199807533dee8e63ddc12f4
Signed-off-by: Richard Zhao <rizhao@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1763536
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c | 269 |
1 files changed, 0 insertions, 269 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c b/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c deleted file mode 100644 index 2a6ace37..00000000 --- a/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c +++ /dev/null | |||
@@ -1,269 +0,0 @@ | |||
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 | |||
33 | static 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 | |||
47 | static 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 | |||
93 | int 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 | |||
120 | int 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 | |||
213 | void 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 | |||
231 | void 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 | } | ||