ksysfs.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Architecture specific sysfs attributes in /sys/kernel
  3. *
  4. * Copyright (C) 2007, Intel Corp.
  5. * Huang Ying <ying.huang@intel.com>
  6. * Copyright (C) 2013, 2013 Red Hat, Inc.
  7. * Dave Young <dyoung@redhat.com>
  8. *
  9. * This file is released under the GPLv2
  10. */
  11. #include <linux/kobject.h>
  12. #include <linux/string.h>
  13. #include <linux/sysfs.h>
  14. #include <linux/init.h>
  15. #include <linux/stat.h>
  16. #include <linux/slab.h>
  17. #include <linux/mm.h>
  18. #include <asm/io.h>
  19. #include <asm/setup.h>
  20. static ssize_t version_show(struct kobject *kobj,
  21. struct kobj_attribute *attr, char *buf)
  22. {
  23. return sprintf(buf, "0x%04x\n", boot_params.hdr.version);
  24. }
  25. static struct kobj_attribute boot_params_version_attr = __ATTR_RO(version);
  26. static ssize_t boot_params_data_read(struct file *fp, struct kobject *kobj,
  27. struct bin_attribute *bin_attr,
  28. char *buf, loff_t off, size_t count)
  29. {
  30. memcpy(buf, (void *)&boot_params + off, count);
  31. return count;
  32. }
  33. static struct bin_attribute boot_params_data_attr = {
  34. .attr = {
  35. .name = "data",
  36. .mode = S_IRUGO,
  37. },
  38. .read = boot_params_data_read,
  39. .size = sizeof(boot_params),
  40. };
  41. static struct attribute *boot_params_version_attrs[] = {
  42. &boot_params_version_attr.attr,
  43. NULL,
  44. };
  45. static struct bin_attribute *boot_params_data_attrs[] = {
  46. &boot_params_data_attr,
  47. NULL,
  48. };
  49. static struct attribute_group boot_params_attr_group = {
  50. .attrs = boot_params_version_attrs,
  51. .bin_attrs = boot_params_data_attrs,
  52. };
  53. static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr)
  54. {
  55. const char *name;
  56. name = kobject_name(kobj);
  57. return kstrtoint(name, 10, nr);
  58. }
  59. static int get_setup_data_paddr(int nr, u64 *paddr)
  60. {
  61. int i = 0;
  62. struct setup_data *data;
  63. u64 pa_data = boot_params.hdr.setup_data;
  64. while (pa_data) {
  65. if (nr == i) {
  66. *paddr = pa_data;
  67. return 0;
  68. }
  69. data = ioremap_cache(pa_data, sizeof(*data));
  70. if (!data)
  71. return -ENOMEM;
  72. pa_data = data->next;
  73. iounmap(data);
  74. i++;
  75. }
  76. return -EINVAL;
  77. }
  78. static int __init get_setup_data_size(int nr, size_t *size)
  79. {
  80. int i = 0;
  81. struct setup_data *data;
  82. u64 pa_data = boot_params.hdr.setup_data;
  83. while (pa_data) {
  84. data = ioremap_cache(pa_data, sizeof(*data));
  85. if (!data)
  86. return -ENOMEM;
  87. if (nr == i) {
  88. *size = data->len;
  89. iounmap(data);
  90. return 0;
  91. }
  92. pa_data = data->next;
  93. iounmap(data);
  94. i++;
  95. }
  96. return -EINVAL;
  97. }
  98. static ssize_t type_show(struct kobject *kobj,
  99. struct kobj_attribute *attr, char *buf)
  100. {
  101. int nr, ret;
  102. u64 paddr;
  103. struct setup_data *data;
  104. ret = kobj_to_setup_data_nr(kobj, &nr);
  105. if (ret)
  106. return ret;
  107. ret = get_setup_data_paddr(nr, &paddr);
  108. if (ret)
  109. return ret;
  110. data = ioremap_cache(paddr, sizeof(*data));
  111. if (!data)
  112. return -ENOMEM;
  113. ret = sprintf(buf, "0x%x\n", data->type);
  114. iounmap(data);
  115. return ret;
  116. }
  117. static ssize_t setup_data_data_read(struct file *fp,
  118. struct kobject *kobj,
  119. struct bin_attribute *bin_attr,
  120. char *buf,
  121. loff_t off, size_t count)
  122. {
  123. int nr, ret = 0;
  124. u64 paddr;
  125. struct setup_data *data;
  126. void *p;
  127. ret = kobj_to_setup_data_nr(kobj, &nr);
  128. if (ret)
  129. return ret;
  130. ret = get_setup_data_paddr(nr, &paddr);
  131. if (ret)
  132. return ret;
  133. data = ioremap_cache(paddr, sizeof(*data));
  134. if (!data)
  135. return -ENOMEM;
  136. if (off > data->len) {
  137. ret = -EINVAL;
  138. goto out;
  139. }
  140. if (count > data->len - off)
  141. count = data->len - off;
  142. if (!count)
  143. goto out;
  144. ret = count;
  145. p = ioremap_cache(paddr + sizeof(*data), data->len);
  146. if (!p) {
  147. ret = -ENOMEM;
  148. goto out;
  149. }
  150. memcpy(buf, p + off, count);
  151. iounmap(p);
  152. out:
  153. iounmap(data);
  154. return ret;
  155. }
  156. static struct kobj_attribute type_attr = __ATTR_RO(type);
  157. static struct bin_attribute data_attr __ro_after_init = {
  158. .attr = {
  159. .name = "data",
  160. .mode = S_IRUGO,
  161. },
  162. .read = setup_data_data_read,
  163. };
  164. static struct attribute *setup_data_type_attrs[] = {
  165. &type_attr.attr,
  166. NULL,
  167. };
  168. static struct bin_attribute *setup_data_data_attrs[] = {
  169. &data_attr,
  170. NULL,
  171. };
  172. static struct attribute_group setup_data_attr_group = {
  173. .attrs = setup_data_type_attrs,
  174. .bin_attrs = setup_data_data_attrs,
  175. };
  176. static int __init create_setup_data_node(struct kobject *parent,
  177. struct kobject **kobjp, int nr)
  178. {
  179. int ret = 0;
  180. size_t size;
  181. struct kobject *kobj;
  182. char name[16]; /* should be enough for setup_data nodes numbers */
  183. snprintf(name, 16, "%d", nr);
  184. kobj = kobject_create_and_add(name, parent);
  185. if (!kobj)
  186. return -ENOMEM;
  187. ret = get_setup_data_size(nr, &size);
  188. if (ret)
  189. goto out_kobj;
  190. data_attr.size = size;
  191. ret = sysfs_create_group(kobj, &setup_data_attr_group);
  192. if (ret)
  193. goto out_kobj;
  194. *kobjp = kobj;
  195. return 0;
  196. out_kobj:
  197. kobject_put(kobj);
  198. return ret;
  199. }
  200. static void __init cleanup_setup_data_node(struct kobject *kobj)
  201. {
  202. sysfs_remove_group(kobj, &setup_data_attr_group);
  203. kobject_put(kobj);
  204. }
  205. static int __init get_setup_data_total_num(u64 pa_data, int *nr)
  206. {
  207. int ret = 0;
  208. struct setup_data *data;
  209. *nr = 0;
  210. while (pa_data) {
  211. *nr += 1;
  212. data = ioremap_cache(pa_data, sizeof(*data));
  213. if (!data) {
  214. ret = -ENOMEM;
  215. goto out;
  216. }
  217. pa_data = data->next;
  218. iounmap(data);
  219. }
  220. out:
  221. return ret;
  222. }
  223. static int __init create_setup_data_nodes(struct kobject *parent)
  224. {
  225. struct kobject *setup_data_kobj, **kobjp;
  226. u64 pa_data;
  227. int i, j, nr, ret = 0;
  228. pa_data = boot_params.hdr.setup_data;
  229. if (!pa_data)
  230. return 0;
  231. setup_data_kobj = kobject_create_and_add("setup_data", parent);
  232. if (!setup_data_kobj) {
  233. ret = -ENOMEM;
  234. goto out;
  235. }
  236. ret = get_setup_data_total_num(pa_data, &nr);
  237. if (ret)
  238. goto out_setup_data_kobj;
  239. kobjp = kmalloc(sizeof(*kobjp) * nr, GFP_KERNEL);
  240. if (!kobjp) {
  241. ret = -ENOMEM;
  242. goto out_setup_data_kobj;
  243. }
  244. for (i = 0; i < nr; i++) {
  245. ret = create_setup_data_node(setup_data_kobj, kobjp + i, i);
  246. if (ret)
  247. goto out_clean_nodes;
  248. }
  249. kfree(kobjp);
  250. return 0;
  251. out_clean_nodes:
  252. for (j = i - 1; j > 0; j--)
  253. cleanup_setup_data_node(*(kobjp + j));
  254. kfree(kobjp);
  255. out_setup_data_kobj:
  256. kobject_put(setup_data_kobj);
  257. out:
  258. return ret;
  259. }
  260. static int __init boot_params_ksysfs_init(void)
  261. {
  262. int ret;
  263. struct kobject *boot_params_kobj;
  264. boot_params_kobj = kobject_create_and_add("boot_params",
  265. kernel_kobj);
  266. if (!boot_params_kobj) {
  267. ret = -ENOMEM;
  268. goto out;
  269. }
  270. ret = sysfs_create_group(boot_params_kobj, &boot_params_attr_group);
  271. if (ret)
  272. goto out_boot_params_kobj;
  273. ret = create_setup_data_nodes(boot_params_kobj);
  274. if (ret)
  275. goto out_create_group;
  276. return 0;
  277. out_create_group:
  278. sysfs_remove_group(boot_params_kobj, &boot_params_attr_group);
  279. out_boot_params_kobj:
  280. kobject_put(boot_params_kobj);
  281. out:
  282. return ret;
  283. }
  284. arch_initcall(boot_params_ksysfs_init);