GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / staging / gasket / gasket_sysfs.c
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. */
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. */
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. */
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  */
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
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
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
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
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
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
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 *
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
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         put_mapping(mapping);
347 }
348 EXPORT_SYMBOL(gasket_sysfs_put_attr);
349
350 ssize_t gasket_sysfs_register_store(struct device *device,
351                                     struct device_attribute *attr,
352                                     const char *buf, size_t count)
353 {
354         ulong parsed_value = 0;
355         struct gasket_sysfs_mapping *mapping;
356         struct gasket_dev *gasket_dev;
357         struct gasket_sysfs_attribute *gasket_attr;
358
359         if (count < 3 || buf[0] != '0' || buf[1] != 'x') {
360                 dev_err(device,
361                         "sysfs register write format: \"0x<hex value>\"\n");
362                 return -EINVAL;
363         }
364
365         if (kstrtoul(buf, 16, &parsed_value) != 0) {
366                 dev_err(device,
367                         "Unable to parse input as 64-bit hex value: %s\n", buf);
368                 return -EINVAL;
369         }
370
371         mapping = get_mapping(device);
372         if (!mapping) {
373                 dev_err(device, "Device driver may have been removed\n");
374                 return 0;
375         }
376
377         gasket_dev = mapping->gasket_dev;
378         if (!gasket_dev) {
379                 dev_err(device, "Device driver may have been removed\n");
380                 put_mapping(mapping);
381                 return 0;
382         }
383
384         gasket_attr = gasket_sysfs_get_attr(device, attr);
385         if (!gasket_attr) {
386                 put_mapping(mapping);
387                 return count;
388         }
389
390         gasket_dev_write_64(gasket_dev, parsed_value,
391                             gasket_attr->data.bar_address.bar,
392                             gasket_attr->data.bar_address.offset);
393
394         if (gasket_attr->write_callback)
395                 gasket_attr->write_callback(gasket_dev, gasket_attr,
396                                             parsed_value);
397
398         gasket_sysfs_put_attr(device, gasket_attr);
399         put_mapping(mapping);
400         return count;
401 }
402 EXPORT_SYMBOL(gasket_sysfs_register_store);