sysfs.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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/sysdev.h>
  17. #include <linux/cpu.h>
  18. #include <linux/slab.h>
  19. #include <linux/smp.h>
  20. #include <hv/hypervisor.h>
  21. /* Return a string queried from the hypervisor, truncated to page size. */
  22. static ssize_t get_hv_confstr(char *page, int query)
  23. {
  24. ssize_t n = hv_confstr(query, (unsigned long)page, PAGE_SIZE - 1);
  25. n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1) - 1;
  26. if (n)
  27. page[n++] = '\n';
  28. page[n] = '\0';
  29. return n;
  30. }
  31. static ssize_t chip_width_show(struct sysdev_class *dev,
  32. struct sysdev_class_attribute *attr,
  33. char *page)
  34. {
  35. return sprintf(page, "%u\n", smp_width);
  36. }
  37. static SYSDEV_CLASS_ATTR(chip_width, 0444, chip_width_show, NULL);
  38. static ssize_t chip_height_show(struct sysdev_class *dev,
  39. struct sysdev_class_attribute *attr,
  40. char *page)
  41. {
  42. return sprintf(page, "%u\n", smp_height);
  43. }
  44. static SYSDEV_CLASS_ATTR(chip_height, 0444, chip_height_show, NULL);
  45. static ssize_t chip_serial_show(struct sysdev_class *dev,
  46. struct sysdev_class_attribute *attr,
  47. char *page)
  48. {
  49. return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM);
  50. }
  51. static SYSDEV_CLASS_ATTR(chip_serial, 0444, chip_serial_show, NULL);
  52. static ssize_t chip_revision_show(struct sysdev_class *dev,
  53. struct sysdev_class_attribute *attr,
  54. char *page)
  55. {
  56. return get_hv_confstr(page, HV_CONFSTR_CHIP_REV);
  57. }
  58. static SYSDEV_CLASS_ATTR(chip_revision, 0444, chip_revision_show, NULL);
  59. static ssize_t type_show(struct sysdev_class *dev,
  60. struct sysdev_class_attribute *attr,
  61. char *page)
  62. {
  63. return sprintf(page, "tilera\n");
  64. }
  65. static SYSDEV_CLASS_ATTR(type, 0444, type_show, NULL);
  66. #define HV_CONF_ATTR(name, conf) \
  67. static ssize_t name ## _show(struct sysdev_class *dev, \
  68. struct sysdev_class_attribute *attr, \
  69. char *page) \
  70. { \
  71. return get_hv_confstr(page, conf); \
  72. } \
  73. static SYSDEV_CLASS_ATTR(name, 0444, name ## _show, NULL);
  74. HV_CONF_ATTR(version, HV_CONFSTR_HV_SW_VER)
  75. HV_CONF_ATTR(config_version, HV_CONFSTR_HV_CONFIG_VER)
  76. HV_CONF_ATTR(board_part, HV_CONFSTR_BOARD_PART_NUM)
  77. HV_CONF_ATTR(board_serial, HV_CONFSTR_BOARD_SERIAL_NUM)
  78. HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV)
  79. HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC)
  80. HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM)
  81. HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM)
  82. HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV)
  83. HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
  84. HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL)
  85. static struct attribute *board_attrs[] = {
  86. &attr_board_part.attr,
  87. &attr_board_serial.attr,
  88. &attr_board_revision.attr,
  89. &attr_board_description.attr,
  90. &attr_mezz_part.attr,
  91. &attr_mezz_serial.attr,
  92. &attr_mezz_revision.attr,
  93. &attr_mezz_description.attr,
  94. &attr_switch_control.attr,
  95. NULL
  96. };
  97. static struct attribute_group board_attr_group = {
  98. .name = "board",
  99. .attrs = board_attrs,
  100. };
  101. static struct bin_attribute hvconfig_bin;
  102. static ssize_t
  103. hvconfig_bin_read(struct file *filp, struct kobject *kobj,
  104. struct bin_attribute *bin_attr,
  105. char *buf, loff_t off, size_t count)
  106. {
  107. static size_t size;
  108. /* Lazily learn the true size (minus the trailing NUL). */
  109. if (size == 0)
  110. size = hv_confstr(HV_CONFSTR_HV_CONFIG, 0, 0) - 1;
  111. /* Check and adjust input parameters. */
  112. if (off > size)
  113. return -EINVAL;
  114. if (count > size - off)
  115. count = size - off;
  116. if (count) {
  117. /* Get a copy of the hvc and copy out the relevant portion. */
  118. char *hvc;
  119. size = off + count;
  120. hvc = kmalloc(size, GFP_KERNEL);
  121. if (hvc == NULL)
  122. return -ENOMEM;
  123. hv_confstr(HV_CONFSTR_HV_CONFIG, (unsigned long)hvc, size);
  124. memcpy(buf, hvc + off, count);
  125. kfree(hvc);
  126. }
  127. return count;
  128. }
  129. static int __init create_sysfs_entries(void)
  130. {
  131. struct sysdev_class *cls = &cpu_sysdev_class;
  132. int err = 0;
  133. #define create_cpu_attr(name) \
  134. if (!err) \
  135. err = sysfs_create_file(&cls->kset.kobj, &attr_##name.attr);
  136. create_cpu_attr(chip_width);
  137. create_cpu_attr(chip_height);
  138. create_cpu_attr(chip_serial);
  139. create_cpu_attr(chip_revision);
  140. #define create_hv_attr(name) \
  141. if (!err) \
  142. err = sysfs_create_file(hypervisor_kobj, &attr_##name.attr);
  143. create_hv_attr(type);
  144. create_hv_attr(version);
  145. create_hv_attr(config_version);
  146. if (!err)
  147. err = sysfs_create_group(hypervisor_kobj, &board_attr_group);
  148. if (!err) {
  149. sysfs_bin_attr_init(&hvconfig_bin);
  150. hvconfig_bin.attr.name = "hvconfig";
  151. hvconfig_bin.attr.mode = S_IRUGO;
  152. hvconfig_bin.read = hvconfig_bin_read;
  153. hvconfig_bin.size = PAGE_SIZE;
  154. err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin);
  155. }
  156. return err;
  157. }
  158. subsys_initcall(create_sysfs_entries);