root/drivers/dma/qcom/hidma_mgmt_sys.c

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

DEFINITIONS

This source file includes following definitions.
  1. IMPLEMENT_GETSET
  2. set_weight
  3. show_values
  4. set_values
  5. show_values_channel
  6. set_values_channel
  7. create_sysfs_entry
  8. create_sysfs_entry_channel
  9. hidma_mgmt_init_sys

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Qualcomm Technologies HIDMA Management SYS interface
   4  *
   5  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
   6  */
   7 
   8 #include <linux/sysfs.h>
   9 #include <linux/platform_device.h>
  10 
  11 #include "hidma_mgmt.h"
  12 
  13 struct hidma_chan_attr {
  14         struct hidma_mgmt_dev *mdev;
  15         int index;
  16         struct kobj_attribute attr;
  17 };
  18 
  19 struct hidma_mgmt_fileinfo {
  20         char *name;
  21         int mode;
  22         int (*get)(struct hidma_mgmt_dev *mdev);
  23         int (*set)(struct hidma_mgmt_dev *mdev, u64 val);
  24 };
  25 
  26 #define IMPLEMENT_GETSET(name)                                  \
  27 static int get_##name(struct hidma_mgmt_dev *mdev)              \
  28 {                                                               \
  29         return mdev->name;                                      \
  30 }                                                               \
  31 static int set_##name(struct hidma_mgmt_dev *mdev, u64 val)     \
  32 {                                                               \
  33         u64 tmp;                                                \
  34         int rc;                                                 \
  35                                                                 \
  36         tmp = mdev->name;                                       \
  37         mdev->name = val;                                       \
  38         rc = hidma_mgmt_setup(mdev);                            \
  39         if (rc)                                                 \
  40                 mdev->name = tmp;                               \
  41         return rc;                                              \
  42 }
  43 
  44 #define DECLARE_ATTRIBUTE(name, mode)                           \
  45         {#name, mode, get_##name, set_##name}
  46 
  47 IMPLEMENT_GETSET(hw_version_major)
  48 IMPLEMENT_GETSET(hw_version_minor)
  49 IMPLEMENT_GETSET(max_wr_xactions)
  50 IMPLEMENT_GETSET(max_rd_xactions)
  51 IMPLEMENT_GETSET(max_write_request)
  52 IMPLEMENT_GETSET(max_read_request)
  53 IMPLEMENT_GETSET(dma_channels)
  54 IMPLEMENT_GETSET(chreset_timeout_cycles)
  55 
  56 static int set_priority(struct hidma_mgmt_dev *mdev, unsigned int i, u64 val)
  57 {
  58         u64 tmp;
  59         int rc;
  60 
  61         if (i >= mdev->dma_channels)
  62                 return -EINVAL;
  63 
  64         tmp = mdev->priority[i];
  65         mdev->priority[i] = val;
  66         rc = hidma_mgmt_setup(mdev);
  67         if (rc)
  68                 mdev->priority[i] = tmp;
  69         return rc;
  70 }
  71 
  72 static int set_weight(struct hidma_mgmt_dev *mdev, unsigned int i, u64 val)
  73 {
  74         u64 tmp;
  75         int rc;
  76 
  77         if (i >= mdev->dma_channels)
  78                 return -EINVAL;
  79 
  80         tmp = mdev->weight[i];
  81         mdev->weight[i] = val;
  82         rc = hidma_mgmt_setup(mdev);
  83         if (rc)
  84                 mdev->weight[i] = tmp;
  85         return rc;
  86 }
  87 
  88 static struct hidma_mgmt_fileinfo hidma_mgmt_files[] = {
  89         DECLARE_ATTRIBUTE(hw_version_major, S_IRUGO),
  90         DECLARE_ATTRIBUTE(hw_version_minor, S_IRUGO),
  91         DECLARE_ATTRIBUTE(dma_channels, S_IRUGO),
  92         DECLARE_ATTRIBUTE(chreset_timeout_cycles, S_IRUGO),
  93         DECLARE_ATTRIBUTE(max_wr_xactions, S_IRUGO),
  94         DECLARE_ATTRIBUTE(max_rd_xactions, S_IRUGO),
  95         DECLARE_ATTRIBUTE(max_write_request, S_IRUGO),
  96         DECLARE_ATTRIBUTE(max_read_request, S_IRUGO),
  97 };
  98 
  99 static ssize_t show_values(struct device *dev, struct device_attribute *attr,
 100                            char *buf)
 101 {
 102         struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
 103         unsigned int i;
 104 
 105         buf[0] = 0;
 106 
 107         for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
 108                 if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
 109                         sprintf(buf, "%d\n", hidma_mgmt_files[i].get(mdev));
 110                         break;
 111                 }
 112         }
 113         return strlen(buf);
 114 }
 115 
 116 static ssize_t set_values(struct device *dev, struct device_attribute *attr,
 117                           const char *buf, size_t count)
 118 {
 119         struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
 120         unsigned long tmp;
 121         unsigned int i;
 122         int rc;
 123 
 124         rc = kstrtoul(buf, 0, &tmp);
 125         if (rc)
 126                 return rc;
 127 
 128         for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
 129                 if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
 130                         rc = hidma_mgmt_files[i].set(mdev, tmp);
 131                         if (rc)
 132                                 return rc;
 133 
 134                         break;
 135                 }
 136         }
 137         return count;
 138 }
 139 
 140 static ssize_t show_values_channel(struct kobject *kobj,
 141                                    struct kobj_attribute *attr, char *buf)
 142 {
 143         struct hidma_chan_attr *chattr;
 144         struct hidma_mgmt_dev *mdev;
 145 
 146         buf[0] = 0;
 147         chattr = container_of(attr, struct hidma_chan_attr, attr);
 148         mdev = chattr->mdev;
 149         if (strcmp(attr->attr.name, "priority") == 0)
 150                 sprintf(buf, "%d\n", mdev->priority[chattr->index]);
 151         else if (strcmp(attr->attr.name, "weight") == 0)
 152                 sprintf(buf, "%d\n", mdev->weight[chattr->index]);
 153 
 154         return strlen(buf);
 155 }
 156 
 157 static ssize_t set_values_channel(struct kobject *kobj,
 158                                   struct kobj_attribute *attr, const char *buf,
 159                                   size_t count)
 160 {
 161         struct hidma_chan_attr *chattr;
 162         struct hidma_mgmt_dev *mdev;
 163         unsigned long tmp;
 164         int rc;
 165 
 166         chattr = container_of(attr, struct hidma_chan_attr, attr);
 167         mdev = chattr->mdev;
 168 
 169         rc = kstrtoul(buf, 0, &tmp);
 170         if (rc)
 171                 return rc;
 172 
 173         if (strcmp(attr->attr.name, "priority") == 0) {
 174                 rc = set_priority(mdev, chattr->index, tmp);
 175                 if (rc)
 176                         return rc;
 177         } else if (strcmp(attr->attr.name, "weight") == 0) {
 178                 rc = set_weight(mdev, chattr->index, tmp);
 179                 if (rc)
 180                         return rc;
 181         }
 182         return count;
 183 }
 184 
 185 static int create_sysfs_entry(struct hidma_mgmt_dev *dev, char *name, int mode)
 186 {
 187         struct device_attribute *attrs;
 188         char *name_copy;
 189 
 190         attrs = devm_kmalloc(&dev->pdev->dev,
 191                              sizeof(struct device_attribute), GFP_KERNEL);
 192         if (!attrs)
 193                 return -ENOMEM;
 194 
 195         name_copy = devm_kstrdup(&dev->pdev->dev, name, GFP_KERNEL);
 196         if (!name_copy)
 197                 return -ENOMEM;
 198 
 199         attrs->attr.name = name_copy;
 200         attrs->attr.mode = mode;
 201         attrs->show = show_values;
 202         attrs->store = set_values;
 203         sysfs_attr_init(&attrs->attr);
 204 
 205         return device_create_file(&dev->pdev->dev, attrs);
 206 }
 207 
 208 static int create_sysfs_entry_channel(struct hidma_mgmt_dev *mdev, char *name,
 209                                       int mode, int index,
 210                                       struct kobject *parent)
 211 {
 212         struct hidma_chan_attr *chattr;
 213         char *name_copy;
 214 
 215         chattr = devm_kmalloc(&mdev->pdev->dev, sizeof(*chattr), GFP_KERNEL);
 216         if (!chattr)
 217                 return -ENOMEM;
 218 
 219         name_copy = devm_kstrdup(&mdev->pdev->dev, name, GFP_KERNEL);
 220         if (!name_copy)
 221                 return -ENOMEM;
 222 
 223         chattr->mdev = mdev;
 224         chattr->index = index;
 225         chattr->attr.attr.name = name_copy;
 226         chattr->attr.attr.mode = mode;
 227         chattr->attr.show = show_values_channel;
 228         chattr->attr.store = set_values_channel;
 229         sysfs_attr_init(&chattr->attr.attr);
 230 
 231         return sysfs_create_file(parent, &chattr->attr.attr);
 232 }
 233 
 234 int hidma_mgmt_init_sys(struct hidma_mgmt_dev *mdev)
 235 {
 236         unsigned int i;
 237         int rc;
 238         int required;
 239         struct kobject *chanops;
 240 
 241         required = sizeof(*mdev->chroots) * mdev->dma_channels;
 242         mdev->chroots = devm_kmalloc(&mdev->pdev->dev, required, GFP_KERNEL);
 243         if (!mdev->chroots)
 244                 return -ENOMEM;
 245 
 246         chanops = kobject_create_and_add("chanops", &mdev->pdev->dev.kobj);
 247         if (!chanops)
 248                 return -ENOMEM;
 249 
 250         /* create each channel directory here */
 251         for (i = 0; i < mdev->dma_channels; i++) {
 252                 char name[20];
 253 
 254                 snprintf(name, sizeof(name), "chan%d", i);
 255                 mdev->chroots[i] = kobject_create_and_add(name, chanops);
 256                 if (!mdev->chroots[i])
 257                         return -ENOMEM;
 258         }
 259 
 260         /* populate common parameters */
 261         for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
 262                 rc = create_sysfs_entry(mdev, hidma_mgmt_files[i].name,
 263                                         hidma_mgmt_files[i].mode);
 264                 if (rc)
 265                         return rc;
 266         }
 267 
 268         /* populate parameters that are per channel */
 269         for (i = 0; i < mdev->dma_channels; i++) {
 270                 rc = create_sysfs_entry_channel(mdev, "priority",
 271                                                 (S_IRUGO | S_IWUGO), i,
 272                                                 mdev->chroots[i]);
 273                 if (rc)
 274                         return rc;
 275 
 276                 rc = create_sysfs_entry_channel(mdev, "weight",
 277                                                 (S_IRUGO | S_IWUGO), i,
 278                                                 mdev->chroots[i]);
 279                 if (rc)
 280                         return rc;
 281         }
 282 
 283         return 0;
 284 }
 285 EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys);

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