hidma_mgmt_sys.c 6.6 KB

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