From 19e9a791955811416729ae3a94439c09000b3952 Mon Sep 17 00:00:00 2001 From: Nitin Kumbhar Date: Thu, 31 May 2018 16:38:20 +0530 Subject: gpu: nvgpu: move ecc sysfs funcs to a common file To make ecc sysfs related code reusable, move it to a seprate file. This allows possible optimizations with localized changes. There is no change in the code. Bug 1987855 Change-Id: I69aefb649df628d0c8dad529de6dde07ab4e6009 Signed-off-by: Nitin Kumbhar Reviewed-on: https://git-master.nvidia.com/r/1735988 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/Makefile | 1 + .../gpu/nvgpu/common/linux/platform_ecc_sysfs.c | 259 +++++++++++++++++++++ .../gpu/nvgpu/common/linux/platform_ecc_sysfs.h | 45 ++++ .../gpu/nvgpu/common/linux/platform_gp10b_tegra.c | 233 ------------------ .../gpu/nvgpu/common/linux/platform_gp10b_tegra.h | 25 +- 5 files changed, 306 insertions(+), 257 deletions(-) create mode 100644 drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c create mode 100644 drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h (limited to 'drivers/gpu') diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index e219df98..5c7bb767 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -166,6 +166,7 @@ nvgpu-$(CONFIG_TEGRA_GK20A) += \ common/linux/module_usermode.o \ common/linux/soc.o \ common/linux/fuse.o \ + common/linux/platform_ecc_sysfs.o \ common/linux/platform_gk20a_tegra.o \ common/linux/platform_gp10b_tegra.o \ common/linux/platform_gv11b_tegra.o diff --git a/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c new file mode 100644 index 00000000..ee59e5de --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "os_linux.h" + +#include "gk20a/gk20a.h" + +#include "platform_gk20a.h" +#include "platform_gk20a_tegra.h" +#include "gp10b/platform_gp10b.h" +#include "platform_gp10b_tegra.h" +#include "platform_ecc_sysfs.h" + +#define ECC_STAT_NAME_MAX_SIZE 100 + +static DEFINE_HASHTABLE(ecc_hash_table, 5); + +static u32 gen_ecc_hash_key(char *str) +{ + int i = 0; + u32 hash_key = 0x811c9dc5; + + while (str[i]) { + hash_key *= 0x1000193; + hash_key ^= (u32)(str[i]); + i++; + }; + + return hash_key; +} + +static ssize_t ecc_stat_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const char *ecc_stat_full_name = attr->attr.name; + const char *ecc_stat_base_name; + unsigned int hw_unit; + unsigned int subunit; + struct gk20a_ecc_stat *ecc_stat; + u32 hash_key; + struct gk20a *g = get_gk20a(dev); + + if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit, + &subunit) == 2) { + ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_lts0_")]); + hw_unit = g->gr.slices_per_ltc * hw_unit + subunit; + } else if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) { + ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]); + } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) { + ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]); + } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) { + ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]); + } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) { + ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]); + } else { + return snprintf(buf, + PAGE_SIZE, + "Error: Invalid ECC stat name!\n"); + } + + hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name); + + hash_for_each_possible(ecc_hash_table, + ecc_stat, + hash_node, + hash_key) { + if (hw_unit >= ecc_stat->count) + continue; + if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit])) + return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]); + } + + return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n"); +} + +int gr_gp10b_ecc_stat_create(struct device *dev, + int is_l2, + char *ecc_stat_name, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute **dev_attr_array) +{ + struct gk20a *g = get_gk20a(dev); + char *ltc_unit_name = "ltc"; + char *gr_unit_name = "gpc0_tpc"; + char *lts_unit_name = "lts"; + int num_hw_units = 0; + int num_subunits = 0; + + if (is_l2 == 1) + num_hw_units = g->ltc_count; + else if (is_l2 == 2) { + num_hw_units = g->ltc_count; + num_subunits = g->gr.slices_per_ltc; + } else + num_hw_units = g->gr.tpc_count; + + + return gp10b_ecc_stat_create(dev, num_hw_units, num_subunits, + is_l2 ? ltc_unit_name : gr_unit_name, + num_subunits ? lts_unit_name: NULL, + ecc_stat_name, + ecc_stat, + dev_attr_array); +} + +int gp10b_ecc_stat_create(struct device *dev, + int num_hw_units, + int num_subunits, + char *ecc_unit_name, + char *ecc_subunit_name, + char *ecc_stat_name, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute **__dev_attr_array) +{ + int error = 0; + struct gk20a *g = get_gk20a(dev); + int hw_unit = 0; + int subunit = 0; + int element = 0; + u32 hash_key = 0; + struct device_attribute *dev_attr_array; + + int num_elements = num_subunits ? num_subunits*num_hw_units : + num_hw_units; + + /* Allocate arrays */ + dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) * + num_elements); + ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements); + ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements); + for (hw_unit = 0; hw_unit < num_elements; hw_unit++) { + ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) * + ECC_STAT_NAME_MAX_SIZE); + } + ecc_stat->count = num_elements; + if (num_subunits) { + for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { + for (subunit = 0; subunit < num_subunits; subunit++) { + element = hw_unit*num_subunits + subunit; + + snprintf(ecc_stat->names[element], + ECC_STAT_NAME_MAX_SIZE, + "%s%d_%s%d_%s", + ecc_unit_name, + hw_unit, + ecc_subunit_name, + subunit, + ecc_stat_name); + + sysfs_attr_init(&dev_attr_array[element].attr); + dev_attr_array[element].attr.name = + ecc_stat->names[element]; + dev_attr_array[element].attr.mode = + VERIFY_OCTAL_PERMISSIONS(S_IRUGO); + dev_attr_array[element].show = ecc_stat_show; + dev_attr_array[element].store = NULL; + + /* Create sysfs file */ + error |= device_create_file(dev, + &dev_attr_array[element]); + + } + } + } else { + for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { + + /* Fill in struct device_attribute members */ + snprintf(ecc_stat->names[hw_unit], + ECC_STAT_NAME_MAX_SIZE, + "%s%d_%s", + ecc_unit_name, + hw_unit, + ecc_stat_name); + + sysfs_attr_init(&dev_attr_array[hw_unit].attr); + dev_attr_array[hw_unit].attr.name = + ecc_stat->names[hw_unit]; + dev_attr_array[hw_unit].attr.mode = + VERIFY_OCTAL_PERMISSIONS(S_IRUGO); + dev_attr_array[hw_unit].show = ecc_stat_show; + dev_attr_array[hw_unit].store = NULL; + + /* Create sysfs file */ + error |= device_create_file(dev, + &dev_attr_array[hw_unit]); + } + } + + /* Add hash table entry */ + hash_key = gen_ecc_hash_key(ecc_stat_name); + hash_add(ecc_hash_table, + &ecc_stat->hash_node, + hash_key); + + *__dev_attr_array = dev_attr_array; + + return error; +} + +void gr_gp10b_ecc_stat_remove(struct device *dev, + int is_l2, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute *dev_attr_array) +{ + struct gk20a *g = get_gk20a(dev); + int num_hw_units = 0; + + if (is_l2 == 1) + num_hw_units = g->ltc_count; + else if (is_l2 == 2) + num_hw_units = g->ltc_count * g->gr.slices_per_ltc; + else + num_hw_units = g->gr.tpc_count; + + gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array); +} + +void gp10b_ecc_stat_remove(struct device *dev, + int num_hw_units, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute *dev_attr_array) +{ + struct gk20a *g = get_gk20a(dev); + int hw_unit = 0; + + /* Remove sysfs files */ + for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { + device_remove_file(dev, &dev_attr_array[hw_unit]); + } + + /* Remove hash table entry */ + hash_del(&ecc_stat->hash_node); + + /* Free arrays */ + nvgpu_kfree(g, ecc_stat->counters); + for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { + nvgpu_kfree(g, ecc_stat->names[hw_unit]); + } + nvgpu_kfree(g, ecc_stat->names); + nvgpu_kfree(g, dev_attr_array); +} diff --git a/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h new file mode 100644 index 00000000..d5622757 --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _NVGPU_PLATFORM_SYSFS_H_ +#define _NVGPU_PLATFORM_SYSFS_H_ + +#include "gp10b/gr_gp10b.h" + +int gr_gp10b_ecc_stat_create(struct device *dev, + int is_l2, + char *ecc_stat_name, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute **dev_attr_array); +int gp10b_ecc_stat_create(struct device *dev, + int num_hw_units, + int num_subunits, + char *ecc_unit_name, + char *ecc_subunit_name, + char *ecc_stat_name, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute **__dev_attr_array); + +void gr_gp10b_ecc_stat_remove(struct device *dev, + int is_l2, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute *dev_attr_array); + +void gp10b_ecc_stat_remove(struct device *dev, + int hw_units, + struct gk20a_ecc_stat *ecc_stat, + struct device_attribute *dev_attr_array); +#endif diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c index a2506341..6f8cc507 100644 --- a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c +++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.c @@ -446,12 +446,6 @@ struct gk20a_platform gp10b_tegra_platform = { .secure_buffer_size = 401408, }; - -#define ECC_STAT_NAME_MAX_SIZE 100 - - -static DEFINE_HASHTABLE(ecc_hash_table, 5); - static struct device_attribute *dev_attr_sm_lrf_ecc_single_err_count_array; static struct device_attribute *dev_attr_sm_lrf_ecc_double_err_count_array; @@ -471,233 +465,6 @@ static struct device_attribute *dev_attr_tex_ecc_unique_ded_pipe1_count_array; static struct device_attribute *dev_attr_l2_ecc_sec_count_array; static struct device_attribute *dev_attr_l2_ecc_ded_count_array; - -static u32 gen_ecc_hash_key(char *str) -{ - int i = 0; - u32 hash_key = 0x811c9dc5; - - while (str[i]) { - hash_key *= 0x1000193; - hash_key ^= (u32)(str[i]); - i++; - }; - - return hash_key; -} - -static ssize_t ecc_stat_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - const char *ecc_stat_full_name = attr->attr.name; - const char *ecc_stat_base_name; - unsigned int hw_unit; - unsigned int subunit; - struct gk20a_ecc_stat *ecc_stat; - u32 hash_key; - struct gk20a *g = get_gk20a(dev); - - if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit, - &subunit) == 2) { - ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_lts0_")]); - hw_unit = g->gr.slices_per_ltc * hw_unit + subunit; - } else if (sscanf(ecc_stat_full_name, "ltc%u", &hw_unit) == 1) { - ecc_stat_base_name = &(ecc_stat_full_name[strlen("ltc0_")]); - } else if (sscanf(ecc_stat_full_name, "gpc0_tpc%u", &hw_unit) == 1) { - ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_tpc0_")]); - } else if (sscanf(ecc_stat_full_name, "gpc%u", &hw_unit) == 1) { - ecc_stat_base_name = &(ecc_stat_full_name[strlen("gpc0_")]); - } else if (sscanf(ecc_stat_full_name, "eng%u", &hw_unit) == 1) { - ecc_stat_base_name = &(ecc_stat_full_name[strlen("eng0_")]); - } else { - return snprintf(buf, - PAGE_SIZE, - "Error: Invalid ECC stat name!\n"); - } - - hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name); - - hash_for_each_possible(ecc_hash_table, - ecc_stat, - hash_node, - hash_key) { - if (hw_unit >= ecc_stat->count) - continue; - if (!strcmp(ecc_stat_full_name, ecc_stat->names[hw_unit])) - return snprintf(buf, PAGE_SIZE, "%u\n", ecc_stat->counters[hw_unit]); - } - - return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n"); -} - -int gr_gp10b_ecc_stat_create(struct device *dev, - int is_l2, - char *ecc_stat_name, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute **dev_attr_array) -{ - struct gk20a *g = get_gk20a(dev); - char *ltc_unit_name = "ltc"; - char *gr_unit_name = "gpc0_tpc"; - char *lts_unit_name = "lts"; - int num_hw_units = 0; - int num_subunits = 0; - - if (is_l2 == 1) - num_hw_units = g->ltc_count; - else if (is_l2 == 2) { - num_hw_units = g->ltc_count; - num_subunits = g->gr.slices_per_ltc; - } else - num_hw_units = g->gr.tpc_count; - - - return gp10b_ecc_stat_create(dev, num_hw_units, num_subunits, - is_l2 ? ltc_unit_name : gr_unit_name, - num_subunits ? lts_unit_name: NULL, - ecc_stat_name, - ecc_stat, - dev_attr_array); -} - -int gp10b_ecc_stat_create(struct device *dev, - int num_hw_units, - int num_subunits, - char *ecc_unit_name, - char *ecc_subunit_name, - char *ecc_stat_name, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute **__dev_attr_array) -{ - int error = 0; - struct gk20a *g = get_gk20a(dev); - int hw_unit = 0; - int subunit = 0; - int element = 0; - u32 hash_key = 0; - struct device_attribute *dev_attr_array; - - int num_elements = num_subunits ? num_subunits*num_hw_units : - num_hw_units; - - /* Allocate arrays */ - dev_attr_array = nvgpu_kzalloc(g, sizeof(struct device_attribute) * - num_elements); - ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements); - ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements); - for (hw_unit = 0; hw_unit < num_elements; hw_unit++) { - ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) * - ECC_STAT_NAME_MAX_SIZE); - } - ecc_stat->count = num_elements; - if (num_subunits) { - for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { - for (subunit = 0; subunit < num_subunits; subunit++) { - element = hw_unit*num_subunits + subunit; - - snprintf(ecc_stat->names[element], - ECC_STAT_NAME_MAX_SIZE, - "%s%d_%s%d_%s", - ecc_unit_name, - hw_unit, - ecc_subunit_name, - subunit, - ecc_stat_name); - - sysfs_attr_init(&dev_attr_array[element].attr); - dev_attr_array[element].attr.name = - ecc_stat->names[element]; - dev_attr_array[element].attr.mode = - VERIFY_OCTAL_PERMISSIONS(S_IRUGO); - dev_attr_array[element].show = ecc_stat_show; - dev_attr_array[element].store = NULL; - - /* Create sysfs file */ - error |= device_create_file(dev, - &dev_attr_array[element]); - - } - } - } else { - for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { - - /* Fill in struct device_attribute members */ - snprintf(ecc_stat->names[hw_unit], - ECC_STAT_NAME_MAX_SIZE, - "%s%d_%s", - ecc_unit_name, - hw_unit, - ecc_stat_name); - - sysfs_attr_init(&dev_attr_array[hw_unit].attr); - dev_attr_array[hw_unit].attr.name = - ecc_stat->names[hw_unit]; - dev_attr_array[hw_unit].attr.mode = - VERIFY_OCTAL_PERMISSIONS(S_IRUGO); - dev_attr_array[hw_unit].show = ecc_stat_show; - dev_attr_array[hw_unit].store = NULL; - - /* Create sysfs file */ - error |= device_create_file(dev, - &dev_attr_array[hw_unit]); - } - } - - /* Add hash table entry */ - hash_key = gen_ecc_hash_key(ecc_stat_name); - hash_add(ecc_hash_table, - &ecc_stat->hash_node, - hash_key); - - *__dev_attr_array = dev_attr_array; - - return error; -} - -void gr_gp10b_ecc_stat_remove(struct device *dev, - int is_l2, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute *dev_attr_array) -{ - struct gk20a *g = get_gk20a(dev); - int num_hw_units = 0; - - if (is_l2 == 1) - num_hw_units = g->ltc_count; - else if (is_l2 == 2) - num_hw_units = g->ltc_count * g->gr.slices_per_ltc; - else - num_hw_units = g->gr.tpc_count; - - gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array); -} - -void gp10b_ecc_stat_remove(struct device *dev, - int num_hw_units, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute *dev_attr_array) -{ - struct gk20a *g = get_gk20a(dev); - int hw_unit = 0; - - /* Remove sysfs files */ - for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { - device_remove_file(dev, &dev_attr_array[hw_unit]); - } - - /* Remove hash table entry */ - hash_del(&ecc_stat->hash_node); - - /* Free arrays */ - nvgpu_kfree(g, ecc_stat->counters); - for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { - nvgpu_kfree(g, ecc_stat->names[hw_unit]); - } - nvgpu_kfree(g, ecc_stat->names); - nvgpu_kfree(g, dev_attr_array); -} - void gr_gp10b_create_sysfs(struct gk20a *g) { int error = 0; diff --git a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h index 725bd0cf..6de90275 100644 --- a/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h +++ b/drivers/gpu/nvgpu/common/linux/platform_gp10b_tegra.h @@ -18,29 +18,6 @@ #define _PLATFORM_GP10B_TEGRA_H_ #include "gp10b/gr_gp10b.h" - -int gr_gp10b_ecc_stat_create(struct device *dev, - int is_l2, - char *ecc_stat_name, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute **dev_attr_array); -int gp10b_ecc_stat_create(struct device *dev, - int num_hw_units, - int num_subunits, - char *ecc_unit_name, - char *ecc_subunit_name, - char *ecc_stat_name, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute **__dev_attr_array); - -void gr_gp10b_ecc_stat_remove(struct device *dev, - int is_l2, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute *dev_attr_array); - -void gp10b_ecc_stat_remove(struct device *dev, - int hw_units, - struct gk20a_ecc_stat *ecc_stat, - struct device_attribute *dev_attr_array); +#include "platform_ecc_sysfs.h" #endif -- cgit v1.2.2