summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c
diff options
context:
space:
mode:
authorNitin Kumbhar <nkumbhar@nvidia.com>2018-05-31 09:43:43 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-06-15 08:04:16 -0400
commit8f2cb85983c7cd0c913e6a06df16f929d58a10a9 (patch)
tree8b56f492d2e422104690f38606bba824ded45cff /drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c
parent19e9a791955811416729ae3a94439c09000b3952 (diff)
gpu: nvgpu: update ecc sysfs node handling
Make ecc sysfs hash table per GPU by adding it as part of nvgpu_os_linux. Using a single hash table might give incorrect results as GPUs have same filenames and a filename is used as a key for a lookup. Add device_attribute as part of struct gk20a_ecc_stat. Using a single array of pointers of device attribute for an ecc_stat results in memory leak and incorrect stats if multiple GPUs are present on the system. This array of pointers will always hold info for GPU which created sysfs nodes last. Fix this by making device attribute array per ecc stat per GPU. Fix ecc stat removal to consider zero sub-units for a given number of hwunits. The multiplication with zero results in not removing any sysfs node at all. Bug 1987855 Change-Id: Ifcacc5623cede8decfe228c02d72786337cd0876 Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1735989 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c90
1 files changed, 50 insertions, 40 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c
index ee59e5de..0fe1c8d2 100644
--- a/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c
+++ b/drivers/gpu/nvgpu/common/linux/platform_ecc_sysfs.c
@@ -14,6 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#include <linux/hashtable.h>
18
17#include <nvgpu/kmem.h> 19#include <nvgpu/kmem.h>
18#include <nvgpu/bug.h> 20#include <nvgpu/bug.h>
19#include <nvgpu/hashtable.h> 21#include <nvgpu/hashtable.h>
@@ -28,10 +30,6 @@
28#include "platform_gp10b_tegra.h" 30#include "platform_gp10b_tegra.h"
29#include "platform_ecc_sysfs.h" 31#include "platform_ecc_sysfs.h"
30 32
31#define ECC_STAT_NAME_MAX_SIZE 100
32
33static DEFINE_HASHTABLE(ecc_hash_table, 5);
34
35static u32 gen_ecc_hash_key(char *str) 33static u32 gen_ecc_hash_key(char *str)
36{ 34{
37 int i = 0; 35 int i = 0;
@@ -57,6 +55,7 @@ static ssize_t ecc_stat_show(struct device *dev,
57 struct gk20a_ecc_stat *ecc_stat; 55 struct gk20a_ecc_stat *ecc_stat;
58 u32 hash_key; 56 u32 hash_key;
59 struct gk20a *g = get_gk20a(dev); 57 struct gk20a *g = get_gk20a(dev);
58 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
60 59
61 if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit, 60 if (sscanf(ecc_stat_full_name, "ltc%u_lts%u", &hw_unit,
62 &subunit) == 2) { 61 &subunit) == 2) {
@@ -78,7 +77,7 @@ static ssize_t ecc_stat_show(struct device *dev,
78 77
79 hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name); 78 hash_key = gen_ecc_hash_key((char *)ecc_stat_base_name);
80 79
81 hash_for_each_possible(ecc_hash_table, 80 hash_for_each_possible(l->ecc_sysfs_stats_htable,
82 ecc_stat, 81 ecc_stat,
83 hash_node, 82 hash_node,
84 hash_key) { 83 hash_key) {
@@ -91,11 +90,9 @@ static ssize_t ecc_stat_show(struct device *dev,
91 return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n"); 90 return snprintf(buf, PAGE_SIZE, "Error: No ECC stat found!\n");
92} 91}
93 92
94int gr_gp10b_ecc_stat_create(struct device *dev, 93int nvgpu_gr_ecc_stat_create(struct device *dev,
95 int is_l2, 94 int is_l2, char *ecc_stat_name,
96 char *ecc_stat_name, 95 struct gk20a_ecc_stat *ecc_stat)
97 struct gk20a_ecc_stat *ecc_stat,
98 struct device_attribute **dev_attr_array)
99{ 96{
100 struct gk20a *g = get_gk20a(dev); 97 struct gk20a *g = get_gk20a(dev);
101 char *ltc_unit_name = "ltc"; 98 char *ltc_unit_name = "ltc";
@@ -113,32 +110,29 @@ int gr_gp10b_ecc_stat_create(struct device *dev,
113 num_hw_units = g->gr.tpc_count; 110 num_hw_units = g->gr.tpc_count;
114 111
115 112
116 return gp10b_ecc_stat_create(dev, num_hw_units, num_subunits, 113 return nvgpu_ecc_stat_create(dev, num_hw_units, num_subunits,
117 is_l2 ? ltc_unit_name : gr_unit_name, 114 is_l2 ? ltc_unit_name : gr_unit_name,
118 num_subunits ? lts_unit_name: NULL, 115 num_subunits ? lts_unit_name: NULL,
119 ecc_stat_name, 116 ecc_stat_name,
120 ecc_stat, 117 ecc_stat);
121 dev_attr_array);
122} 118}
123 119
124int gp10b_ecc_stat_create(struct device *dev, 120int nvgpu_ecc_stat_create(struct device *dev,
125 int num_hw_units, 121 int num_hw_units, int num_subunits,
126 int num_subunits, 122 char *ecc_unit_name, char *ecc_subunit_name,
127 char *ecc_unit_name, 123 char *ecc_stat_name,
128 char *ecc_subunit_name, 124 struct gk20a_ecc_stat *ecc_stat)
129 char *ecc_stat_name,
130 struct gk20a_ecc_stat *ecc_stat,
131 struct device_attribute **__dev_attr_array)
132{ 125{
133 int error = 0; 126 int error = 0;
134 struct gk20a *g = get_gk20a(dev); 127 struct gk20a *g = get_gk20a(dev);
128 struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
135 int hw_unit = 0; 129 int hw_unit = 0;
136 int subunit = 0; 130 int subunit = 0;
137 int element = 0; 131 int element = 0;
138 u32 hash_key = 0; 132 u32 hash_key = 0;
139 struct device_attribute *dev_attr_array; 133 struct device_attribute *dev_attr_array;
140 134
141 int num_elements = num_subunits ? num_subunits*num_hw_units : 135 int num_elements = num_subunits ? num_subunits * num_hw_units :
142 num_hw_units; 136 num_hw_units;
143 137
144 /* Allocate arrays */ 138 /* Allocate arrays */
@@ -146,6 +140,7 @@ int gp10b_ecc_stat_create(struct device *dev,
146 num_elements); 140 num_elements);
147 ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements); 141 ecc_stat->counters = nvgpu_kzalloc(g, sizeof(u32) * num_elements);
148 ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements); 142 ecc_stat->names = nvgpu_kzalloc(g, sizeof(char *) * num_elements);
143
149 for (hw_unit = 0; hw_unit < num_elements; hw_unit++) { 144 for (hw_unit = 0; hw_unit < num_elements; hw_unit++) {
150 ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) * 145 ecc_stat->names[hw_unit] = nvgpu_kzalloc(g, sizeof(char) *
151 ECC_STAT_NAME_MAX_SIZE); 146 ECC_STAT_NAME_MAX_SIZE);
@@ -206,44 +201,58 @@ int gp10b_ecc_stat_create(struct device *dev,
206 201
207 /* Add hash table entry */ 202 /* Add hash table entry */
208 hash_key = gen_ecc_hash_key(ecc_stat_name); 203 hash_key = gen_ecc_hash_key(ecc_stat_name);
209 hash_add(ecc_hash_table, 204 hash_add(l->ecc_sysfs_stats_htable,
210 &ecc_stat->hash_node, 205 &ecc_stat->hash_node,
211 hash_key); 206 hash_key);
212 207
213 *__dev_attr_array = dev_attr_array; 208 ecc_stat->attr_array = dev_attr_array;
214 209
215 return error; 210 return error;
216} 211}
217 212
218void gr_gp10b_ecc_stat_remove(struct device *dev, 213void nvgpu_gr_ecc_stat_remove(struct device *dev,
219 int is_l2, 214 int is_l2, struct gk20a_ecc_stat *ecc_stat)
220 struct gk20a_ecc_stat *ecc_stat,
221 struct device_attribute *dev_attr_array)
222{ 215{
223 struct gk20a *g = get_gk20a(dev); 216 struct gk20a *g = get_gk20a(dev);
224 int num_hw_units = 0; 217 int num_hw_units = 0;
218 int num_subunits = 0;
225 219
226 if (is_l2 == 1) 220 if (is_l2 == 1)
227 num_hw_units = g->ltc_count; 221 num_hw_units = g->ltc_count;
228 else if (is_l2 == 2) 222 else if (is_l2 == 2) {
229 num_hw_units = g->ltc_count * g->gr.slices_per_ltc; 223 num_hw_units = g->ltc_count;
230 else 224 num_subunits = g->gr.slices_per_ltc;
225 } else
231 num_hw_units = g->gr.tpc_count; 226 num_hw_units = g->gr.tpc_count;
232 227
233 gp10b_ecc_stat_remove(dev, num_hw_units, ecc_stat, dev_attr_array); 228 nvgpu_ecc_stat_remove(dev, num_hw_units, num_subunits, ecc_stat);
234} 229}
235 230
236void gp10b_ecc_stat_remove(struct device *dev, 231void nvgpu_ecc_stat_remove(struct device *dev,
237 int num_hw_units, 232 int num_hw_units, int num_subunits,
238 struct gk20a_ecc_stat *ecc_stat, 233 struct gk20a_ecc_stat *ecc_stat)
239 struct device_attribute *dev_attr_array)
240{ 234{
241 struct gk20a *g = get_gk20a(dev); 235 struct gk20a *g = get_gk20a(dev);
236 struct device_attribute *dev_attr_array = ecc_stat->attr_array;
242 int hw_unit = 0; 237 int hw_unit = 0;
238 int subunit = 0;
239 int element = 0;
240 int num_elements = num_subunits ? num_subunits * num_hw_units :
241 num_hw_units;
243 242
244 /* Remove sysfs files */ 243 /* Remove sysfs files */
245 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { 244 if (num_subunits) {
246 device_remove_file(dev, &dev_attr_array[hw_unit]); 245 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) {
246 for (subunit = 0; subunit < num_subunits; subunit++) {
247 element = hw_unit * num_subunits + subunit;
248
249 device_remove_file(dev,
250 &dev_attr_array[element]);
251 }
252 }
253 } else {
254 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++)
255 device_remove_file(dev, &dev_attr_array[hw_unit]);
247 } 256 }
248 257
249 /* Remove hash table entry */ 258 /* Remove hash table entry */
@@ -251,9 +260,10 @@ void gp10b_ecc_stat_remove(struct device *dev,
251 260
252 /* Free arrays */ 261 /* Free arrays */
253 nvgpu_kfree(g, ecc_stat->counters); 262 nvgpu_kfree(g, ecc_stat->counters);
254 for (hw_unit = 0; hw_unit < num_hw_units; hw_unit++) { 263
264 for (hw_unit = 0; hw_unit < num_elements; hw_unit++)
255 nvgpu_kfree(g, ecc_stat->names[hw_unit]); 265 nvgpu_kfree(g, ecc_stat->names[hw_unit]);
256 } 266
257 nvgpu_kfree(g, ecc_stat->names); 267 nvgpu_kfree(g, ecc_stat->names);
258 nvgpu_kfree(g, dev_attr_array); 268 nvgpu_kfree(g, dev_attr_array);
259} 269}