sysfs.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * Copyright 2011 Tilera Corporation. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation, version 2.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11. * NON INFRINGEMENT. See the GNU General Public License for
  12. * more details.
  13. *
  14. * /sys entry support.
  15. */
  16. #include <linux/device.h>
  17. #include <linux/cpu.h>
  18. #include <linux/slab.h>
  19. #include <linux/smp.h>
  20. #include <linux/stat.h>
  21. #include <hv/hypervisor.h>
  22. /* Return a string queried from the hypervisor, truncated to page size. */
  23. static ssize_t get_hv_confstr(char *page, int query)
  24. {
  25. ssize_t n = hv_confstr(query, (unsigned long)page, PAGE_SIZE - 1);
  26. n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1) - 1;
  27. if (n)
  28. page[n++] = '\n';
  29. page[n] = '\0';
  30. return n;
  31. }
  32. static ssize_t chip_width_show(struct device *dev,
  33. struct device_attribute *attr,
  34. char *page)
  35. {
  36. return sprintf(page, "%u\n", smp_width);
  37. }
  38. static DEVICE_ATTR(chip_width, 0444, chip_width_show, NULL);
  39. static ssize_t chip_height_show(struct device *dev,
  40. struct device_attribute *attr,
  41. char *page)
  42. {
  43. return sprintf(page, "%u\n", smp_height);
  44. }
  45. static DEVICE_ATTR(chip_height, 0444, chip_height_show, NULL);
  46. static ssize_t chip_serial_show(struct device *dev,
  47. struct device_attribute *attr,
  48. char *page)
  49. {
  50. return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM);
  51. }
  52. static DEVICE_ATTR(chip_serial, 0444, chip_serial_show, NULL);
  53. static ssize_t chip_revision_show(struct device *dev,
  54. struct device_attribute *attr,
  55. char *page)
  56. {
  57. return get_hv_confstr(page, HV_CONFSTR_CHIP_REV);
  58. }
  59. static DEVICE_ATTR(chip_revision, 0444, chip_revision_show, NULL);
  60. static ssize_t type_show(struct device *dev,
  61. struct device_attribute *attr,
  62. char *page)
  63. {
  64. return sprintf(page, "tilera\n");
  65. }
  66. static DEVICE_ATTR(type, 0444, type_show, NULL);
  67. #define HV_CONF_ATTR(name, conf) \
  68. static ssize_t name ## _show(struct device *dev, \
  69. struct device_attribute *attr, \
  70. char *page) \
  71. { \
  72. return get_hv_confstr(page, conf); \
  73. } \
  74. static DEVICE_ATTR(name, 0444, name ## _show, NULL);
  75. HV_CONF_ATTR(version, HV_CONFSTR_HV_SW_VER)
  76. HV_CONF_ATTR(config_version, HV_CONFSTR_HV_CONFIG_VER)
  77. HV_CONF_ATTR(board_part, HV_CONFSTR_BOARD_PART_NUM)
  78. HV_CONF_ATTR(board_serial, HV_CONFSTR_BOARD_SERIAL_NUM)
  79. HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV)
  80. HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC)
  81. HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM)
  82. HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM)
  83. HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV)
  84. HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
  85. HV_CONF_ATTR(cpumod_part, HV_CONFSTR_CPUMOD_PART_NUM)
  86. HV_CONF_ATTR(cpumod_serial, HV_CONFSTR_CPUMOD_SERIAL_NUM)
  87. HV_CONF_ATTR(cpumod_revision, HV_CONFSTR_CPUMOD_REV)
  88. HV_CONF_ATTR(cpumod_description,HV_CONFSTR_CPUMOD_DESC)
  89. HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL)
  90. static struct attribute *board_attrs[] = {
  91. &dev_attr_board_part.attr,
  92. &dev_attr_board_serial.attr,
  93. &dev_attr_board_revision.attr,
  94. &dev_attr_board_description.attr,
  95. &dev_attr_mezz_part.attr,
  96. &dev_attr_mezz_serial.attr,
  97. &dev_attr_mezz_revision.attr,
  98. &dev_attr_mezz_description.attr,
  99. &dev_attr_cpumod_part.attr,
  100. &dev_attr_cpumod_serial.attr,
  101. &dev_attr_cpumod_revision.attr,
  102. &dev_attr_cpumod_description.attr,
  103. &dev_attr_switch_control.attr,
  104. NULL
  105. };
  106. static struct attribute_group board_attr_group = {
  107. .name = "board",
  108. .attrs = board_attrs,
  109. };
  110. static struct bin_attribute hvconfig_bin;
  111. static ssize_t
  112. hvconfig_bin_read(struct file *filp, struct kobject *kobj,
  113. struct bin_attribute *bin_attr,
  114. char *buf, loff_t off, size_t count)
  115. {
  116. static size_t size;
  117. /* Lazily learn the true size (minus the trailing NUL). */
  118. if (size == 0)
  119. size = hv_confstr(HV_CONFSTR_HV_CONFIG, 0, 0) - 1;
  120. /* Check and adjust input parameters. */
  121. if (off > size)
  122. return -EINVAL;
  123. if (count > size - off)
  124. count = size - off;
  125. if (count) {
  126. /* Get a copy of the hvc and copy out the relevant portion. */
  127. char *hvc;
  128. size = off + count;
  129. hvc = kmalloc(size, GFP_KERNEL);
  130. if (hvc == NULL)
  131. return -ENOMEM;
  132. hv_confstr(HV_CONFSTR_HV_CONFIG, (unsigned long)hvc, size);
  133. memcpy(buf, hvc + off, count);
  134. kfree(hvc);
  135. }
  136. return count;
  137. }
  138. static ssize_t hv_stats_show(struct device *dev,
  139. struct device_attribute *attr,
  140. char *page)
  141. {
  142. int cpu = dev->id;
  143. long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu));
  144. ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS,
  145. (unsigned long)page, PAGE_SIZE - 1,
  146. lotar, 0);
  147. n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1);
  148. page[n] = '\0';
  149. return n;
  150. }
  151. static ssize_t hv_stats_store(struct device *dev,
  152. struct device_attribute *attr,
  153. const char *page,
  154. size_t count)
  155. {
  156. int cpu = dev->id;
  157. long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu));
  158. ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, 0, 0, lotar, 1);
  159. return n < 0 ? n : count;
  160. }
  161. static DEVICE_ATTR(hv_stats, 0644, hv_stats_show, hv_stats_store);
  162. static int hv_stats_device_add(struct device *dev, struct subsys_interface *sif)
  163. {
  164. int err, cpu = dev->id;
  165. if (!cpu_online(cpu))
  166. return 0;
  167. err = sysfs_create_file(&dev->kobj, &dev_attr_hv_stats.attr);
  168. return err;
  169. }
  170. static void hv_stats_device_remove(struct device *dev,
  171. struct subsys_interface *sif)
  172. {
  173. int cpu = dev->id;
  174. if (cpu_online(cpu))
  175. sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr);
  176. }
  177. static struct subsys_interface hv_stats_interface = {
  178. .name = "hv_stats",
  179. .subsys = &cpu_subsys,
  180. .add_dev = hv_stats_device_add,
  181. .remove_dev = hv_stats_device_remove,
  182. };
  183. static int __init create_sysfs_entries(void)
  184. {
  185. int err = 0;
  186. #define create_cpu_attr(name) \
  187. if (!err) \
  188. err = device_create_file(cpu_subsys.dev_root, &dev_attr_##name);
  189. create_cpu_attr(chip_width);
  190. create_cpu_attr(chip_height);
  191. create_cpu_attr(chip_serial);
  192. create_cpu_attr(chip_revision);
  193. #define create_hv_attr(name) \
  194. if (!err) \
  195. err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name.attr);
  196. create_hv_attr(type);
  197. create_hv_attr(version);
  198. create_hv_attr(config_version);
  199. if (!err)
  200. err = sysfs_create_group(hypervisor_kobj, &board_attr_group);
  201. if (!err) {
  202. sysfs_bin_attr_init(&hvconfig_bin);
  203. hvconfig_bin.attr.name = "hvconfig";
  204. hvconfig_bin.attr.mode = S_IRUGO;
  205. hvconfig_bin.read = hvconfig_bin_read;
  206. hvconfig_bin.size = PAGE_SIZE;
  207. err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin);
  208. }
  209. if (!err) {
  210. /*
  211. * Don't bother adding the hv_stats files on each CPU if
  212. * our hypervisor doesn't supply statistics.
  213. */
  214. int cpu = raw_smp_processor_id();
  215. long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu));
  216. char dummy;
  217. ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS,
  218. (unsigned long) &dummy, 1,
  219. lotar, 0);
  220. if (n >= 0)
  221. err = subsys_interface_register(&hv_stats_interface);
  222. }
  223. return err;
  224. }
  225. subsys_initcall(create_sysfs_entries);