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