Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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