1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * IBM Accelerator Family 'GenWQE' |
4 | * |
5 | * (C) Copyright IBM Corp. 2013 |
6 | * |
7 | * Author: Frank Haverkamp <haver@linux.vnet.ibm.com> |
8 | * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> |
9 | * Author: Michael Jung <mijung@gmx.net> |
10 | * Author: Michael Ruettger <michael@ibmra.de> |
11 | */ |
12 | |
13 | /* |
14 | * Sysfs interfaces for the GenWQE card. There are attributes to query |
15 | * the version of the bitstream as well as some for the driver. For |
16 | * debugging, please also see the debugfs interfaces of this driver. |
17 | */ |
18 | |
19 | #include <linux/kernel.h> |
20 | #include <linux/types.h> |
21 | #include <linux/module.h> |
22 | #include <linux/pci.h> |
23 | #include <linux/string.h> |
24 | #include <linux/fs.h> |
25 | #include <linux/sysfs.h> |
26 | #include <linux/ctype.h> |
27 | #include <linux/device.h> |
28 | |
29 | #include "card_base.h" |
30 | #include "card_ddcb.h" |
31 | |
32 | static const char * const genwqe_types[] = { |
33 | [GENWQE_TYPE_ALTERA_230] = "GenWQE4-230" , |
34 | [GENWQE_TYPE_ALTERA_530] = "GenWQE4-530" , |
35 | [GENWQE_TYPE_ALTERA_A4] = "GenWQE5-A4" , |
36 | [GENWQE_TYPE_ALTERA_A7] = "GenWQE5-A7" , |
37 | }; |
38 | |
39 | static ssize_t status_show(struct device *dev, struct device_attribute *attr, |
40 | char *buf) |
41 | { |
42 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
43 | const char *cs[GENWQE_CARD_STATE_MAX] = { "unused" , "used" , "error" }; |
44 | |
45 | return sprintf(buf, fmt: "%s\n" , cs[cd->card_state]); |
46 | } |
47 | static DEVICE_ATTR_RO(status); |
48 | |
49 | static ssize_t appid_show(struct device *dev, struct device_attribute *attr, |
50 | char *buf) |
51 | { |
52 | char app_name[5]; |
53 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
54 | |
55 | genwqe_read_app_id(cd, app_name, len: sizeof(app_name)); |
56 | return sprintf(buf, fmt: "%s\n" , app_name); |
57 | } |
58 | static DEVICE_ATTR_RO(appid); |
59 | |
60 | static ssize_t version_show(struct device *dev, struct device_attribute *attr, |
61 | char *buf) |
62 | { |
63 | u64 slu_id, app_id; |
64 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
65 | |
66 | slu_id = __genwqe_readq(cd, IO_SLU_UNITCFG); |
67 | app_id = __genwqe_readq(cd, IO_APP_UNITCFG); |
68 | |
69 | return sprintf(buf, fmt: "%016llx.%016llx\n" , slu_id, app_id); |
70 | } |
71 | static DEVICE_ATTR_RO(version); |
72 | |
73 | static ssize_t type_show(struct device *dev, struct device_attribute *attr, |
74 | char *buf) |
75 | { |
76 | u8 card_type; |
77 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
78 | |
79 | card_type = genwqe_card_type(cd); |
80 | return sprintf(buf, fmt: "%s\n" , (card_type >= ARRAY_SIZE(genwqe_types)) ? |
81 | "invalid" : genwqe_types[card_type]); |
82 | } |
83 | static DEVICE_ATTR_RO(type); |
84 | |
85 | static ssize_t tempsens_show(struct device *dev, struct device_attribute *attr, |
86 | char *buf) |
87 | { |
88 | u64 tempsens; |
89 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
90 | |
91 | tempsens = __genwqe_readq(cd, IO_SLU_TEMPERATURE_SENSOR); |
92 | return sprintf(buf, fmt: "%016llx\n" , tempsens); |
93 | } |
94 | static DEVICE_ATTR_RO(tempsens); |
95 | |
96 | static ssize_t freerunning_timer_show(struct device *dev, |
97 | struct device_attribute *attr, |
98 | char *buf) |
99 | { |
100 | u64 t; |
101 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
102 | |
103 | t = __genwqe_readq(cd, IO_SLC_FREE_RUNNING_TIMER); |
104 | return sprintf(buf, fmt: "%016llx\n" , t); |
105 | } |
106 | static DEVICE_ATTR_RO(freerunning_timer); |
107 | |
108 | static ssize_t queue_working_time_show(struct device *dev, |
109 | struct device_attribute *attr, |
110 | char *buf) |
111 | { |
112 | u64 t; |
113 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
114 | |
115 | t = __genwqe_readq(cd, IO_SLC_QUEUE_WTIME); |
116 | return sprintf(buf, fmt: "%016llx\n" , t); |
117 | } |
118 | static DEVICE_ATTR_RO(queue_working_time); |
119 | |
120 | static ssize_t base_clock_show(struct device *dev, |
121 | struct device_attribute *attr, |
122 | char *buf) |
123 | { |
124 | u64 base_clock; |
125 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
126 | |
127 | base_clock = genwqe_base_clock_frequency(cd); |
128 | return sprintf(buf, fmt: "%lld\n" , base_clock); |
129 | } |
130 | static DEVICE_ATTR_RO(base_clock); |
131 | |
132 | /* |
133 | * curr_bitstream_show() - Show the current bitstream id |
134 | * |
135 | * There is a bug in some old versions of the CPLD which selects the |
136 | * bitstream, which causes the IO_SLU_BITSTREAM register to report |
137 | * unreliable data in very rare cases. This makes this sysfs |
138 | * unreliable up to the point were a new CPLD version is being used. |
139 | * |
140 | * Unfortunately there is no automatic way yet to query the CPLD |
141 | * version, such that you need to manually ensure via programming |
142 | * tools that you have a recent version of the CPLD software. |
143 | * |
144 | * The proposed circumvention is to use a special recovery bitstream |
145 | * on the backup partition (0) to identify problems while loading the |
146 | * image. |
147 | */ |
148 | static ssize_t curr_bitstream_show(struct device *dev, |
149 | struct device_attribute *attr, char *buf) |
150 | { |
151 | int curr_bitstream; |
152 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
153 | |
154 | curr_bitstream = __genwqe_readq(cd, IO_SLU_BITSTREAM) & 0x1; |
155 | return sprintf(buf, fmt: "%d\n" , curr_bitstream); |
156 | } |
157 | static DEVICE_ATTR_RO(curr_bitstream); |
158 | |
159 | /* |
160 | * next_bitstream_show() - Show the next activated bitstream |
161 | * |
162 | * IO_SLC_CFGREG_SOFTRESET: This register can only be accessed by the PF. |
163 | */ |
164 | static ssize_t next_bitstream_show(struct device *dev, |
165 | struct device_attribute *attr, char *buf) |
166 | { |
167 | int next_bitstream; |
168 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
169 | |
170 | switch ((cd->softreset & 0xc) >> 2) { |
171 | case 0x2: |
172 | next_bitstream = 0; |
173 | break; |
174 | case 0x3: |
175 | next_bitstream = 1; |
176 | break; |
177 | default: |
178 | next_bitstream = -1; |
179 | break; /* error */ |
180 | } |
181 | return sprintf(buf, fmt: "%d\n" , next_bitstream); |
182 | } |
183 | |
184 | static ssize_t next_bitstream_store(struct device *dev, |
185 | struct device_attribute *attr, |
186 | const char *buf, size_t count) |
187 | { |
188 | int partition; |
189 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
190 | |
191 | if (kstrtoint(s: buf, base: 0, res: &partition) < 0) |
192 | return -EINVAL; |
193 | |
194 | switch (partition) { |
195 | case 0x0: |
196 | cd->softreset = 0x78; |
197 | break; |
198 | case 0x1: |
199 | cd->softreset = 0x7c; |
200 | break; |
201 | default: |
202 | return -EINVAL; |
203 | } |
204 | |
205 | __genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, val: cd->softreset); |
206 | return count; |
207 | } |
208 | static DEVICE_ATTR_RW(next_bitstream); |
209 | |
210 | static ssize_t reload_bitstream_store(struct device *dev, |
211 | struct device_attribute *attr, |
212 | const char *buf, size_t count) |
213 | { |
214 | int reload; |
215 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
216 | |
217 | if (kstrtoint(s: buf, base: 0, res: &reload) < 0) |
218 | return -EINVAL; |
219 | |
220 | if (reload == 0x1) { |
221 | if (cd->card_state == GENWQE_CARD_UNUSED || |
222 | cd->card_state == GENWQE_CARD_USED) |
223 | cd->card_state = GENWQE_CARD_RELOAD_BITSTREAM; |
224 | else |
225 | return -EIO; |
226 | } else { |
227 | return -EINVAL; |
228 | } |
229 | |
230 | return count; |
231 | } |
232 | static DEVICE_ATTR_WO(reload_bitstream); |
233 | |
234 | /* |
235 | * Create device_attribute structures / params: name, mode, show, store |
236 | * additional flag if valid in VF |
237 | */ |
238 | static struct attribute *genwqe_attributes[] = { |
239 | &dev_attr_tempsens.attr, |
240 | &dev_attr_next_bitstream.attr, |
241 | &dev_attr_curr_bitstream.attr, |
242 | &dev_attr_base_clock.attr, |
243 | &dev_attr_type.attr, |
244 | &dev_attr_version.attr, |
245 | &dev_attr_appid.attr, |
246 | &dev_attr_status.attr, |
247 | &dev_attr_freerunning_timer.attr, |
248 | &dev_attr_queue_working_time.attr, |
249 | &dev_attr_reload_bitstream.attr, |
250 | NULL, |
251 | }; |
252 | |
253 | static struct attribute *genwqe_normal_attributes[] = { |
254 | &dev_attr_type.attr, |
255 | &dev_attr_version.attr, |
256 | &dev_attr_appid.attr, |
257 | &dev_attr_status.attr, |
258 | &dev_attr_freerunning_timer.attr, |
259 | &dev_attr_queue_working_time.attr, |
260 | NULL, |
261 | }; |
262 | |
263 | /* |
264 | * genwqe_is_visible() - Determine if sysfs attribute should be visible or not |
265 | * |
266 | * VFs have restricted mmio capabilities, so not all sysfs entries |
267 | * are allowed in VFs. |
268 | */ |
269 | static umode_t genwqe_is_visible(struct kobject *kobj, |
270 | struct attribute *attr, int n) |
271 | { |
272 | unsigned int j; |
273 | struct device *dev = kobj_to_dev(kobj); |
274 | struct genwqe_dev *cd = dev_get_drvdata(dev); |
275 | umode_t mode = attr->mode; |
276 | |
277 | if (genwqe_is_privileged(cd)) |
278 | return mode; |
279 | |
280 | for (j = 0; genwqe_normal_attributes[j] != NULL; j++) |
281 | if (genwqe_normal_attributes[j] == attr) |
282 | return mode; |
283 | |
284 | return 0; |
285 | } |
286 | |
287 | static struct attribute_group genwqe_attribute_group = { |
288 | .is_visible = genwqe_is_visible, |
289 | .attrs = genwqe_attributes, |
290 | }; |
291 | |
292 | const struct attribute_group *genwqe_attribute_groups[] = { |
293 | &genwqe_attribute_group, |
294 | NULL, |
295 | }; |
296 | |