diff options
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/vgpu/sysfs_vgpu.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/vgpu/sysfs_vgpu.c b/drivers/gpu/nvgpu/os/linux/vgpu/sysfs_vgpu.c index 57aad4b4..30ca7f53 100644 --- a/drivers/gpu/nvgpu/os/linux/vgpu/sysfs_vgpu.c +++ b/drivers/gpu/nvgpu/os/linux/vgpu/sysfs_vgpu.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <nvgpu/vgpu/vgpu.h> | 18 | #include <nvgpu/vgpu/vgpu.h> |
19 | 19 | ||
20 | #include "os/linux/platform_gk20a.h" | 20 | #include "os/linux/platform_gk20a.h" |
21 | #include "os/linux/os_linux.h" | ||
22 | #include "vgpu/ecc_vgpu.h" | ||
21 | 23 | ||
22 | static ssize_t vgpu_load_show(struct device *dev, | 24 | static ssize_t vgpu_load_show(struct device *dev, |
23 | struct device_attribute *attr, | 25 | struct device_attribute *attr, |
@@ -38,13 +40,104 @@ static ssize_t vgpu_load_show(struct device *dev, | |||
38 | } | 40 | } |
39 | static DEVICE_ATTR(load, S_IRUGO, vgpu_load_show, NULL); | 41 | static DEVICE_ATTR(load, S_IRUGO, vgpu_load_show, NULL); |
40 | 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); | ||
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 | |||
41 | void vgpu_create_sysfs(struct device *dev) | 131 | void vgpu_create_sysfs(struct device *dev) |
42 | { | 132 | { |
43 | if (device_create_file(dev, &dev_attr_load)) | 133 | if (device_create_file(dev, &dev_attr_load)) |
44 | dev_err(dev, "Failed to create vgpu sysfs attributes!\n"); | 134 | dev_err(dev, "Failed to create vgpu sysfs attributes!\n"); |
135 | |||
136 | vgpu_create_ecc_sysfs(dev); | ||
45 | } | 137 | } |
46 | 138 | ||
47 | void vgpu_remove_sysfs(struct device *dev) | 139 | void vgpu_remove_sysfs(struct device *dev) |
48 | { | 140 | { |
49 | device_remove_file(dev, &dev_attr_load); | 141 | device_remove_file(dev, &dev_attr_load); |
142 | vgpu_remove_ecc_sysfs(dev); | ||
50 | } | 143 | } |