1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018 Google, Inc. */
3 #include "gasket_sysfs.h"
4
5 #include "gasket_core.h"
6
7 #include <linux/device.h>
8 #include <linux/printk.h>
9
10 /*
11 * Pair of kernel device and user-specified pointer. Used in lookups in sysfs
12 * "show" functions to return user data.
13 */
14
15 struct gasket_sysfs_mapping {
16 /*
17 * The device bound to this mapping. If this is NULL, then this mapping
18 * is free.
19 */
20 struct device *device;
21
22 /* The Gasket descriptor for this device. */
23 struct gasket_dev *gasket_dev;
24
25 /* This device's set of sysfs attributes/nodes. */
26 struct gasket_sysfs_attribute *attributes;
27
28 /* The number of live elements in "attributes". */
29 int attribute_count;
30
31 /* Protects structure from simultaneous access. */
32 struct mutex mutex;
33
34 /* Tracks active users of this mapping. */
35 struct kref refcount;
36 };
37
38 /*
39 * Data needed to manage users of this sysfs utility.
40 * Currently has a fixed size; if space is a concern, this can be dynamically
41 * allocated.
42 */
43 /*
44 * 'Global' (file-scoped) list of mappings between devices and gasket_data
45 * pointers. This removes the requirement to have a gasket_sysfs_data
46 * handle in all files.
47 */
48 static struct gasket_sysfs_mapping dev_mappings[GASKET_SYSFS_NUM_MAPPINGS];
49
50 /* Callback when a mapping's refcount goes to zero. */
release_entry(struct kref * ref)51 static void release_entry(struct kref *ref)
52 {
53 /* All work is done after the return from kref_put. */
54 }
55
56 /* Look up mapping information for the given device. */
get_mapping(struct device * device)57 static struct gasket_sysfs_mapping *get_mapping(struct device *device)
58 {
59 int i;
60
61 for (i = 0; i < GASKET_SYSFS_NUM_MAPPINGS; i++) {
62 mutex_lock(&dev_mappings[i].mutex);
63 if (dev_mappings[i].device == device) {
64 kref_get(&dev_mappings[i].refcount);
65 mutex_unlock(&dev_mappings[i].mutex);
66 return &dev_mappings[i];
67 }
68 mutex_unlock(&dev_mappings[i].mutex);
69 }
70
71 dev_dbg(device, "%s: Mapping to device %s not found\n",
72 __func__, device->kobj.name);
73 return NULL;
74 }
75
76 /* Put a reference to a mapping. */
put_mapping(struct gasket_sysfs_mapping * mapping)77 static void put_mapping(struct gasket_sysfs_mapping *mapping)
78 {
79 int i;
80 int num_files_to_remove = 0;
81 struct device_attribute *files_to_remove;
82 struct device *device;
83
84 if (!mapping) {
85 pr_debug("%s: Mapping should not be NULL\n", __func__);
86 return;
87 }
88
89 mutex_lock(&mapping->mutex);
90 if (kref_put(&mapping->refcount, release_entry)) {
91 dev_dbg(mapping->device, "Removing Gasket sysfs mapping\n");
92 /*
93 * We can't remove the sysfs nodes in the kref callback, since
94 * device_remove_file() blocks until the node is free.
95 * Readers/writers of sysfs nodes, though, will be blocked on
96 * the mapping mutex, resulting in deadlock. To fix this, the
97 * sysfs nodes are removed outside the lock.
98 */
99 device = mapping->device;
100 num_files_to_remove = mapping->attribute_count;
101 files_to_remove = kcalloc(num_files_to_remove,
102 sizeof(*files_to_remove),
103 GFP_KERNEL);
104 if (files_to_remove)
105 for (i = 0; i < num_files_to_remove; i++)
106 files_to_remove[i] =
107 mapping->attributes[i].attr;
108 else
109 num_files_to_remove = 0;
110
111 kfree(mapping->attributes);
112 mapping->attributes = NULL;
113 mapping->attribute_count = 0;
114 put_device(mapping->device);
115 mapping->device = NULL;
116 mapping->gasket_dev = NULL;
117 }
118 mutex_unlock(&mapping->mutex);
119
120 if (num_files_to_remove != 0) {
121 for (i = 0; i < num_files_to_remove; ++i)
122 device_remove_file(device, &files_to_remove[i]);
123 kfree(files_to_remove);
124 }
125 }
126
127 /*
128 * Put a reference to a mapping N times.
129 *
130 * In higher-level resource acquire/release function pairs, the release function
131 * will need to release a mapping 2x - once for the refcount taken in the
132 * release function itself, and once for the count taken in the acquire call.
133 */
put_mapping_n(struct gasket_sysfs_mapping * mapping,int times)134 static void put_mapping_n(struct gasket_sysfs_mapping *mapping, int times)
135 {
136 int i;
137
138 for (i = 0; i < times; i++)
139 put_mapping(mapping);
140 }
141
gasket_sysfs_init(void)142 void gasket_sysfs_init(void)
143 {
144 int i;
145
146 for (i = 0; i < GASKET_SYSFS_NUM_MAPPINGS; i++) {
147 dev_mappings[i].device = NULL;
148 mutex_init(&dev_mappings[i].mutex);
149 }
150 }
151
gasket_sysfs_create_mapping(struct device * device,struct gasket_dev * gasket_dev)152 int gasket_sysfs_create_mapping(struct device *device,
153 struct gasket_dev *gasket_dev)
154 {
155 struct gasket_sysfs_mapping *mapping;
156 int map_idx = -1;
157
158 /*
159 * We need a function-level mutex to protect against the same device
160 * being added [multiple times] simultaneously.
161 */
162 static DEFINE_MUTEX(function_mutex);
163
164 mutex_lock(&function_mutex);
165 dev_dbg(device, "Creating sysfs entries for device\n");
166
167 /* Check that the device we're adding hasn't already been added. */
168 mapping = get_mapping(device);
169 if (mapping) {
170 dev_err(device,
171 "Attempting to re-initialize sysfs mapping for device\n");
172 put_mapping(mapping);
173 mutex_unlock(&function_mutex);
174 return -EBUSY;
175 }
176
177 /* Find the first empty entry in the array. */
178 for (map_idx = 0; map_idx < GASKET_SYSFS_NUM_MAPPINGS; ++map_idx) {
179 mutex_lock(&dev_mappings[map_idx].mutex);
180 if (!dev_mappings[map_idx].device)
181 /* Break with the mutex held! */
182 break;
183 mutex_unlock(&dev_mappings[map_idx].mutex);
184 }
185
186 if (map_idx == GASKET_SYSFS_NUM_MAPPINGS) {
187 dev_err(device, "All mappings have been exhausted\n");
188 mutex_unlock(&function_mutex);
189 return -ENOMEM;
190 }
191
192 dev_dbg(device, "Creating sysfs mapping for device %s\n",
193 device->kobj.name);
194
195 mapping = &dev_mappings[map_idx];
196 mapping->attributes = kcalloc(GASKET_SYSFS_MAX_NODES,
197 sizeof(*mapping->attributes),
198 GFP_KERNEL);
199 if (!mapping->attributes) {
200 dev_dbg(device, "Unable to allocate sysfs attribute array\n");
201 mutex_unlock(&mapping->mutex);
202 mutex_unlock(&function_mutex);
203 return -ENOMEM;
204 }
205
206 kref_init(&mapping->refcount);
207 mapping->device = get_device(device);
208 mapping->gasket_dev = gasket_dev;
209 mapping->attribute_count = 0;
210 mutex_unlock(&mapping->mutex);
211 mutex_unlock(&function_mutex);
212
213 /* Don't decrement the refcount here! One open count keeps it alive! */
214 return 0;
215 }
216
gasket_sysfs_create_entries(struct device * device,const struct gasket_sysfs_attribute * attrs)217 int gasket_sysfs_create_entries(struct device *device,
218 const struct gasket_sysfs_attribute *attrs)
219 {
220 int i;
221 int ret;
222 struct gasket_sysfs_mapping *mapping = get_mapping(device);
223
224 if (!mapping) {
225 dev_dbg(device,
226 "Creating entries for device without first "
227 "initializing mapping\n");
228 return -EINVAL;
229 }
230
231 mutex_lock(&mapping->mutex);
232 for (i = 0; strcmp(attrs[i].attr.attr.name, GASKET_ARRAY_END_MARKER);
233 i++) {
234 if (mapping->attribute_count == GASKET_SYSFS_MAX_NODES) {
235 dev_err(device,
236 "Maximum number of sysfs nodes reached for "
237 "device\n");
238 mutex_unlock(&mapping->mutex);
239 put_mapping(mapping);
240 return -ENOMEM;
241 }
242
243 ret = device_create_file(device, &attrs[i].attr);
244 if (ret) {
245 dev_dbg(device, "Unable to create device entries\n");
246 mutex_unlock(&mapping->mutex);
247 put_mapping(mapping);
248 return ret;
249 }
250
251 mapping->attributes[mapping->attribute_count] = attrs[i];
252 ++mapping->attribute_count;
253 }
254
255 mutex_unlock(&mapping->mutex);
256 put_mapping(mapping);
257 return 0;
258 }
259 EXPORT_SYMBOL(gasket_sysfs_create_entries);
260
gasket_sysfs_remove_mapping(struct device * device)261 void gasket_sysfs_remove_mapping(struct device *device)
262 {
263 struct gasket_sysfs_mapping *mapping = get_mapping(device);
264
265 if (!mapping) {
266 dev_err(device,
267 "Attempted to remove non-existent sysfs mapping to "
268 "device\n");
269 return;
270 }
271
272 put_mapping_n(mapping, 2);
273 }
274
gasket_sysfs_get_device_data(struct device * device)275 struct gasket_dev *gasket_sysfs_get_device_data(struct device *device)
276 {
277 struct gasket_sysfs_mapping *mapping = get_mapping(device);
278
279 if (!mapping) {
280 dev_err(device, "device not registered\n");
281 return NULL;
282 }
283
284 return mapping->gasket_dev;
285 }
286 EXPORT_SYMBOL(gasket_sysfs_get_device_data);
287
gasket_sysfs_put_device_data(struct device * device,struct gasket_dev * dev)288 void gasket_sysfs_put_device_data(struct device *device, struct gasket_dev *dev)
289 {
290 struct gasket_sysfs_mapping *mapping = get_mapping(device);
291
292 if (!mapping)
293 return;
294
295 /* See comment of put_mapping_n() for why the '2' is necessary. */
296 put_mapping_n(mapping, 2);
297 }
298 EXPORT_SYMBOL(gasket_sysfs_put_device_data);
299
300 struct gasket_sysfs_attribute *
gasket_sysfs_get_attr(struct device * device,struct device_attribute * attr)301 gasket_sysfs_get_attr(struct device *device, struct device_attribute *attr)
302 {
303 int i;
304 int num_attrs;
305 struct gasket_sysfs_mapping *mapping = get_mapping(device);
306 struct gasket_sysfs_attribute *attrs = NULL;
307
308 if (!mapping)
309 return NULL;
310
311 attrs = mapping->attributes;
312 num_attrs = mapping->attribute_count;
313 for (i = 0; i < num_attrs; ++i) {
314 if (!strcmp(attrs[i].attr.attr.name, attr->attr.name))
315 return &attrs[i];
316 }
317
318 dev_err(device, "Unable to find match for device_attribute %s\n",
319 attr->attr.name);
320 return NULL;
321 }
322 EXPORT_SYMBOL(gasket_sysfs_get_attr);
323
gasket_sysfs_put_attr(struct device * device,struct gasket_sysfs_attribute * attr)324 void gasket_sysfs_put_attr(struct device *device,
325 struct gasket_sysfs_attribute *attr)
326 {
327 int i;
328 int num_attrs;
329 struct gasket_sysfs_mapping *mapping = get_mapping(device);
330 struct gasket_sysfs_attribute *attrs = NULL;
331
332 if (!mapping)
333 return;
334
335 attrs = mapping->attributes;
336 num_attrs = mapping->attribute_count;
337 for (i = 0; i < num_attrs; ++i) {
338 if (&attrs[i] == attr) {
339 put_mapping_n(mapping, 2);
340 return;
341 }
342 }
343
344 dev_err(device, "Unable to put unknown attribute: %s\n",
345 attr->attr.attr.name);
346 }
347 EXPORT_SYMBOL(gasket_sysfs_put_attr);
348
gasket_sysfs_register_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)349 ssize_t gasket_sysfs_register_store(struct device *device,
350 struct device_attribute *attr,
351 const char *buf, size_t count)
352 {
353 ulong parsed_value = 0;
354 struct gasket_sysfs_mapping *mapping;
355 struct gasket_dev *gasket_dev;
356 struct gasket_sysfs_attribute *gasket_attr;
357
358 if (count < 3 || buf[0] != '0' || buf[1] != 'x') {
359 dev_err(device,
360 "sysfs register write format: \"0x<hex value>\"\n");
361 return -EINVAL;
362 }
363
364 if (kstrtoul(buf, 16, &parsed_value) != 0) {
365 dev_err(device,
366 "Unable to parse input as 64-bit hex value: %s\n", buf);
367 return -EINVAL;
368 }
369
370 mapping = get_mapping(device);
371 if (!mapping) {
372 dev_err(device, "Device driver may have been removed\n");
373 return 0;
374 }
375
376 gasket_dev = mapping->gasket_dev;
377 if (!gasket_dev) {
378 dev_err(device, "Device driver may have been removed\n");
379 return 0;
380 }
381
382 gasket_attr = gasket_sysfs_get_attr(device, attr);
383 if (!gasket_attr) {
384 put_mapping(mapping);
385 return count;
386 }
387
388 gasket_dev_write_64(gasket_dev, parsed_value,
389 gasket_attr->data.bar_address.bar,
390 gasket_attr->data.bar_address.offset);
391
392 if (gasket_attr->write_callback)
393 gasket_attr->write_callback(gasket_dev, gasket_attr,
394 parsed_value);
395
396 gasket_sysfs_put_attr(device, gasket_attr);
397 put_mapping(mapping);
398 return count;
399 }
400 EXPORT_SYMBOL(gasket_sysfs_register_store);
401