From 2a2c16af5f9f1ccfc93a13e820d5381e5c881e92 Mon Sep 17 00:00:00 2001 From: Terje Bergstrom Date: Wed, 18 Apr 2018 12:59:00 -0700 Subject: gpu: nvgpu: Move Linux files away from common Move all Linux source code files to drivers/gpu/nvgpu/os/linux from drivers/gpu/nvgpu/common/linux. This changes the meaning of common to be OS independent. JIRA NVGPU-598 JIRA NVGPU-601 Change-Id: Ib7f2a43d3688bb0d0b7dcc48469a6783fd988ce9 Signed-off-by: Terje Bergstrom Reviewed-on: https://git-master.nvidia.com/r/1747714 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c | 269 ++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c (limited to 'drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c') diff --git a/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c b/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c new file mode 100644 index 00000000..2a6ace37 --- /dev/null +++ b/drivers/gpu/nvgpu/os/linux/platform_ecc_sysfs.c @@ -0,0 +1,269 @@ +/* + * 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 + +#include "os_linux.h" + +#include "gk20a/gk20a.h" + +#include "platform_gk20a.h" +#include "platform_gk20a_tegra.h" +#include "platform_gp10b.h" +#include "platform_gp10b_tegra.h" +#include "platform_ecc_sysfs.h" + +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); + struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); + + 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(l->ecc_sysfs_stats_htable, + 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 nvgpu_gr_ecc_stat_create(struct device *dev, + int is_l2, char *ecc_stat_name, + struct gk20a_ecc_stat *ecc_stat) +{ + 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 nvgpu_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); +} + +int nvgpu_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) +{ + int error = 0; + struct gk20a *g = get_gk20a(dev); + struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); + 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(l->ecc_sysfs_stats_htable, + &ecc_stat->hash_node, + hash_key); + + ecc_stat->attr_array = dev_attr_array; + + return error; +} + +void nvgpu_gr_ecc_stat_remove(struct device *dev, + int is_l2, struct gk20a_ecc_stat *ecc_stat) +{ + struct gk20a *g = get_gk20a(dev); + 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; + + nvgpu_ecc_stat_remove(dev, num_hw_units, num_subunits, ecc_stat); +} + +void nvgpu_ecc_stat_remove(struct device *dev, + int num_hw_units, int num_subunits, + struct gk20a_ecc_stat *ecc_stat) +{ + struct gk20a *g = get_gk20a(dev); + struct device_attribute *dev_attr_array = ecc_stat->attr_array; + int hw_unit = 0; + int subunit = 0; + int element = 0; + int num_elements = num_subunits ? num_subunits * num_hw_units : + num_hw_units; + + /* Remove sysfs files */ + 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; + + device_remove_file(dev, + &dev_attr_array[element]); + } + } + } else { + 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_elements; hw_unit++) + nvgpu_kfree(g, ecc_stat->names[hw_unit]); + + nvgpu_kfree(g, ecc_stat->names); + nvgpu_kfree(g, dev_attr_array); +} -- cgit v1.2.2