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