diff options
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c new file mode 100644 index 00000000..5cb82687 --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c | |||
@@ -0,0 +1,607 @@ | |||
1 | /* | ||
2 | * GP10B Tegra Platform Interface | ||
3 | * | ||
4 | * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/of_platform.h> | ||
17 | #include <linux/debugfs.h> | ||
18 | #include <linux/dma-buf.h> | ||
19 | #include <linux/nvmap.h> | ||
20 | #include <linux/reset.h> | ||
21 | #include <linux/platform/tegra/emc_bwmgr.h> | ||
22 | |||
23 | #include <uapi/linux/nvgpu.h> | ||
24 | |||
25 | #include <soc/tegra/tegra_bpmp.h> | ||
26 | #include <soc/tegra/tegra_powergate.h> | ||
27 | #include <soc/tegra/tegra-bpmp-dvfs.h> | ||
28 | |||
29 | #include <dt-bindings/memory/tegra-swgroup.h> | ||
30 | |||
31 | #include <nvgpu/kmem.h> | ||
32 | #include <nvgpu/bug.h> | ||
33 | #include <nvgpu/enabled.h> | ||
34 | #include <nvgpu/hashtable.h> | ||
35 | #include <nvgpu/nvhost.h> | ||
36 | |||
37 | #include "os_linux.h" | ||
38 | |||
39 | #include "clk.h" | ||
40 | |||
41 | #include "gk20a/gk20a.h" | ||
42 | |||
43 | #include "platform_gk20a.h" | ||
44 | #include "platform_ecc_sysfs.h" | ||
45 | #include "platform_gk20a_tegra.h" | ||
46 | #include "platform_gp10b.h" | ||
47 | #include "platform_gp10b_tegra.h" | ||
48 | #include "scale.h" | ||
49 | |||
50 | /* Select every GP10B_FREQ_SELECT_STEP'th frequency from h/w table */ | ||
51 | #define GP10B_FREQ_SELECT_STEP 8 | ||
52 | /* Max number of freq supported in h/w */ | ||
53 | #define GP10B_MAX_SUPPORTED_FREQS 120 | ||
54 | static unsigned long | ||
55 | gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS / GP10B_FREQ_SELECT_STEP]; | ||
56 | |||
57 | #define TEGRA_GP10B_BW_PER_FREQ 64 | ||
58 | #define TEGRA_DDR4_BW_PER_FREQ 16 | ||
59 | |||
60 | #define EMC_BW_RATIO (TEGRA_GP10B_BW_PER_FREQ / TEGRA_DDR4_BW_PER_FREQ) | ||
61 | |||
62 | #define GPCCLK_INIT_RATE 1000000000 | ||
63 | |||
64 | static struct { | ||
65 | char *name; | ||
66 | unsigned long default_rate; | ||
67 | } tegra_gp10b_clocks[] = { | ||
68 | {"gpu", GPCCLK_INIT_RATE}, | ||
69 | {"gpu_sys", 204000000} }; | ||
70 | |||
71 | /* | ||
72 | * gp10b_tegra_get_clocks() | ||
73 | * | ||
74 | * This function finds clocks in tegra platform and populates | ||
75 | * the clock information to gp10b platform data. | ||
76 | */ | ||
77 | |||
78 | int gp10b_tegra_get_clocks(struct device *dev) | ||
79 | { | ||
80 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
81 | unsigned int i; | ||
82 | |||
83 | platform->num_clks = 0; | ||
84 | for (i = 0; i < ARRAY_SIZE(tegra_gp10b_clocks); i++) { | ||
85 | long rate = tegra_gp10b_clocks[i].default_rate; | ||
86 | struct clk *c; | ||
87 | |||
88 | c = clk_get(dev, tegra_gp10b_clocks[i].name); | ||
89 | if (IS_ERR(c)) { | ||
90 | nvgpu_err(platform->g, "cannot get clock %s", | ||
91 | tegra_gp10b_clocks[i].name); | ||
92 | } else { | ||
93 | clk_set_rate(c, rate); | ||
94 | platform->clk[i] = c; | ||
95 | if (i == 0) | ||
96 | platform->cached_rate = rate; | ||
97 | } | ||
98 | } | ||
99 | platform->num_clks = i; | ||
100 | |||
101 | if (platform->clk[0]) { | ||
102 | i = tegra_bpmp_dvfs_get_clk_id(dev->of_node, | ||
103 | tegra_gp10b_clocks[0].name); | ||
104 | if (i > 0) | ||
105 | platform->maxmin_clk_id = i; | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | void gp10b_tegra_scale_init(struct device *dev) | ||
112 | { | ||
113 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
114 | struct gk20a_scale_profile *profile = platform->g->scale_profile; | ||
115 | struct tegra_bwmgr_client *bwmgr_handle; | ||
116 | |||
117 | if (!profile) | ||
118 | return; | ||
119 | |||
120 | if ((struct tegra_bwmgr_client *)profile->private_data) | ||
121 | return; | ||
122 | |||
123 | bwmgr_handle = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_GPU); | ||
124 | if (!bwmgr_handle) | ||
125 | return; | ||
126 | |||
127 | profile->private_data = (void *)bwmgr_handle; | ||
128 | } | ||
129 | |||
130 | static void gp10b_tegra_scale_exit(struct device *dev) | ||
131 | { | ||
132 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
133 | struct gk20a_scale_profile *profile = platform->g->scale_profile; | ||
134 | |||
135 | if (profile) | ||
136 | tegra_bwmgr_unregister( | ||
137 | (struct tegra_bwmgr_client *)profile->private_data); | ||
138 | } | ||
139 | |||
140 | static int gp10b_tegra_probe(struct device *dev) | ||
141 | { | ||
142 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
143 | #ifdef CONFIG_TEGRA_GK20A_NVHOST | ||
144 | int ret; | ||
145 | |||
146 | ret = nvgpu_get_nvhost_dev(platform->g); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | #endif | ||
150 | |||
151 | ret = gk20a_tegra_init_secure_alloc(platform); | ||
152 | if (ret) | ||
153 | return ret; | ||
154 | |||
155 | platform->disable_bigpage = !device_is_iommuable(dev); | ||
156 | |||
157 | platform->g->gr.ctx_vars.dump_ctxsw_stats_on_channel_close | ||
158 | = false; | ||
159 | platform->g->gr.ctx_vars.dump_ctxsw_stats_on_channel_close | ||
160 | = false; | ||
161 | |||
162 | platform->g->gr.ctx_vars.force_preemption_gfxp = false; | ||
163 | platform->g->gr.ctx_vars.force_preemption_cilp = false; | ||
164 | |||
165 | gp10b_tegra_get_clocks(dev); | ||
166 | nvgpu_linux_init_clk_support(platform->g); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int gp10b_tegra_late_probe(struct device *dev) | ||
172 | { | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int gp10b_tegra_remove(struct device *dev) | ||
177 | { | ||
178 | struct gk20a *g = get_gk20a(dev); | ||
179 | |||
180 | if (g->ops.gr.remove_gr_sysfs) | ||
181 | g->ops.gr.remove_gr_sysfs(g); | ||
182 | |||
183 | /* deinitialise tegra specific scaling quirks */ | ||
184 | gp10b_tegra_scale_exit(dev); | ||
185 | |||
186 | #ifdef CONFIG_TEGRA_GK20A_NVHOST | ||
187 | nvgpu_free_nvhost_dev(get_gk20a(dev)); | ||
188 | #endif | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static bool gp10b_tegra_is_railgated(struct device *dev) | ||
194 | { | ||
195 | bool ret = false; | ||
196 | |||
197 | if (tegra_bpmp_running()) | ||
198 | ret = !tegra_powergate_is_powered(TEGRA186_POWER_DOMAIN_GPU); | ||
199 | |||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | static int gp10b_tegra_railgate(struct device *dev) | ||
204 | { | ||
205 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
206 | struct gk20a_scale_profile *profile = platform->g->scale_profile; | ||
207 | |||
208 | /* remove emc frequency floor */ | ||
209 | if (profile) | ||
210 | tegra_bwmgr_set_emc( | ||
211 | (struct tegra_bwmgr_client *)profile->private_data, | ||
212 | 0, TEGRA_BWMGR_SET_EMC_FLOOR); | ||
213 | |||
214 | if (tegra_bpmp_running() && | ||
215 | tegra_powergate_is_powered(TEGRA186_POWER_DOMAIN_GPU)) { | ||
216 | int i; | ||
217 | for (i = 0; i < platform->num_clks; i++) { | ||
218 | if (platform->clk[i]) | ||
219 | clk_disable_unprepare(platform->clk[i]); | ||
220 | } | ||
221 | tegra_powergate_partition(TEGRA186_POWER_DOMAIN_GPU); | ||
222 | } | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int gp10b_tegra_unrailgate(struct device *dev) | ||
227 | { | ||
228 | int ret = 0; | ||
229 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
230 | struct gk20a_scale_profile *profile = platform->g->scale_profile; | ||
231 | |||
232 | if (tegra_bpmp_running()) { | ||
233 | int i; | ||
234 | ret = tegra_unpowergate_partition(TEGRA186_POWER_DOMAIN_GPU); | ||
235 | for (i = 0; i < platform->num_clks; i++) { | ||
236 | if (platform->clk[i]) | ||
237 | clk_prepare_enable(platform->clk[i]); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* to start with set emc frequency floor to max rate*/ | ||
242 | if (profile) | ||
243 | tegra_bwmgr_set_emc( | ||
244 | (struct tegra_bwmgr_client *)profile->private_data, | ||
245 | tegra_bwmgr_get_max_emc_rate(), | ||
246 | TEGRA_BWMGR_SET_EMC_FLOOR); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static int gp10b_tegra_suspend(struct device *dev) | ||
251 | { | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | int gp10b_tegra_reset_assert(struct device *dev) | ||
256 | { | ||
257 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
258 | int ret = 0; | ||
259 | |||
260 | if (!platform->reset_control) | ||
261 | return -EINVAL; | ||
262 | |||
263 | ret = reset_control_assert(platform->reset_control); | ||
264 | |||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | int gp10b_tegra_reset_deassert(struct device *dev) | ||
269 | { | ||
270 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
271 | int ret = 0; | ||
272 | |||
273 | if (!platform->reset_control) | ||
274 | return -EINVAL; | ||
275 | |||
276 | ret = reset_control_deassert(platform->reset_control); | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | void gp10b_tegra_prescale(struct device *dev) | ||
282 | { | ||
283 | struct gk20a *g = get_gk20a(dev); | ||
284 | u32 avg = 0; | ||
285 | |||
286 | nvgpu_log_fn(g, " "); | ||
287 | |||
288 | nvgpu_pmu_load_norm(g, &avg); | ||
289 | |||
290 | nvgpu_log_fn(g, "done"); | ||
291 | } | ||
292 | |||
293 | void gp10b_tegra_postscale(struct device *pdev, | ||
294 | unsigned long freq) | ||
295 | { | ||
296 | struct gk20a_platform *platform = gk20a_get_platform(pdev); | ||
297 | struct gk20a_scale_profile *profile = platform->g->scale_profile; | ||
298 | struct gk20a *g = get_gk20a(pdev); | ||
299 | unsigned long emc_rate; | ||
300 | |||
301 | nvgpu_log_fn(g, " "); | ||
302 | if (profile && !platform->is_railgated(pdev)) { | ||
303 | unsigned long emc_scale; | ||
304 | |||
305 | if (freq <= gp10b_freq_table[0]) | ||
306 | emc_scale = 0; | ||
307 | else | ||
308 | emc_scale = g->emc3d_ratio; | ||
309 | |||
310 | emc_rate = (freq * EMC_BW_RATIO * emc_scale) / 1000; | ||
311 | |||
312 | if (emc_rate > tegra_bwmgr_get_max_emc_rate()) | ||
313 | emc_rate = tegra_bwmgr_get_max_emc_rate(); | ||
314 | |||
315 | tegra_bwmgr_set_emc( | ||
316 | (struct tegra_bwmgr_client *)profile->private_data, | ||
317 | emc_rate, TEGRA_BWMGR_SET_EMC_FLOOR); | ||
318 | } | ||
319 | nvgpu_log_fn(g, "done"); | ||
320 | } | ||
321 | |||
322 | long gp10b_round_clk_rate(struct device *dev, unsigned long rate) | ||
323 | { | ||
324 | struct gk20a *g = get_gk20a(dev); | ||
325 | struct gk20a_scale_profile *profile = g->scale_profile; | ||
326 | unsigned long *freq_table = profile->devfreq_profile.freq_table; | ||
327 | int max_states = profile->devfreq_profile.max_state; | ||
328 | int i; | ||
329 | |||
330 | for (i = 0; i < max_states; ++i) | ||
331 | if (freq_table[i] >= rate) | ||
332 | return freq_table[i]; | ||
333 | |||
334 | return freq_table[max_states - 1]; | ||
335 | } | ||
336 | |||
337 | int gp10b_clk_get_freqs(struct device *dev, | ||
338 | unsigned long **freqs, int *num_freqs) | ||
339 | { | ||
340 | struct gk20a_platform *platform = gk20a_get_platform(dev); | ||
341 | struct gk20a *g = platform->g; | ||
342 | unsigned long max_rate; | ||
343 | unsigned long new_rate = 0, prev_rate = 0; | ||
344 | int i = 0, freq_counter = 0; | ||
345 | |||
346 | max_rate = clk_round_rate(platform->clk[0], (UINT_MAX - 1)); | ||
347 | |||
348 | /* | ||
349 | * Walk the h/w frequency table and only select | ||
350 | * GP10B_FREQ_SELECT_STEP'th frequencies and | ||
351 | * add MAX freq to last | ||
352 | */ | ||
353 | for (; i < GP10B_MAX_SUPPORTED_FREQS; ++i) { | ||
354 | prev_rate = new_rate; | ||
355 | new_rate = clk_round_rate(platform->clk[0], prev_rate + 1); | ||
356 | |||
357 | if (i % GP10B_FREQ_SELECT_STEP == 0 || | ||
358 | new_rate == max_rate) { | ||
359 | gp10b_freq_table[freq_counter++] = new_rate; | ||
360 | |||
361 | if (new_rate == max_rate) | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | WARN_ON(i == GP10B_MAX_SUPPORTED_FREQS); | ||
367 | |||
368 | /* Fill freq table */ | ||
369 | *freqs = gp10b_freq_table; | ||
370 | *num_freqs = freq_counter; | ||
371 | |||
372 | nvgpu_log_info(g, "min rate: %ld max rate: %ld num_of_freq %d\n", | ||
373 | gp10b_freq_table[0], max_rate, *num_freqs); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | struct gk20a_platform gp10b_tegra_platform = { | ||
379 | .has_syncpoints = true, | ||
380 | |||
381 | /* power management configuration */ | ||
382 | .railgate_delay_init = 500, | ||
383 | |||
384 | /* ldiv slowdown factor */ | ||
385 | .ldiv_slowdown_factor_init = SLOWDOWN_FACTOR_FPDIV_BY16, | ||
386 | |||
387 | /* power management configuration */ | ||
388 | .can_railgate_init = true, | ||
389 | .enable_elpg = true, | ||
390 | .can_elpg_init = true, | ||
391 | .enable_blcg = true, | ||
392 | .enable_slcg = true, | ||
393 | .enable_elcg = true, | ||
394 | .can_slcg = true, | ||
395 | .can_blcg = true, | ||
396 | .can_elcg = true, | ||
397 | .enable_aelpg = true, | ||
398 | .enable_perfmon = true, | ||
399 | |||
400 | /* ptimer src frequency in hz*/ | ||
401 | .ptimer_src_freq = 31250000, | ||
402 | |||
403 | .ch_wdt_timeout_ms = 5000, | ||
404 | |||
405 | .probe = gp10b_tegra_probe, | ||
406 | .late_probe = gp10b_tegra_late_probe, | ||
407 | .remove = gp10b_tegra_remove, | ||
408 | |||
409 | /* power management callbacks */ | ||
410 | .suspend = gp10b_tegra_suspend, | ||
411 | .railgate = gp10b_tegra_railgate, | ||
412 | .unrailgate = gp10b_tegra_unrailgate, | ||
413 | .is_railgated = gp10b_tegra_is_railgated, | ||
414 | |||
415 | .busy = gk20a_tegra_busy, | ||
416 | .idle = gk20a_tegra_idle, | ||
417 | |||
418 | .dump_platform_dependencies = gk20a_tegra_debug_dump, | ||
419 | |||
420 | #ifdef CONFIG_NVGPU_SUPPORT_CDE | ||
421 | .has_cde = true, | ||
422 | #endif | ||
423 | |||
424 | .clk_round_rate = gp10b_round_clk_rate, | ||
425 | .get_clk_freqs = gp10b_clk_get_freqs, | ||
426 | |||
427 | /* frequency scaling configuration */ | ||
428 | .initscale = gp10b_tegra_scale_init, | ||
429 | .prescale = gp10b_tegra_prescale, | ||
430 | .postscale = gp10b_tegra_postscale, | ||
431 | .devfreq_governor = "nvhost_podgov", | ||
432 | |||
433 | .qos_notify = gk20a_scale_qos_notify, | ||
434 | |||
435 | .reset_assert = gp10b_tegra_reset_assert, | ||
436 | .reset_deassert = gp10b_tegra_reset_deassert, | ||
437 | |||
438 | .force_reset_in_do_idle = false, | ||
439 | |||
440 | .soc_name = "tegra18x", | ||
441 | |||
442 | .unified_memory = true, | ||
443 | .dma_mask = DMA_BIT_MASK(36), | ||
444 | |||
445 | .ltc_streamid = TEGRA_SID_GPUB, | ||
446 | |||
447 | .secure_buffer_size = 401408, | ||
448 | }; | ||
449 | |||
450 | void gr_gp10b_create_sysfs(struct gk20a *g) | ||
451 | { | ||
452 | int error = 0; | ||
453 | struct device *dev = dev_from_gk20a(g); | ||
454 | |||
455 | /* This stat creation function is called on GR init. GR can get | ||
456 | initialized multiple times but we only need to create the ECC | ||
457 | stats once. Therefore, add the following check to avoid | ||
458 | creating duplicate stat sysfs nodes. */ | ||
459 | if (g->ecc.gr.sm_lrf_single_err_count.counters != NULL) | ||
460 | return; | ||
461 | |||
462 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
463 | 0, | ||
464 | "sm_lrf_ecc_single_err_count", | ||
465 | &g->ecc.gr.sm_lrf_single_err_count); | ||
466 | |||
467 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
468 | 0, | ||
469 | "sm_lrf_ecc_double_err_count", | ||
470 | &g->ecc.gr.sm_lrf_double_err_count); | ||
471 | |||
472 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
473 | 0, | ||
474 | "sm_shm_ecc_sec_count", | ||
475 | &g->ecc.gr.sm_shm_sec_count); | ||
476 | |||
477 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
478 | 0, | ||
479 | "sm_shm_ecc_sed_count", | ||
480 | &g->ecc.gr.sm_shm_sed_count); | ||
481 | |||
482 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
483 | 0, | ||
484 | "sm_shm_ecc_ded_count", | ||
485 | &g->ecc.gr.sm_shm_ded_count); | ||
486 | |||
487 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
488 | 0, | ||
489 | "tex_ecc_total_sec_pipe0_count", | ||
490 | &g->ecc.gr.tex_total_sec_pipe0_count); | ||
491 | |||
492 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
493 | 0, | ||
494 | "tex_ecc_total_ded_pipe0_count", | ||
495 | &g->ecc.gr.tex_total_ded_pipe0_count); | ||
496 | |||
497 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
498 | 0, | ||
499 | "tex_ecc_unique_sec_pipe0_count", | ||
500 | &g->ecc.gr.tex_unique_sec_pipe0_count); | ||
501 | |||
502 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
503 | 0, | ||
504 | "tex_ecc_unique_ded_pipe0_count", | ||
505 | &g->ecc.gr.tex_unique_ded_pipe0_count); | ||
506 | |||
507 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
508 | 0, | ||
509 | "tex_ecc_total_sec_pipe1_count", | ||
510 | &g->ecc.gr.tex_total_sec_pipe1_count); | ||
511 | |||
512 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
513 | 0, | ||
514 | "tex_ecc_total_ded_pipe1_count", | ||
515 | &g->ecc.gr.tex_total_ded_pipe1_count); | ||
516 | |||
517 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
518 | 0, | ||
519 | "tex_ecc_unique_sec_pipe1_count", | ||
520 | &g->ecc.gr.tex_unique_sec_pipe1_count); | ||
521 | |||
522 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
523 | 0, | ||
524 | "tex_ecc_unique_ded_pipe1_count", | ||
525 | &g->ecc.gr.tex_unique_ded_pipe1_count); | ||
526 | |||
527 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
528 | 2, | ||
529 | "ecc_sec_count", | ||
530 | &g->ecc.ltc.l2_sec_count); | ||
531 | |||
532 | error |= nvgpu_gr_ecc_stat_create(dev, | ||
533 | 2, | ||
534 | "ecc_ded_count", | ||
535 | &g->ecc.ltc.l2_ded_count); | ||
536 | |||
537 | if (error) | ||
538 | dev_err(dev, "Failed to create sysfs attributes!\n"); | ||
539 | } | ||
540 | |||
541 | void gr_gp10b_remove_sysfs(struct gk20a *g) | ||
542 | { | ||
543 | struct device *dev = dev_from_gk20a(g); | ||
544 | |||
545 | if (!g->ecc.gr.sm_lrf_single_err_count.counters) | ||
546 | return; | ||
547 | |||
548 | nvgpu_gr_ecc_stat_remove(dev, | ||
549 | 0, | ||
550 | &g->ecc.gr.sm_lrf_single_err_count); | ||
551 | |||
552 | nvgpu_gr_ecc_stat_remove(dev, | ||
553 | 0, | ||
554 | &g->ecc.gr.sm_lrf_double_err_count); | ||
555 | |||
556 | nvgpu_gr_ecc_stat_remove(dev, | ||
557 | 0, | ||
558 | &g->ecc.gr.sm_shm_sec_count); | ||
559 | |||
560 | nvgpu_gr_ecc_stat_remove(dev, | ||
561 | 0, | ||
562 | &g->ecc.gr.sm_shm_sed_count); | ||
563 | |||
564 | nvgpu_gr_ecc_stat_remove(dev, | ||
565 | 0, | ||
566 | &g->ecc.gr.sm_shm_ded_count); | ||
567 | |||
568 | nvgpu_gr_ecc_stat_remove(dev, | ||
569 | 0, | ||
570 | &g->ecc.gr.tex_total_sec_pipe0_count); | ||
571 | |||
572 | nvgpu_gr_ecc_stat_remove(dev, | ||
573 | 0, | ||
574 | &g->ecc.gr.tex_total_ded_pipe0_count); | ||
575 | |||
576 | nvgpu_gr_ecc_stat_remove(dev, | ||
577 | 0, | ||
578 | &g->ecc.gr.tex_unique_sec_pipe0_count); | ||
579 | |||
580 | nvgpu_gr_ecc_stat_remove(dev, | ||
581 | 0, | ||
582 | &g->ecc.gr.tex_unique_ded_pipe0_count); | ||
583 | |||
584 | nvgpu_gr_ecc_stat_remove(dev, | ||
585 | 0, | ||
586 | &g->ecc.gr.tex_total_sec_pipe1_count); | ||
587 | |||
588 | nvgpu_gr_ecc_stat_remove(dev, | ||
589 | 0, | ||
590 | &g->ecc.gr.tex_total_ded_pipe1_count); | ||
591 | |||
592 | nvgpu_gr_ecc_stat_remove(dev, | ||
593 | 0, | ||
594 | &g->ecc.gr.tex_unique_sec_pipe1_count); | ||
595 | |||
596 | nvgpu_gr_ecc_stat_remove(dev, | ||
597 | 0, | ||
598 | &g->ecc.gr.tex_unique_ded_pipe1_count); | ||
599 | |||
600 | nvgpu_gr_ecc_stat_remove(dev, | ||
601 | 2, | ||
602 | &g->ecc.ltc.l2_sec_count); | ||
603 | |||
604 | nvgpu_gr_ecc_stat_remove(dev, | ||
605 | 2, | ||
606 | &g->ecc.ltc.l2_ded_count); | ||
607 | } | ||