root/drivers/staging/gasket/gasket_sysfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. release_entry
  2. get_mapping
  3. put_mapping
  4. put_mapping_n
  5. gasket_sysfs_init
  6. gasket_sysfs_create_mapping
  7. gasket_sysfs_create_entries
  8. gasket_sysfs_remove_mapping
  9. gasket_sysfs_get_device_data
  10. gasket_sysfs_put_device_data
  11. gasket_sysfs_get_attr
  12. gasket_sysfs_put_attr
  13. gasket_sysfs_register_store

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

/* [<][>][^][v][top][bottom][index][help] */