diff options
Diffstat (limited to 'include/os/linux/vgpu/sysfs_vgpu.c')
-rw-r--r-- | include/os/linux/vgpu/sysfs_vgpu.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/include/os/linux/vgpu/sysfs_vgpu.c b/include/os/linux/vgpu/sysfs_vgpu.c new file mode 100644 index 0000000..ade5d82 --- /dev/null +++ b/include/os/linux/vgpu/sysfs_vgpu.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/device.h> | ||
18 | #include <nvgpu/vgpu/vgpu.h> | ||
19 | |||
20 | #include "os/linux/platform_gk20a.h" | ||
21 | #include "os/linux/os_linux.h" | ||
22 | #include "vgpu/ecc_vgpu.h" | ||
23 | |||
24 | static ssize_t vgpu_load_show(struct device *dev, | ||
25 | struct device_attribute *attr, | ||
26 | char *buf) | ||
27 | { | ||
28 | struct gk20a *g = get_gk20a(dev); | ||
29 | struct tegra_vgpu_cmd_msg msg = {0}; | ||
30 | struct tegra_vgpu_gpu_load_params *p = &msg.params.gpu_load; | ||
31 | int err; | ||
32 | |||
33 | msg.cmd = TEGRA_VGPU_CMD_GET_GPU_LOAD; | ||
34 | msg.handle = vgpu_get_handle(g); | ||
35 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
36 | if (err) | ||
37 | return err; | ||
38 | |||
39 | return snprintf(buf, PAGE_SIZE, "%u\n", p->load); | ||
40 | } | ||
41 | static DEVICE_ATTR(load, S_IRUGO, vgpu_load_show, NULL); | ||
42 | |||
43 | static ssize_t vgpu_ecc_stat_show(struct device *dev, | ||
44 | struct device_attribute *attr, | ||
45 | char *buf) | ||
46 | { | ||
47 | struct gk20a *g = get_gk20a(dev); | ||
48 | struct tegra_vgpu_cmd_msg msg = {0}; | ||
49 | struct tegra_vgpu_ecc_counter_params *p = &msg.params.ecc_counter; | ||
50 | struct dev_ext_attribute *ext_attr = container_of(attr, | ||
51 | struct dev_ext_attribute, attr); | ||
52 | struct vgpu_ecc_stat *ecc_stat = ext_attr->var; | ||
53 | int err; | ||
54 | |||
55 | p->ecc_id = ecc_stat->ecc_id; | ||
56 | |||
57 | msg.cmd = TEGRA_VGPU_CMD_GET_ECC_COUNTER_VALUE; | ||
58 | msg.handle = vgpu_get_handle(g); | ||
59 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
60 | err = err ? err : msg.ret; | ||
61 | if (unlikely(err)) { | ||
62 | nvgpu_err(g, "ecc: cannot get ECC counter value: %d", err); | ||
63 | return err; | ||
64 | } | ||
65 | |||
66 | return snprintf(buf, PAGE_SIZE, "%u\n", p->value); | ||
67 | } | ||
68 | |||
69 | static int vgpu_create_ecc_sysfs(struct device *dev) | ||
70 | { | ||
71 | struct gk20a *g = get_gk20a(dev); | ||
72 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
73 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | ||
74 | struct vgpu_ecc_stat *stats; | ||
75 | struct dev_ext_attribute *attrs; | ||
76 | int err, i, count; | ||
77 | |||
78 | err = vgpu_ecc_get_info(g); | ||
79 | if (unlikely(err)) { | ||
80 | nvgpu_err(g, "ecc: cannot get ECC info: %d", err); | ||
81 | return err; | ||
82 | } | ||
83 | |||
84 | stats = priv->ecc_stats; | ||
85 | count = priv->ecc_stats_count; | ||
86 | |||
87 | attrs = nvgpu_kzalloc(g, count * sizeof(*attrs)); | ||
88 | if (unlikely(!attrs)) { | ||
89 | nvgpu_err(g, "ecc: no memory"); | ||
90 | vgpu_ecc_remove_info(g); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | for (i = 0; i < count; i++) { | ||
95 | sysfs_attr_init(&attrs[i].attr.attr); | ||
96 | attrs[i].attr.attr.name = stats[i].name; | ||
97 | attrs[i].attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(S_IRUGO); | ||
98 | attrs[i].attr.show = vgpu_ecc_stat_show; | ||
99 | attrs[i].attr.store = NULL; | ||
100 | attrs[i].var = &stats[i]; | ||
101 | |||
102 | err = device_create_file(dev, &attrs[i].attr); | ||
103 | if (unlikely(err)) { | ||
104 | nvgpu_warn(g, "ecc: cannot create file \"%s\": %d", | ||
105 | stats[i].name, err); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | l->ecc_attrs = attrs; | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static void vgpu_remove_ecc_sysfs(struct device *dev) | ||
114 | { | ||
115 | struct gk20a *g = get_gk20a(dev); | ||
116 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
117 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | ||
118 | int i; | ||
119 | |||
120 | if (l->ecc_attrs) { | ||
121 | for (i = 0; i < priv->ecc_stats_count; i++) | ||
122 | device_remove_file(dev, &l->ecc_attrs[i].attr); | ||
123 | |||
124 | nvgpu_kfree(g, l->ecc_attrs); | ||
125 | l->ecc_attrs = NULL; | ||
126 | } | ||
127 | |||
128 | vgpu_ecc_remove_info(g); | ||
129 | } | ||
130 | |||
131 | void vgpu_create_sysfs(struct device *dev) | ||
132 | { | ||
133 | if (device_create_file(dev, &dev_attr_load)) | ||
134 | dev_err(dev, "Failed to create vgpu sysfs attributes!\n"); | ||
135 | |||
136 | vgpu_create_ecc_sysfs(dev); | ||
137 | } | ||
138 | |||
139 | void vgpu_remove_sysfs(struct device *dev) | ||
140 | { | ||
141 | device_remove_file(dev, &dev_attr_load); | ||
142 | vgpu_remove_ecc_sysfs(dev); | ||
143 | } | ||