hidma_mgmt_sys.c 7.2 KB

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