summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c786
1 files changed, 786 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c
new file mode 100644
index 00000000..5980c592
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c
@@ -0,0 +1,786 @@
1/*
2 * GP10B Tegra Platform Interface
3 *
4 * Copyright (c) 2014-2017, 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
28#include <nvgpu/kmem.h>
29#include <nvgpu/bug.h>
30#include <nvgpu/enabled.h>
31#include <nvgpu/hashtable.h>
32#include <nvgpu/nvhost.h>
33
34#include "clk.h"
35
36#include "gk20a/platform_gk20a.h"
37#include "gk20a/gk20a.h"
38#include "gk20a/gk20a_scale.h"
39
40#include "platform_gk20a_tegra.h"
41#include "gp10b/gp10b_sysfs.h"
42#include "gp10b/platform_gp10b.h"
43#include "platform_gp10b_tegra.h"
44
45#include <nvgpu/hw/gp10b/hw_gr_gp10b.h>
46#include <nvgpu/hw/gp10b/hw_ltc_gp10b.h>
47
48/* Select every GP10B_FREQ_SELECT_STEP'th frequency from h/w table */
49#define GP10B_FREQ_SELECT_STEP 8
50/* Max number of freq supported in h/w */
51#define GP10B_MAX_SUPPORTED_FREQS 120
52static unsigned long
53gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS / GP10B_FREQ_SELECT_STEP];
54
55#define TEGRA_GP10B_BW_PER_FREQ 64
56#define TEGRA_DDR4_BW_PER_FREQ 16
57
58#define EMC_BW_RATIO (TEGRA_GP10B_BW_PER_FREQ / TEGRA_DDR4_BW_PER_FREQ)
59
60static struct {
61 char *name;
62 unsigned long default_rate;
63} tegra_gp10b_clocks[] = {
64 {"gpu", 1000000000},
65 {"gpu_sys", 204000000} };
66
67static void gr_gp10b_remove_sysfs(struct device *dev);
68
69/*
70 * gp10b_tegra_get_clocks()
71 *
72 * This function finds clocks in tegra platform and populates
73 * the clock information to gp10b platform data.
74 */
75
76int gp10b_tegra_get_clocks(struct device *dev)
77{
78 struct gk20a *g = get_gk20a(dev);
79 struct gk20a_platform *platform = dev_get_drvdata(dev);
80 unsigned int i;
81
82 if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
83 return 0;
84
85 platform->num_clks = 0;
86 for (i = 0; i < ARRAY_SIZE(tegra_gp10b_clocks); i++) {
87 long rate = tegra_gp10b_clocks[i].default_rate;
88 struct clk *c;
89
90 c = clk_get(dev, tegra_gp10b_clocks[i].name);
91 if (IS_ERR(c)) {
92 nvgpu_err(platform->g, "cannot get clock %s",
93 tegra_gp10b_clocks[i].name);
94 } else {
95 clk_set_rate(c, rate);
96 platform->clk[i] = c;
97 }
98 }
99 platform->num_clks = i;
100
101 return 0;
102}
103
104static void gp10b_tegra_scale_init(struct device *dev)
105{
106 struct gk20a_platform *platform = gk20a_get_platform(dev);
107 struct gk20a_scale_profile *profile = platform->g->scale_profile;
108 struct tegra_bwmgr_client *bwmgr_handle;
109
110 if (!profile)
111 return;
112
113 bwmgr_handle = tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_GPU);
114 if (!bwmgr_handle)
115 return;
116
117 profile->private_data = (void *)bwmgr_handle;
118}
119
120static void gp10b_tegra_scale_exit(struct device *dev)
121{
122 struct gk20a_platform *platform = gk20a_get_platform(dev);
123 struct gk20a_scale_profile *profile = platform->g->scale_profile;
124
125 if (profile)
126 tegra_bwmgr_unregister(
127 (struct tegra_bwmgr_client *)profile->private_data);
128}
129
130static int gp10b_tegra_probe(struct device *dev)
131{
132 struct gk20a_platform *platform = dev_get_drvdata(dev);
133#ifdef CONFIG_TEGRA_GK20A_NVHOST
134 int ret;
135
136 ret = nvgpu_get_nvhost_dev(platform->g);
137 if (ret)
138 return ret;
139#endif
140
141 platform->bypass_smmu = !device_is_iommuable(dev);
142 platform->disable_bigpage = platform->bypass_smmu;
143
144 platform->g->gr.t18x.ctx_vars.dump_ctxsw_stats_on_channel_close
145 = false;
146 platform->g->gr.t18x.ctx_vars.dump_ctxsw_stats_on_channel_close
147 = false;
148
149 platform->g->gr.t18x.ctx_vars.force_preemption_gfxp = false;
150 platform->g->gr.t18x.ctx_vars.force_preemption_cilp = false;
151
152 gp10b_tegra_get_clocks(dev);
153 nvgpu_linux_init_clk_support(platform->g);
154 gk20a_tegra_init_secure_alloc(platform->g);
155
156 return 0;
157}
158
159static int gp10b_tegra_late_probe(struct device *dev)
160{
161 /* Cause early VPR resize */
162 gk20a_tegra_secure_page_alloc(dev);
163
164 /*Create GP10B specific sysfs*/
165 gp10b_create_sysfs(dev);
166
167 /* Initialise tegra specific scaling quirks */
168 gp10b_tegra_scale_init(dev);
169 return 0;
170}
171
172int gp10b_tegra_remove(struct device *dev)
173{
174 gr_gp10b_remove_sysfs(dev);
175 /*Remove GP10B specific sysfs*/
176 gp10b_remove_sysfs(dev);
177
178 /* deinitialise tegra specific scaling quirks */
179 gp10b_tegra_scale_exit(dev);
180
181#ifdef CONFIG_TEGRA_GK20A_NVHOST
182 nvgpu_free_nvhost_dev(get_gk20a(dev));
183#endif
184
185 return 0;
186}
187
188static bool gp10b_tegra_is_railgated(struct device *dev)
189{
190 bool ret = false;
191
192 if (tegra_bpmp_running())
193 ret = !tegra_powergate_is_powered(TEGRA186_POWER_DOMAIN_GPU);
194
195 return ret;
196}
197
198static int gp10b_tegra_railgate(struct device *dev)
199{
200 struct gk20a_platform *platform = gk20a_get_platform(dev);
201 struct gk20a_scale_profile *profile = platform->g->scale_profile;
202
203 /* remove emc frequency floor */
204 if (profile)
205 tegra_bwmgr_set_emc(
206 (struct tegra_bwmgr_client *)profile->private_data,
207 0, TEGRA_BWMGR_SET_EMC_FLOOR);
208
209 if (tegra_bpmp_running() &&
210 tegra_powergate_is_powered(TEGRA186_POWER_DOMAIN_GPU)) {
211 int i;
212 for (i = 0; i < platform->num_clks; i++) {
213 if (platform->clk[i])
214 clk_disable_unprepare(platform->clk[i]);
215 }
216 tegra_powergate_partition(TEGRA186_POWER_DOMAIN_GPU);
217 }
218 return 0;
219}
220
221static int gp10b_tegra_unrailgate(struct device *dev)
222{
223 int ret = 0;
224 struct gk20a_platform *platform = gk20a_get_platform(dev);
225 struct gk20a_scale_profile *profile = platform->g->scale_profile;
226
227 if (tegra_bpmp_running()) {
228 int i;
229 ret = tegra_unpowergate_partition(TEGRA186_POWER_DOMAIN_GPU);
230 for (i = 0; i < platform->num_clks; i++) {
231 if (platform->clk[i])
232 clk_prepare_enable(platform->clk[i]);
233 }
234 }
235
236 /* to start with set emc frequency floor to max rate*/
237 if (profile)
238 tegra_bwmgr_set_emc(
239 (struct tegra_bwmgr_client *)profile->private_data,
240 tegra_bwmgr_get_max_emc_rate(),
241 TEGRA_BWMGR_SET_EMC_FLOOR);
242 return ret;
243}
244
245static int gp10b_tegra_suspend(struct device *dev)
246{
247 return 0;
248}
249
250int gp10b_tegra_reset_assert(struct device *dev)
251{
252 struct gk20a_platform *platform = gk20a_get_platform(dev);
253 int ret = 0;
254
255 if (!platform->reset_control)
256 return -EINVAL;
257
258 ret = reset_control_assert(platform->reset_control);
259
260 return ret;
261}
262
263int gp10b_tegra_reset_deassert(struct device *dev)
264{
265 struct gk20a_platform *platform = gk20a_get_platform(dev);
266 int ret = 0;
267
268 if (!platform->reset_control)
269 return -EINVAL;
270
271 ret = reset_control_deassert(platform->reset_control);
272
273 return ret;
274}
275
276static void gp10b_tegra_prescale(struct device *dev)
277{
278 struct gk20a *g = get_gk20a(dev);
279 u32 avg = 0;
280
281 gk20a_dbg_fn("");
282
283 nvgpu_pmu_load_norm(g, &avg);
284
285 gk20a_dbg_fn("done");
286}
287
288static void gp10b_tegra_postscale(struct device *pdev,
289 unsigned long freq)
290{
291 struct gk20a_platform *platform = gk20a_get_platform(pdev);
292 struct gk20a_scale_profile *profile = platform->g->scale_profile;
293 struct gk20a *g = get_gk20a(pdev);
294 unsigned long emc_rate;
295
296 gk20a_dbg_fn("");
297 if (profile && !gp10b_tegra_is_railgated(pdev)) {
298 unsigned long emc_scale;
299
300 if (freq <= gp10b_freq_table[0])
301 emc_scale = 0;
302 else
303 emc_scale = g->emc3d_ratio;
304
305 emc_rate = (freq * EMC_BW_RATIO * emc_scale) / 1000;
306
307 if (emc_rate > tegra_bwmgr_get_max_emc_rate())
308 emc_rate = tegra_bwmgr_get_max_emc_rate();
309
310 tegra_bwmgr_set_emc(
311 (struct tegra_bwmgr_client *)profile->private_data,
312 emc_rate, TEGRA_BWMGR_SET_EMC_FLOOR);
313 }
314 gk20a_dbg_fn("done");
315}
316
317static long gp10b_round_clk_rate(struct device *dev, unsigned long rate)
318{
319 struct gk20a *g = get_gk20a(dev);
320 struct gk20a_scale_profile *profile = g->scale_profile;
321 unsigned long *freq_table = profile->devfreq_profile.freq_table;
322 int max_states = profile->devfreq_profile.max_state;
323 int i;
324
325 for (i = 0; i < max_states; ++i)
326 if (freq_table[i] >= rate)
327 return freq_table[i];
328
329 return freq_table[max_states - 1];
330}
331
332static int gp10b_clk_get_freqs(struct device *dev,
333 unsigned long **freqs, int *num_freqs)
334{
335 struct gk20a_platform *platform = gk20a_get_platform(dev);
336 unsigned long max_rate;
337 unsigned long new_rate = 0, prev_rate = 0;
338 int i = 0, freq_counter = 0;
339
340 max_rate = clk_round_rate(platform->clk[0], (UINT_MAX - 1));
341
342 /*
343 * Walk the h/w frequency table and only select
344 * GP10B_FREQ_SELECT_STEP'th frequencies and
345 * add MAX freq to last
346 */
347 for (; i < GP10B_MAX_SUPPORTED_FREQS; ++i) {
348 prev_rate = new_rate;
349 new_rate = clk_round_rate(platform->clk[0], prev_rate + 1);
350
351 if (i % GP10B_FREQ_SELECT_STEP == 0 ||
352 new_rate == max_rate) {
353 gp10b_freq_table[freq_counter++] = new_rate;
354
355 if (new_rate == max_rate)
356 break;
357 }
358 }
359
360 WARN_ON(i == GP10B_MAX_SUPPORTED_FREQS);
361
362 /* Fill freq table */
363 *freqs = gp10b_freq_table;
364 *num_freqs = freq_counter;
365
366 gk20a_dbg_info("min rate: %ld max rate: %ld num_of_freq %d\n",
367 gp10b_freq_table[0], max_rate, *num_freqs);
368
369 return 0;
370}
371
372struct gk20a_platform gp10b_tegra_platform = {
373 .has_syncpoints = true,
374
375 /* power management configuration */
376 .railgate_delay_init = 500,
377
378 /* power management configuration */
379 .can_railgate_init = true,
380 .enable_elpg = true,
381 .can_elpg_init = true,
382 .enable_blcg = true,
383 .enable_slcg = true,
384 .enable_elcg = true,
385 .enable_aelpg = true,
386
387 /* ptimer src frequency in hz*/
388 .ptimer_src_freq = 31250000,
389
390 .ch_wdt_timeout_ms = 5000,
391
392 .probe = gp10b_tegra_probe,
393 .late_probe = gp10b_tegra_late_probe,
394 .remove = gp10b_tegra_remove,
395
396 /* power management callbacks */
397 .suspend = gp10b_tegra_suspend,
398 .railgate = gp10b_tegra_railgate,
399 .unrailgate = gp10b_tegra_unrailgate,
400 .is_railgated = gp10b_tegra_is_railgated,
401
402 .busy = gk20a_tegra_busy,
403 .idle = gk20a_tegra_idle,
404
405 .dump_platform_dependencies = gk20a_tegra_debug_dump,
406
407 .default_big_page_size = SZ_64K,
408
409 .has_cde = true,
410
411 .clk_round_rate = gp10b_round_clk_rate,
412 .get_clk_freqs = gp10b_clk_get_freqs,
413
414 /* frequency scaling configuration */
415 .prescale = gp10b_tegra_prescale,
416 .postscale = gp10b_tegra_postscale,
417 .devfreq_governor = "nvhost_podgov",
418
419 .qos_notify = gk20a_scale_qos_notify,
420
421 .reset_assert = gp10b_tegra_reset_assert,
422 .reset_deassert = gp10b_tegra_reset_deassert,
423
424 .force_reset_in_do_idle = false,
425
426 .soc_name = "tegra18x",
427
428 .unified_memory = true,
429};
430
431
432#define ECC_STAT_NAME_MAX_SIZE 100
433
434
435static DEFINE_HASHTABLE(ecc_hash_table, 5);
436
437static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array;
438static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array;
439
440static struct device_attribute *dev_attr_sm_shm_ecc_sec_count_array;
441static struct device_attribute *dev_attr_sm_shm_ecc_sed_count_array;
442static struct device_attribute *dev_attr_sm_shm_ecc_ded_count_array;
443
444static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe0_count_array;
445static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe0_count_array;
446static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe0_count_array;
447static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe0_count_array;
448static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe1_count_array;
449static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe1_count_array;
450static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe1_count_array;
451static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe1_count_array;
452
453static struct device_attribute *dev_attr_l2_ecc_sec_count_array;
454static struct device_attribute *dev_attr_l2_ecc_ded_count_array;
455
456
457static u32 gen_ecc_hash_key(char *str)
458{
459 int i = 0;
460 u32 hash_key = 0;
461
462 while (str[i]) {
463 hash_key += (u32)(str[i]);
464 i++;
465 };
466
467 return hash_key;
468}
469
470static ssize_t ecc_stat_show(struct device *dev,
471 struct device_attribute *attr,
472 char *buf)
473{
474 const char *ecc_stat_full_name = attr->attr.name;
475 const char *ecc_stat_base_name;
476 unsigned int hw_unit;
477 struct gk20a_ecc_stat *ecc_stat;
478 u32 hash_key;
479
480 if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) {
481 ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]);
482 } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) {
483 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]);
484 } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) {
485 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]);
486 } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) {
487 ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]);
488 } else {
489 return snprintf(buf,
490 PAGE_SIZE,
491 "Error: Invalid ECC stat name!\n");
492 }
493
494 hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name);
495 hash_for_each_possible(ecc_hash_table,
496 ecc_stat,
497 hash_node,
498 hash_key) {
499 if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit]))
500 return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]);
501 }
502
503 return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n");
504}
505
506int gr_gp10b_ecc_stat_create(struct device *dev,
507 int is_l2,
508 char *ecc_stat_name,
509 struct gk20a_ecc_stat *ecc_stat,
510 struct device_attribute **dev_attr_array)
511{
512 struct gk20a *g = get_gk20a(dev);
513 char *ltc_unit_name = "ltc";
514 char *gr_unit_name = "gpc0_tpc";
515 int num_hw_units = 0;
516
517 if (is_l2)
518 num_hw_units = g->ltc_count;
519 else
520 num_hw_units = g->gr.tpc_count;
521
522
523 return gp10b_ecc_stat_create(dev, num_hw_units,
524 is_l2 ? ltc_unit_name : gr_unit_name,
525 ecc_stat_name,
526 ecc_stat,
527 dev_attr_array);
528}
529
530int gp10b_ecc_stat_create(struct device *dev,
531 int num_hw_units,
532 char *ecc_unit_name,
533 char *ecc_stat_name,
534 struct gk20a_ecc_stat *ecc_stat,
535 struct device_attribute **__dev_attr_array)
536{
537 int error = 0;
538 struct gk20a *g = get_gk20a(dev);
539 int hw_unit = 0;
540 u32 hash_key = 0;
541 struct device_attribute *dev_attr_array;
542
543 /* Allocate arrays */
544 dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) *
545 num_hw_units);
546 ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_hw_units);
547 ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_hw_units);
548 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
549 ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) *
550 ECC_STAT_NAME_MAX_SIZE);
551 }
552
553 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
554 /* Fill in struct device_attribute members */
555 snprintf(ecc_stat->names[hw_unit],
556 ECC_STAT_NAME_MAX_SIZE,
557 "%s%d_%s",
558 ecc_unit_name,
559 hw_unit,
560 ecc_stat_name);
561
562 sysfs_attr_init(&dev_attr_array[hw_unit].attr);
563 dev_attr_array[hw_unit].attr.name = ecc_stat->names[hw_unit];
564 dev_attr_array[hw_unit].attr.mode = VERIFY_OCTAL_PERMISSIONS(S_IRUGO);
565 dev_attr_array[hw_unit].show = ecc_stat_show;
566 dev_attr_array[hw_unit].store = NULL;
567
568 /* Create sysfs file */
569 error |= device_create_file(dev, &dev_attr_array[hw_unit]);
570 }
571
572 /* Add hash table entry */
573 hash_key = gen_ecc_hash_key(ecc_stat_name);
574 hash_add(ecc_hash_table,
575 &ecc_stat->hash_node,
576 hash_key);
577
578 *__dev_attr_array = dev_attr_array;
579
580 return error;
581}
582
583void gr_gp10b_ecc_stat_remove(struct device *dev,
584 int is_l2,
585 struct gk20a_ecc_stat *ecc_stat,
586 struct device_attribute *dev_attr_array)
587{
588 struct gk20a *g = get_gk20a(dev);
589 int num_hw_units = 0;
590
591 if (is_l2)
592 num_hw_units = g->ltc_count;
593 else
594 num_hw_units = g->gr.tpc_count;
595
596 gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array);
597}
598
599void gp10b_ecc_stat_remove(struct device *dev,
600 int num_hw_units,
601 struct gk20a_ecc_stat *ecc_stat,
602 struct device_attribute *dev_attr_array)
603{
604 struct gk20a *g = get_gk20a(dev);
605 int hw_unit = 0;
606
607 /* Remove sysfs files */
608 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
609 device_remove_file(dev, &dev_attr_array[hw_unit]);
610 }
611
612 /* Remove hash table entry */
613 hash_del(&ecc_stat->hash_node);
614
615 /* Free arrays */
616 nvgpu_kfree(g, ecc_stat->counters);
617 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
618 nvgpu_kfree(g, ecc_stat->names[hw_unit]);
619 }
620 nvgpu_kfree(g, ecc_stat->names);
621 nvgpu_kfree(g, dev_attr_array);
622}
623
624void gr_gp10b_create_sysfs(struct device *dev)
625{
626 int error = 0;
627 struct gk20a *g = get_gk20a(dev);
628
629 /* This stat creation function is called on GR init. GR can get
630 initialized multiple times but we only need to create the ECC
631 stats once. Therefore, add the following check to avoid
632 creating duplicate stat sysfs nodes. */
633 if (g->ecc.gr.t18x.sm_lrf_single_err_count.counters != NULL)
634 return;
635
636 error |= gr_gp10b_ecc_stat_create(dev,
637 0,
638 "sm_lrf_ecc_single_err_count",
639 &g->ecc.gr.t18x.sm_lrf_single_err_count,
640 &dev_attr_sm_lrf_ecc_single_err_count_array);
641 error |= gr_gp10b_ecc_stat_create(dev,
642 0,
643 "sm_lrf_ecc_double_err_count",
644 &g->ecc.gr.t18x.sm_lrf_double_err_count,
645 &dev_attr_sm_lrf_ecc_double_err_count_array);
646
647 error |= gr_gp10b_ecc_stat_create(dev,
648 0,
649 "sm_shm_ecc_sec_count",
650 &g->ecc.gr.t18x.sm_shm_sec_count,
651 &dev_attr_sm_shm_ecc_sec_count_array);
652 error |= gr_gp10b_ecc_stat_create(dev,
653 0,
654 "sm_shm_ecc_sed_count",
655 &g->ecc.gr.t18x.sm_shm_sed_count,
656 &dev_attr_sm_shm_ecc_sed_count_array);
657 error |= gr_gp10b_ecc_stat_create(dev,
658 0,
659 "sm_shm_ecc_ded_count",
660 &g->ecc.gr.t18x.sm_shm_ded_count,
661 &dev_attr_sm_shm_ecc_ded_count_array);
662
663 error |= gr_gp10b_ecc_stat_create(dev,
664 0,
665 "tex_ecc_total_sec_pipe0_count",
666 &g->ecc.gr.t18x.tex_total_sec_pipe0_count,
667 &dev_attr_tex_ecc_total_sec_pipe0_count_array);
668 error |= gr_gp10b_ecc_stat_create(dev,
669 0,
670 "tex_ecc_total_ded_pipe0_count",
671 &g->ecc.gr.t18x.tex_total_ded_pipe0_count,
672 &dev_attr_tex_ecc_total_ded_pipe0_count_array);
673 error |= gr_gp10b_ecc_stat_create(dev,
674 0,
675 "tex_ecc_unique_sec_pipe0_count",
676 &g->ecc.gr.t18x.tex_unique_sec_pipe0_count,
677 &dev_attr_tex_ecc_unique_sec_pipe0_count_array);
678 error |= gr_gp10b_ecc_stat_create(dev,
679 0,
680 "tex_ecc_unique_ded_pipe0_count",
681 &g->ecc.gr.t18x.tex_unique_ded_pipe0_count,
682 &dev_attr_tex_ecc_unique_ded_pipe0_count_array);
683 error |= gr_gp10b_ecc_stat_create(dev,
684 0,
685 "tex_ecc_total_sec_pipe1_count",
686 &g->ecc.gr.t18x.tex_total_sec_pipe1_count,
687 &dev_attr_tex_ecc_total_sec_pipe1_count_array);
688 error |= gr_gp10b_ecc_stat_create(dev,
689 0,
690 "tex_ecc_total_ded_pipe1_count",
691 &g->ecc.gr.t18x.tex_total_ded_pipe1_count,
692 &dev_attr_tex_ecc_total_ded_pipe1_count_array);
693 error |= gr_gp10b_ecc_stat_create(dev,
694 0,
695 "tex_ecc_unique_sec_pipe1_count",
696 &g->ecc.gr.t18x.tex_unique_sec_pipe1_count,
697 &dev_attr_tex_ecc_unique_sec_pipe1_count_array);
698 error |= gr_gp10b_ecc_stat_create(dev,
699 0,
700 "tex_ecc_unique_ded_pipe1_count",
701 &g->ecc.gr.t18x.tex_unique_ded_pipe1_count,
702 &dev_attr_tex_ecc_unique_ded_pipe1_count_array);
703
704 error |= gr_gp10b_ecc_stat_create(dev,
705 1,
706 "lts0_ecc_sec_count",
707 &g->ecc.gr.t18x.l2_sec_count,
708 &dev_attr_l2_ecc_sec_count_array);
709 error |= gr_gp10b_ecc_stat_create(dev,
710 1,
711 "lts0_ecc_ded_count",
712 &g->ecc.gr.t18x.l2_ded_count,
713 &dev_attr_l2_ecc_ded_count_array);
714
715 if (error)
716 dev_err(dev, "Failed to create sysfs attributes!\n");
717}
718
719static void gr_gp10b_remove_sysfs(struct device *dev)
720{
721 struct gk20a *g = get_gk20a(dev);
722
723 gr_gp10b_ecc_stat_remove(dev,
724 0,
725 &g->ecc.gr.t18x.sm_lrf_single_err_count,
726 dev_attr_sm_lrf_ecc_single_err_count_array);
727 gr_gp10b_ecc_stat_remove(dev,
728 0,
729 &g->ecc.gr.t18x.sm_lrf_double_err_count,
730 dev_attr_sm_lrf_ecc_double_err_count_array);
731
732 gr_gp10b_ecc_stat_remove(dev,
733 0,
734 &g->ecc.gr.t18x.sm_shm_sec_count,
735 dev_attr_sm_shm_ecc_sec_count_array);
736 gr_gp10b_ecc_stat_remove(dev,
737 0,
738 &g->ecc.gr.t18x.sm_shm_sed_count,
739 dev_attr_sm_shm_ecc_sed_count_array);
740 gr_gp10b_ecc_stat_remove(dev,
741 0,
742 &g->ecc.gr.t18x.sm_shm_ded_count,
743 dev_attr_sm_shm_ecc_ded_count_array);
744
745 gr_gp10b_ecc_stat_remove(dev,
746 0,
747 &g->ecc.gr.t18x.tex_total_sec_pipe0_count,
748 dev_attr_tex_ecc_total_sec_pipe0_count_array);
749 gr_gp10b_ecc_stat_remove(dev,
750 0,
751 &g->ecc.gr.t18x.tex_total_ded_pipe0_count,
752 dev_attr_tex_ecc_total_ded_pipe0_count_array);
753 gr_gp10b_ecc_stat_remove(dev,
754 0,
755 &g->ecc.gr.t18x.tex_unique_sec_pipe0_count,
756 dev_attr_tex_ecc_unique_sec_pipe0_count_array);
757 gr_gp10b_ecc_stat_remove(dev,
758 0,
759 &g->ecc.gr.t18x.tex_unique_ded_pipe0_count,
760 dev_attr_tex_ecc_unique_ded_pipe0_count_array);
761 gr_gp10b_ecc_stat_remove(dev,
762 0,
763 &g->ecc.gr.t18x.tex_total_sec_pipe1_count,
764 dev_attr_tex_ecc_total_sec_pipe1_count_array);
765 gr_gp10b_ecc_stat_remove(dev,
766 0,
767 &g->ecc.gr.t18x.tex_total_ded_pipe1_count,
768 dev_attr_tex_ecc_total_ded_pipe1_count_array);
769 gr_gp10b_ecc_stat_remove(dev,
770 0,
771 &g->ecc.gr.t18x.tex_unique_sec_pipe1_count,
772 dev_attr_tex_ecc_unique_sec_pipe1_count_array);
773 gr_gp10b_ecc_stat_remove(dev,
774 0,
775 &g->ecc.gr.t18x.tex_unique_ded_pipe1_count,
776 dev_attr_tex_ecc_unique_ded_pipe1_count_array);
777
778 gr_gp10b_ecc_stat_remove(dev,
779 1,
780 &g->ecc.gr.t18x.l2_sec_count,
781 dev_attr_l2_ecc_sec_count_array);
782 gr_gp10b_ecc_stat_remove(dev,
783 1,
784 &g->ecc.gr.t18x.l2_ded_count,
785 dev_attr_l2_ecc_ded_count_array);
786}