1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018 Google, Inc. */
3 #include "gasket_sysfs.h"
5 #include "gasket_core.h"
7 #include <linux/device.h>
8 #include <linux/printk.h>
11 * Pair of kernel device and user-specified pointer. Used in lookups in sysfs
12 * "show" functions to return user data.
15 struct gasket_sysfs_mapping
{
17 * The device bound to this mapping. If this is NULL, then this mapping
20 struct device
*device
;
22 /* The Gasket descriptor for this device. */
23 struct gasket_dev
*gasket_dev
;
25 /* This device's set of sysfs attributes/nodes. */
26 struct gasket_sysfs_attribute
*attributes
;
28 /* The number of live elements in "attributes". */
31 /* Protects structure from simultaneous access. */
34 /* Tracks active users of this mapping. */
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
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.
48 static struct gasket_sysfs_mapping dev_mappings
[GASKET_SYSFS_NUM_MAPPINGS
];
50 /* Callback when a mapping's refcount goes to zero. */
51 static void release_entry(struct kref
*ref
)
53 /* All work is done after the return from kref_put. */
56 /* Look up mapping information for the given device. */
57 static struct gasket_sysfs_mapping
*get_mapping(struct device
*device
)
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
];
68 mutex_unlock(&dev_mappings
[i
].mutex
);
71 dev_dbg(device
, "%s: Mapping to device %s not found\n",
72 __func__
, device
->kobj
.name
);
76 /* Put a reference to a mapping. */
77 static void put_mapping(struct gasket_sysfs_mapping
*mapping
)
80 int num_files_to_remove
= 0;
81 struct device_attribute
*files_to_remove
;
82 struct device
*device
;
85 pr_debug("%s: Mapping should not be NULL\n", __func__
);
89 mutex_lock(&mapping
->mutex
);
90 if (kref_put(&mapping
->refcount
, release_entry
)) {
91 dev_dbg(mapping
->device
, "Removing Gasket sysfs mapping\n");
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.
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
),
105 for (i
= 0; i
< num_files_to_remove
; i
++)
107 mapping
->attributes
[i
].attr
;
109 num_files_to_remove
= 0;
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
;
118 mutex_unlock(&mapping
->mutex
);
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
);
128 * Put a reference to a mapping N times.
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.
134 static void put_mapping_n(struct gasket_sysfs_mapping
*mapping
, int times
)
138 for (i
= 0; i
< times
; i
++)
139 put_mapping(mapping
);
142 void gasket_sysfs_init(void)
146 for (i
= 0; i
< GASKET_SYSFS_NUM_MAPPINGS
; i
++) {
147 dev_mappings
[i
].device
= NULL
;
148 mutex_init(&dev_mappings
[i
].mutex
);
152 int gasket_sysfs_create_mapping(struct device
*device
,
153 struct gasket_dev
*gasket_dev
)
155 struct gasket_sysfs_mapping
*mapping
;
159 * We need a function-level mutex to protect against the same device
160 * being added [multiple times] simultaneously.
162 static DEFINE_MUTEX(function_mutex
);
164 mutex_lock(&function_mutex
);
165 dev_dbg(device
, "Creating sysfs entries for device\n");
167 /* Check that the device we're adding hasn't already been added. */
168 mapping
= get_mapping(device
);
171 "Attempting to re-initialize sysfs mapping for device\n");
172 put_mapping(mapping
);
173 mutex_unlock(&function_mutex
);
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! */
183 mutex_unlock(&dev_mappings
[map_idx
].mutex
);
186 if (map_idx
== GASKET_SYSFS_NUM_MAPPINGS
) {
187 dev_err(device
, "All mappings have been exhausted\n");
188 mutex_unlock(&function_mutex
);
192 dev_dbg(device
, "Creating sysfs mapping for device %s\n",
195 mapping
= &dev_mappings
[map_idx
];
196 mapping
->attributes
= kcalloc(GASKET_SYSFS_MAX_NODES
,
197 sizeof(*mapping
->attributes
),
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
);
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
);
213 /* Don't decrement the refcount here! One open count keeps it alive! */
217 int gasket_sysfs_create_entries(struct device
*device
,
218 const struct gasket_sysfs_attribute
*attrs
)
222 struct gasket_sysfs_mapping
*mapping
= get_mapping(device
);
226 "Creating entries for device without first initializing mapping\n");
230 mutex_lock(&mapping
->mutex
);
231 for (i
= 0; strcmp(attrs
[i
].attr
.attr
.name
, GASKET_ARRAY_END_MARKER
);
233 if (mapping
->attribute_count
== GASKET_SYSFS_MAX_NODES
) {
235 "Maximum number of sysfs nodes reached for device\n");
236 mutex_unlock(&mapping
->mutex
);
237 put_mapping(mapping
);
241 ret
= device_create_file(device
, &attrs
[i
].attr
);
243 dev_dbg(device
, "Unable to create device entries\n");
244 mutex_unlock(&mapping
->mutex
);
245 put_mapping(mapping
);
249 mapping
->attributes
[mapping
->attribute_count
] = attrs
[i
];
250 ++mapping
->attribute_count
;
253 mutex_unlock(&mapping
->mutex
);
254 put_mapping(mapping
);
257 EXPORT_SYMBOL(gasket_sysfs_create_entries
);
259 void gasket_sysfs_remove_mapping(struct device
*device
)
261 struct gasket_sysfs_mapping
*mapping
= get_mapping(device
);
265 "Attempted to remove non-existent sysfs mapping to device\n");
269 put_mapping_n(mapping
, 2);
272 struct gasket_dev
*gasket_sysfs_get_device_data(struct device
*device
)
274 struct gasket_sysfs_mapping
*mapping
= get_mapping(device
);
277 dev_err(device
, "device not registered\n");
281 return mapping
->gasket_dev
;
283 EXPORT_SYMBOL(gasket_sysfs_get_device_data
);
285 void gasket_sysfs_put_device_data(struct device
*device
, struct gasket_dev
*dev
)
287 struct gasket_sysfs_mapping
*mapping
= get_mapping(device
);
292 /* See comment of put_mapping_n() for why the '2' is necessary. */
293 put_mapping_n(mapping
, 2);
295 EXPORT_SYMBOL(gasket_sysfs_put_device_data
);
297 struct gasket_sysfs_attribute
*
298 gasket_sysfs_get_attr(struct device
*device
, struct device_attribute
*attr
)
302 struct gasket_sysfs_mapping
*mapping
= get_mapping(device
);
303 struct gasket_sysfs_attribute
*attrs
= NULL
;
308 attrs
= mapping
->attributes
;
309 num_attrs
= mapping
->attribute_count
;
310 for (i
= 0; i
< num_attrs
; ++i
) {
311 if (!strcmp(attrs
[i
].attr
.attr
.name
, attr
->attr
.name
))
315 dev_err(device
, "Unable to find match for device_attribute %s\n",
319 EXPORT_SYMBOL(gasket_sysfs_get_attr
);
321 void gasket_sysfs_put_attr(struct device
*device
,
322 struct gasket_sysfs_attribute
*attr
)
326 struct gasket_sysfs_mapping
*mapping
= get_mapping(device
);
327 struct gasket_sysfs_attribute
*attrs
= NULL
;
332 attrs
= mapping
->attributes
;
333 num_attrs
= mapping
->attribute_count
;
334 for (i
= 0; i
< num_attrs
; ++i
) {
335 if (&attrs
[i
] == attr
) {
336 put_mapping_n(mapping
, 2);
341 dev_err(device
, "Unable to put unknown attribute: %s\n",
342 attr
->attr
.attr
.name
);
344 EXPORT_SYMBOL(gasket_sysfs_put_attr
);
346 ssize_t
gasket_sysfs_register_store(struct device
*device
,
347 struct device_attribute
*attr
,
348 const char *buf
, size_t count
)
350 ulong parsed_value
= 0;
351 struct gasket_sysfs_mapping
*mapping
;
352 struct gasket_dev
*gasket_dev
;
353 struct gasket_sysfs_attribute
*gasket_attr
;
355 if (count
< 3 || buf
[0] != '0' || buf
[1] != 'x') {
357 "sysfs register write format: \"0x<hex value>\"\n");
361 if (kstrtoul(buf
, 16, &parsed_value
) != 0) {
363 "Unable to parse input as 64-bit hex value: %s\n", buf
);
367 mapping
= get_mapping(device
);
369 dev_err(device
, "Device driver may have been removed\n");
373 gasket_dev
= mapping
->gasket_dev
;
375 dev_err(device
, "Device driver may have been removed\n");
379 gasket_attr
= gasket_sysfs_get_attr(device
, attr
);
381 put_mapping(mapping
);
385 gasket_dev_write_64(gasket_dev
, parsed_value
,
386 gasket_attr
->data
.bar_address
.bar
,
387 gasket_attr
->data
.bar_address
.offset
);
389 if (gasket_attr
->write_callback
)
390 gasket_attr
->write_callback(gasket_dev
, gasket_attr
,
393 gasket_sysfs_put_attr(device
, gasket_attr
);
394 put_mapping(mapping
);
397 EXPORT_SYMBOL(gasket_sysfs_register_store
);