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 initializing mapping\n");
227 		return -EINVAL;
228 	}
229 
230 	mutex_lock(&mapping->mutex);
231 	for (i = 0; attrs[i].attr.attr.name != NULL; i++) {
232 		if (mapping->attribute_count == GASKET_SYSFS_MAX_NODES) {
233 			dev_err(device,
234 				"Maximum number of sysfs nodes reached for device\n");
235 			mutex_unlock(&mapping->mutex);
236 			put_mapping(mapping);
237 			return -ENOMEM;
238 		}
239 
240 		ret = device_create_file(device, &attrs[i].attr);
241 		if (ret) {
242 			dev_dbg(device, "Unable to create device entries\n");
243 			mutex_unlock(&mapping->mutex);
244 			put_mapping(mapping);
245 			return ret;
246 		}
247 
248 		mapping->attributes[mapping->attribute_count] = attrs[i];
249 		++mapping->attribute_count;
250 	}
251 
252 	mutex_unlock(&mapping->mutex);
253 	put_mapping(mapping);
254 	return 0;
255 }
256 EXPORT_SYMBOL(gasket_sysfs_create_entries);
257 
gasket_sysfs_remove_mapping(struct device * device)258 void gasket_sysfs_remove_mapping(struct device *device)
259 {
260 	struct gasket_sysfs_mapping *mapping = get_mapping(device);
261 
262 	if (!mapping) {
263 		dev_err(device,
264 			"Attempted to remove non-existent sysfs mapping to device\n");
265 		return;
266 	}
267 
268 	put_mapping_n(mapping, 2);
269 }
270 
gasket_sysfs_get_device_data(struct device * device)271 struct gasket_dev *gasket_sysfs_get_device_data(struct device *device)
272 {
273 	struct gasket_sysfs_mapping *mapping = get_mapping(device);
274 
275 	if (!mapping) {
276 		dev_err(device, "device not registered\n");
277 		return NULL;
278 	}
279 
280 	return mapping->gasket_dev;
281 }
282 EXPORT_SYMBOL(gasket_sysfs_get_device_data);
283 
gasket_sysfs_put_device_data(struct device * device,struct gasket_dev * dev)284 void gasket_sysfs_put_device_data(struct device *device, struct gasket_dev *dev)
285 {
286 	struct gasket_sysfs_mapping *mapping = get_mapping(device);
287 
288 	if (!mapping)
289 		return;
290 
291 	/* See comment of put_mapping_n() for why the '2' is necessary. */
292 	put_mapping_n(mapping, 2);
293 }
294 EXPORT_SYMBOL(gasket_sysfs_put_device_data);
295 
296 struct gasket_sysfs_attribute *
gasket_sysfs_get_attr(struct device * device,struct device_attribute * attr)297 gasket_sysfs_get_attr(struct device *device, struct device_attribute *attr)
298 {
299 	int i;
300 	int num_attrs;
301 	struct gasket_sysfs_mapping *mapping = get_mapping(device);
302 	struct gasket_sysfs_attribute *attrs = NULL;
303 
304 	if (!mapping)
305 		return NULL;
306 
307 	attrs = mapping->attributes;
308 	num_attrs = mapping->attribute_count;
309 	for (i = 0; i < num_attrs; ++i) {
310 		if (!strcmp(attrs[i].attr.attr.name, attr->attr.name))
311 			return &attrs[i];
312 	}
313 
314 	dev_err(device, "Unable to find match for device_attribute %s\n",
315 		attr->attr.name);
316 	return NULL;
317 }
318 EXPORT_SYMBOL(gasket_sysfs_get_attr);
319 
gasket_sysfs_put_attr(struct device * device,struct gasket_sysfs_attribute * attr)320 void gasket_sysfs_put_attr(struct device *device,
321 			   struct gasket_sysfs_attribute *attr)
322 {
323 	int i;
324 	int num_attrs;
325 	struct gasket_sysfs_mapping *mapping = get_mapping(device);
326 	struct gasket_sysfs_attribute *attrs = NULL;
327 
328 	if (!mapping)
329 		return;
330 
331 	attrs = mapping->attributes;
332 	num_attrs = mapping->attribute_count;
333 	for (i = 0; i < num_attrs; ++i) {
334 		if (&attrs[i] == attr) {
335 			put_mapping_n(mapping, 2);
336 			return;
337 		}
338 	}
339 
340 	dev_err(device, "Unable to put unknown attribute: %s\n",
341 		attr->attr.attr.name);
342 	put_mapping(mapping);
343 }
344 EXPORT_SYMBOL(gasket_sysfs_put_attr);
345 
gasket_sysfs_register_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)346 ssize_t gasket_sysfs_register_store(struct device *device,
347 				    struct device_attribute *attr,
348 				    const char *buf, size_t count)
349 {
350 	ulong parsed_value = 0;
351 	struct gasket_sysfs_mapping *mapping;
352 	struct gasket_dev *gasket_dev;
353 	struct gasket_sysfs_attribute *gasket_attr;
354 
355 	if (count < 3 || buf[0] != '0' || buf[1] != 'x') {
356 		dev_err(device,
357 			"sysfs register write format: \"0x<hex value>\"\n");
358 		return -EINVAL;
359 	}
360 
361 	if (kstrtoul(buf, 16, &parsed_value) != 0) {
362 		dev_err(device,
363 			"Unable to parse input as 64-bit hex value: %s\n", buf);
364 		return -EINVAL;
365 	}
366 
367 	mapping = get_mapping(device);
368 	if (!mapping) {
369 		dev_err(device, "Device driver may have been removed\n");
370 		return 0;
371 	}
372 
373 	gasket_dev = mapping->gasket_dev;
374 	if (!gasket_dev) {
375 		dev_err(device, "Device driver may have been removed\n");
376 		put_mapping(mapping);
377 		return 0;
378 	}
379 
380 	gasket_attr = gasket_sysfs_get_attr(device, attr);
381 	if (!gasket_attr) {
382 		put_mapping(mapping);
383 		return count;
384 	}
385 
386 	gasket_dev_write_64(gasket_dev, parsed_value,
387 			    gasket_attr->data.bar_address.bar,
388 			    gasket_attr->data.bar_address.offset);
389 
390 	if (gasket_attr->write_callback)
391 		gasket_attr->write_callback(gasket_dev, gasket_attr,
392 					    parsed_value);
393 
394 	gasket_sysfs_put_attr(device, gasket_attr);
395 	put_mapping(mapping);
396 	return count;
397 }
398 EXPORT_SYMBOL(gasket_sysfs_register_store);
399