summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c')
-rw-r--r--drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c
index 8bddff3d..0cfb1d91 100644
--- a/drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c
+++ b/drivers/gpu/nvgpu/gp10b/platform_gp10b_tegra.c
@@ -26,9 +26,14 @@
26#include <linux/tegra_pm_domains.h> 26#include <linux/tegra_pm_domains.h>
27#include <linux/reset.h> 27#include <linux/reset.h>
28#include <soc/tegra/tegra_bpmp.h> 28#include <soc/tegra/tegra_bpmp.h>
29#include <linux/hashtable.h>
29#include "gk20a/platform_gk20a.h" 30#include "gk20a/platform_gk20a.h"
30#include "gk20a/gk20a.h" 31#include "gk20a/gk20a.h"
31#include "platform_tegra.h" 32#include "platform_tegra.h"
33#include "gr_gp10b.h"
34#include "ltc_gp10b.h"
35#include "hw_gr_gp10b.h"
36#include "hw_ltc_gp10b.h"
32 37
33#define GP10B_MAX_SUPPORTED_FREQS 11 38#define GP10B_MAX_SUPPORTED_FREQS 11
34static unsigned long gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS]; 39static unsigned long gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS];
@@ -40,6 +45,8 @@ static struct {
40 {"gpu", 1000000000}, 45 {"gpu", 1000000000},
41 {"gpu_sys", 204000000} }; 46 {"gpu_sys", 204000000} };
42 47
48static void gr_gp10b_remove_sysfs(struct device *dev);
49
43/* 50/*
44 * gp10b_tegra_get_clocks() 51 * gp10b_tegra_get_clocks()
45 * 52 *
@@ -144,6 +151,8 @@ static int gp10b_tegra_remove(struct platform_device *pdev)
144 /* remove gk20a power subdomain from host1x */ 151 /* remove gk20a power subdomain from host1x */
145 nvhost_unregister_client_domain(dev_to_genpd(&pdev->dev)); 152 nvhost_unregister_client_domain(dev_to_genpd(&pdev->dev));
146 153
154 gr_gp10b_remove_sysfs(&pdev->dev);
155
147 return 0; 156 return 0;
148 157
149} 158}
@@ -345,3 +354,322 @@ struct gk20a_platform t18x_gpu_tegra_platform = {
345 354
346 .force_reset_in_do_idle = true, 355 .force_reset_in_do_idle = true,
347}; 356};
357
358
359#define ECC_STAT_NAME_MAX_SIZE 100
360
361
362DEFINE_HASHTABLE(ecc_hash_table, 5);
363
364static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array;
365static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array;
366
367static struct device_attribute *dev_attr_sm_shm_ecc_sec_count_array;
368static struct device_attribute *dev_attr_sm_shm_ecc_sed_count_array;
369static struct device_attribute *dev_attr_sm_shm_ecc_ded_count_array;
370
371static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe0_count_array;
372static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe0_count_array;
373static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe0_count_array;
374static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe0_count_array;
375static struct device_attribute *dev_attr_tex_ecc_total_sec_pipe1_count_array;
376static struct device_attribute *dev_attr_tex_ecc_total_ded_pipe1_count_array;
377static struct device_attribute *dev_attr_tex_ecc_unique_sec_pipe1_count_array;
378static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe1_count_array;
379
380static struct device_attribute *dev_attr_l2_ecc_sec_count_array;
381static struct device_attribute *dev_attr_l2_ecc_ded_count_array;
382
383
384static u32 gen_ecc_hash_key(char *str)
385{
386 int i = 0;
387 u32 hash_key = 0;
388
389 while (str[i]) {
390 hash_key += (u32)(str[i]);
391 i++;
392 };
393
394 return hash_key;
395}
396
397static ssize_t ecc_stat_show(struct device *dev,
398 struct device_attribute *attr,
399 char *buf)
400{
401 const char *ecc_stat_full_name = attr->attr.name;
402 const char *ecc_stat_base_name;
403 unsigned int hw_unit;
404 struct ecc_stat *ecc_stat;
405 u32 hash_key;
406
407 if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) {
408 ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]);
409 } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) {
410 ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]);
411 } else {
412 return snprintf(buf,
413 PAGE_SIZE,
414 "Error: Invalid ECC stat name!\n");
415 }
416
417 hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name);
418 hash_for_each_possible(ecc_hash_table,
419 ecc_stat,
420 hash_node,
421 hash_key) {
422 if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit]))
423 return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]);
424 }
425
426 return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n");
427}
428
429static int ecc_stat_create(struct platform_device *dev,
430 int is_l2,
431 char *ecc_stat_name,
432 struct ecc_stat *ecc_stat,
433 struct device_attribute *dev_attr_array)
434{
435 int error = 0;
436 struct gk20a *g = get_gk20a(dev);
437 int num_hw_units = 0;
438 int hw_unit = 0;
439 u32 hash_key = 0;
440
441 if (is_l2)
442 num_hw_units = g->ltc_count;
443 else
444 num_hw_units = g->gr.tpc_count;
445
446 /* Allocate arrays */
447 dev_attr_array = kzalloc(sizeof(struct device_attribute) * num_hw_units, GFP_KERNEL);
448 ecc_stat->counters = kzalloc(sizeof(u32) * num_hw_units, GFP_KERNEL);
449 ecc_stat->names = kzalloc(sizeof(char *) * num_hw_units, GFP_KERNEL);
450 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
451 ecc_stat->names[hw_unit] = kzalloc(sizeof(char) * ECC_STAT_NAME_MAX_SIZE, GFP_KERNEL);
452 }
453
454 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
455 /* Fill in struct device_attribute members */
456 if (is_l2)
457 snprintf(ecc_stat->names[hw_unit],
458 ECC_STAT_NAME_MAX_SIZE,
459 "ltc%d_%s",
460 hw_unit,
461 ecc_stat_name);
462 else
463 snprintf(ecc_stat->names[hw_unit],
464 ECC_STAT_NAME_MAX_SIZE,
465 "gpc0_tpc%d_%s",
466 hw_unit,
467 ecc_stat_name);
468 dev_attr_array[hw_unit].attr.name = ecc_stat->names[hw_unit];
469 dev_attr_array[hw_unit].attr.mode = VERIFY_OCTAL_PERMISSIONS(S_IRUGO);
470 dev_attr_array[hw_unit].show = ecc_stat_show;
471 dev_attr_array[hw_unit].store = NULL;
472
473 /* Create sysfs file */
474 error |= device_create_file(&dev->dev,
475 &dev_attr_array[hw_unit]);
476 }
477
478 /* Add hash table entry */
479 hash_key = gen_ecc_hash_key(ecc_stat_name);
480 hash_add(ecc_hash_table,
481 &ecc_stat->hash_node,
482 hash_key);
483
484 return error;
485}
486
487static void ecc_stat_remove(struct device *dev,
488 int is_l2,
489 struct ecc_stat *ecc_stat,
490 struct device_attribute *dev_attr_array)
491{
492 struct platform_device *ndev = to_platform_device(dev);
493 struct gk20a *g = get_gk20a(ndev);
494 int num_hw_units = 0;
495 int hw_unit = 0;
496
497 if (is_l2)
498 num_hw_units = g->ltc_count;
499 else
500 num_hw_units = g->gr.tpc_count;
501
502 /* Remove sysfs files */
503 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
504 device_remove_file(dev, &dev_attr_array[hw_unit]);
505 }
506
507 /* Remove hash table entry */
508 hash_del(&ecc_stat->hash_node);
509
510 /* Free arrays */
511 kfree(ecc_stat->counters);
512 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
513 kfree(ecc_stat->names[hw_unit]);
514 }
515 kfree(ecc_stat->names);
516 kfree(dev_attr_array);
517}
518
519void gr_gp10b_create_sysfs(struct platform_device *dev)
520{
521 int error = 0;
522 struct gk20a *g = get_gk20a(dev);
523
524 error |= ecc_stat_create(dev,
525 0,
526 "sm_lrf_ecc_single_err_count",
527 &g->gr.t18x.ecc_stats.sm_lrf_single_err_count,
528 dev_attr_sm_lrf_ecc_single_err_count_array);
529 error |= ecc_stat_create(dev,
530 0,
531 "sm_lrf_ecc_double_err_count",
532 &g->gr.t18x.ecc_stats.sm_lrf_double_err_count,
533 dev_attr_sm_lrf_ecc_double_err_count_array);
534
535 error |= ecc_stat_create(dev,
536 0,
537 "sm_shm_ecc_sec_count",
538 &g->gr.t18x.ecc_stats.sm_shm_sec_count,
539 dev_attr_sm_shm_ecc_sec_count_array);
540 error |= ecc_stat_create(dev,
541 0,
542 "sm_shm_ecc_sed_count",
543 &g->gr.t18x.ecc_stats.sm_shm_sed_count,
544 dev_attr_sm_shm_ecc_sed_count_array);
545 error |= ecc_stat_create(dev,
546 0,
547 "sm_shm_ecc_ded_count",
548 &g->gr.t18x.ecc_stats.sm_shm_ded_count,
549 dev_attr_sm_shm_ecc_ded_count_array);
550
551 error |= ecc_stat_create(dev,
552 0,
553 "tex_ecc_total_sec_pipe0_count",
554 &g->gr.t18x.ecc_stats.tex_total_sec_pipe0_count,
555 dev_attr_tex_ecc_total_sec_pipe0_count_array);
556 error |= ecc_stat_create(dev,
557 0,
558 "tex_ecc_total_ded_pipe0_count",
559 &g->gr.t18x.ecc_stats.tex_total_ded_pipe0_count,
560 dev_attr_tex_ecc_total_ded_pipe0_count_array);
561 error |= ecc_stat_create(dev,
562 0,
563 "tex_ecc_unique_sec_pipe0_count",
564 &g->gr.t18x.ecc_stats.tex_unique_sec_pipe0_count,
565 dev_attr_tex_ecc_unique_sec_pipe0_count_array);
566 error |= ecc_stat_create(dev,
567 0,
568 "tex_ecc_unique_ded_pipe0_count",
569 &g->gr.t18x.ecc_stats.tex_unique_ded_pipe0_count,
570 dev_attr_tex_ecc_unique_ded_pipe0_count_array);
571 error |= ecc_stat_create(dev,
572 0,
573 "tex_ecc_total_sec_pipe1_count",
574 &g->gr.t18x.ecc_stats.tex_total_sec_pipe1_count,
575 dev_attr_tex_ecc_total_sec_pipe1_count_array);
576 error |= ecc_stat_create(dev,
577 0,
578 "tex_ecc_total_ded_pipe1_count",
579 &g->gr.t18x.ecc_stats.tex_total_ded_pipe1_count,
580 dev_attr_tex_ecc_total_ded_pipe1_count_array);
581 error |= ecc_stat_create(dev,
582 0,
583 "tex_ecc_unique_sec_pipe1_count",
584 &g->gr.t18x.ecc_stats.tex_unique_sec_pipe1_count,
585 dev_attr_tex_ecc_unique_sec_pipe1_count_array);
586 error |= ecc_stat_create(dev,
587 0,
588 "tex_ecc_unique_ded_pipe1_count",
589 &g->gr.t18x.ecc_stats.tex_unique_ded_pipe1_count,
590 dev_attr_tex_ecc_unique_ded_pipe1_count_array);
591
592 error |= ecc_stat_create(dev,
593 1,
594 "lts0_ecc_sec_count",
595 &g->gr.t18x.ecc_stats.l2_sec_count,
596 dev_attr_l2_ecc_sec_count_array);
597 error |= ecc_stat_create(dev,
598 1,
599 "lts0_ecc_ded_count",
600 &g->gr.t18x.ecc_stats.l2_ded_count,
601 dev_attr_l2_ecc_ded_count_array);
602
603 if (error)
604 dev_err(&dev->dev, "Failed to create sysfs attributes!\n");
605}
606
607static void gr_gp10b_remove_sysfs(struct device *dev)
608{
609 struct platform_device *ndev = to_platform_device(dev);
610 struct gk20a *g = get_gk20a(ndev);
611
612 ecc_stat_remove(dev,
613 0,
614 &g->gr.t18x.ecc_stats.sm_lrf_single_err_count,
615 dev_attr_sm_lrf_ecc_single_err_count_array);
616 ecc_stat_remove(dev,
617 0,
618 &g->gr.t18x.ecc_stats.sm_lrf_double_err_count,
619 dev_attr_sm_lrf_ecc_double_err_count_array);
620
621 ecc_stat_remove(dev,
622 0,
623 &g->gr.t18x.ecc_stats.sm_shm_sec_count,
624 dev_attr_sm_shm_ecc_sec_count_array);
625 ecc_stat_remove(dev,
626 0,
627 &g->gr.t18x.ecc_stats.sm_shm_sed_count,
628 dev_attr_sm_shm_ecc_sed_count_array);
629 ecc_stat_remove(dev,
630 0,
631 &g->gr.t18x.ecc_stats.sm_shm_ded_count,
632 dev_attr_sm_shm_ecc_ded_count_array);
633
634 ecc_stat_remove(dev,
635 0,
636 &g->gr.t18x.ecc_stats.tex_total_sec_pipe0_count,
637 dev_attr_tex_ecc_total_sec_pipe0_count_array);
638 ecc_stat_remove(dev,
639 0,
640 &g->gr.t18x.ecc_stats.tex_total_ded_pipe0_count,
641 dev_attr_tex_ecc_total_ded_pipe0_count_array);
642 ecc_stat_remove(dev,
643 0,
644 &g->gr.t18x.ecc_stats.tex_unique_sec_pipe0_count,
645 dev_attr_tex_ecc_unique_sec_pipe0_count_array);
646 ecc_stat_remove(dev,
647 0,
648 &g->gr.t18x.ecc_stats.tex_unique_ded_pipe0_count,
649 dev_attr_tex_ecc_unique_ded_pipe0_count_array);
650 ecc_stat_remove(dev,
651 0,
652 &g->gr.t18x.ecc_stats.tex_total_sec_pipe1_count,
653 dev_attr_tex_ecc_total_sec_pipe1_count_array);
654 ecc_stat_remove(dev,
655 0,
656 &g->gr.t18x.ecc_stats.tex_total_ded_pipe1_count,
657 dev_attr_tex_ecc_total_ded_pipe1_count_array);
658 ecc_stat_remove(dev,
659 0,
660 &g->gr.t18x.ecc_stats.tex_unique_sec_pipe1_count,
661 dev_attr_tex_ecc_unique_sec_pipe1_count_array);
662 ecc_stat_remove(dev,
663 0,
664 &g->gr.t18x.ecc_stats.tex_unique_ded_pipe1_count,
665 dev_attr_tex_ecc_unique_ded_pipe1_count_array);
666
667 ecc_stat_remove(dev,
668 1,
669 &g->gr.t18x.ecc_stats.l2_sec_count,
670 dev_attr_l2_ecc_sec_count_array);
671 ecc_stat_remove(dev,
672 1,
673 &g->gr.t18x.ecc_stats.l2_ded_count,
674 dev_attr_l2_ecc_ded_count_array);
675}