hidma_mgmt_sys.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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 hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
  96. unsigned int i;
  97. buf[0] = 0;
  98. for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
  99. if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
  100. sprintf(buf, "%d\n", hidma_mgmt_files[i].get(mdev));
  101. break;
  102. }
  103. }
  104. return strlen(buf);
  105. }
  106. static ssize_t set_values(struct device *dev, struct device_attribute *attr,
  107. const char *buf, size_t count)
  108. {
  109. struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
  110. unsigned long tmp;
  111. unsigned int i;
  112. int rc;
  113. rc = kstrtoul(buf, 0, &tmp);
  114. if (rc)
  115. return rc;
  116. for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
  117. if (strcmp(attr->attr.name, hidma_mgmt_files[i].name) == 0) {
  118. rc = hidma_mgmt_files[i].set(mdev, tmp);
  119. if (rc)
  120. return rc;
  121. break;
  122. }
  123. }
  124. return count;
  125. }
  126. static ssize_t show_values_channel(struct kobject *kobj,
  127. struct kobj_attribute *attr, char *buf)
  128. {
  129. struct hidma_chan_attr *chattr;
  130. struct hidma_mgmt_dev *mdev;
  131. buf[0] = 0;
  132. chattr = container_of(attr, struct hidma_chan_attr, attr);
  133. mdev = chattr->mdev;
  134. if (strcmp(attr->attr.name, "priority") == 0)
  135. sprintf(buf, "%d\n", mdev->priority[chattr->index]);
  136. else if (strcmp(attr->attr.name, "weight") == 0)
  137. sprintf(buf, "%d\n", mdev->weight[chattr->index]);
  138. return strlen(buf);
  139. }
  140. static ssize_t set_values_channel(struct kobject *kobj,
  141. struct kobj_attribute *attr, const char *buf,
  142. size_t count)
  143. {
  144. struct hidma_chan_attr *chattr;
  145. struct hidma_mgmt_dev *mdev;
  146. unsigned long tmp;
  147. int rc;
  148. chattr = container_of(attr, struct hidma_chan_attr, attr);
  149. mdev = chattr->mdev;
  150. rc = kstrtoul(buf, 0, &tmp);
  151. if (rc)
  152. return rc;
  153. if (strcmp(attr->attr.name, "priority") == 0) {
  154. rc = set_priority(mdev, chattr->index, tmp);
  155. if (rc)
  156. return rc;
  157. } else if (strcmp(attr->attr.name, "weight") == 0) {
  158. rc = set_weight(mdev, chattr->index, tmp);
  159. if (rc)
  160. return rc;
  161. }
  162. return count;
  163. }
  164. static int create_sysfs_entry(struct hidma_mgmt_dev *dev, char *name, int mode)
  165. {
  166. struct device_attribute *attrs;
  167. char *name_copy;
  168. attrs = devm_kmalloc(&dev->pdev->dev,
  169. sizeof(struct device_attribute), GFP_KERNEL);
  170. if (!attrs)
  171. return -ENOMEM;
  172. name_copy = devm_kstrdup(&dev->pdev->dev, name, GFP_KERNEL);
  173. if (!name_copy)
  174. return -ENOMEM;
  175. attrs->attr.name = name_copy;
  176. attrs->attr.mode = mode;
  177. attrs->show = show_values;
  178. attrs->store = set_values;
  179. sysfs_attr_init(&attrs->attr);
  180. return device_create_file(&dev->pdev->dev, attrs);
  181. }
  182. static int create_sysfs_entry_channel(struct hidma_mgmt_dev *mdev, char *name,
  183. int mode, int index,
  184. struct kobject *parent)
  185. {
  186. struct hidma_chan_attr *chattr;
  187. char *name_copy;
  188. chattr = devm_kmalloc(&mdev->pdev->dev, sizeof(*chattr), GFP_KERNEL);
  189. if (!chattr)
  190. return -ENOMEM;
  191. name_copy = devm_kstrdup(&mdev->pdev->dev, name, GFP_KERNEL);
  192. if (!name_copy)
  193. return -ENOMEM;
  194. chattr->mdev = mdev;
  195. chattr->index = index;
  196. chattr->attr.attr.name = name_copy;
  197. chattr->attr.attr.mode = mode;
  198. chattr->attr.show = show_values_channel;
  199. chattr->attr.store = set_values_channel;
  200. sysfs_attr_init(&chattr->attr.attr);
  201. return sysfs_create_file(parent, &chattr->attr.attr);
  202. }
  203. int hidma_mgmt_init_sys(struct hidma_mgmt_dev *mdev)
  204. {
  205. unsigned int i;
  206. int rc;
  207. int required;
  208. struct kobject *chanops;
  209. required = sizeof(*mdev->chroots) * mdev->dma_channels;
  210. mdev->chroots = devm_kmalloc(&mdev->pdev->dev, required, GFP_KERNEL);
  211. if (!mdev->chroots)
  212. return -ENOMEM;
  213. chanops = kobject_create_and_add("chanops", &mdev->pdev->dev.kobj);
  214. if (!chanops)
  215. return -ENOMEM;
  216. /* create each channel directory here */
  217. for (i = 0; i < mdev->dma_channels; i++) {
  218. char name[20];
  219. snprintf(name, sizeof(name), "chan%d", i);
  220. mdev->chroots[i] = kobject_create_and_add(name, chanops);
  221. if (!mdev->chroots[i])
  222. return -ENOMEM;
  223. }
  224. /* populate common parameters */
  225. for (i = 0; i < ARRAY_SIZE(hidma_mgmt_files); i++) {
  226. rc = create_sysfs_entry(mdev, hidma_mgmt_files[i].name,
  227. hidma_mgmt_files[i].mode);
  228. if (rc)
  229. return rc;
  230. }
  231. /* populate parameters that are per channel */
  232. for (i = 0; i < mdev->dma_channels; i++) {
  233. rc = create_sysfs_entry_channel(mdev, "priority",
  234. (S_IRUGO | S_IWUGO), i,
  235. mdev->chroots[i]);
  236. if (rc)
  237. return rc;
  238. rc = create_sysfs_entry_channel(mdev, "weight",
  239. (S_IRUGO | S_IWUGO), i,
  240. mdev->chroots[i]);
  241. if (rc)
  242. return rc;
  243. }
  244. return 0;
  245. }
  246. EXPORT_SYMBOL_GPL(hidma_mgmt_init_sys);