Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sysfs.c
Go to the documentation of this file.
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 
17 #include <linux/device.h>
18 #include <linux/cpu.h>
19 #include <linux/slab.h>
20 #include <linux/smp.h>
21 #include <linux/stat.h>
22 #include <hv/hypervisor.h>
23 
24 /* Return a string queried from the hypervisor, truncated to page size. */
25 static ssize_t get_hv_confstr(char *page, int query)
26 {
27  ssize_t n = hv_confstr(query, (unsigned long)page, PAGE_SIZE - 1);
28  n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1) - 1;
29  if (n)
30  page[n++] = '\n';
31  page[n] = '\0';
32  return n;
33 }
34 
35 static ssize_t chip_width_show(struct device *dev,
36  struct device_attribute *attr,
37  char *page)
38 {
39  return sprintf(page, "%u\n", smp_width);
40 }
41 static DEVICE_ATTR(chip_width, 0444, chip_width_show, NULL);
42 
43 static ssize_t chip_height_show(struct device *dev,
44  struct device_attribute *attr,
45  char *page)
46 {
47  return sprintf(page, "%u\n", smp_height);
48 }
49 static DEVICE_ATTR(chip_height, 0444, chip_height_show, NULL);
50 
51 static ssize_t chip_serial_show(struct device *dev,
52  struct device_attribute *attr,
53  char *page)
54 {
55  return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM);
56 }
57 static DEVICE_ATTR(chip_serial, 0444, chip_serial_show, NULL);
58 
59 static ssize_t chip_revision_show(struct device *dev,
60  struct device_attribute *attr,
61  char *page)
62 {
63  return get_hv_confstr(page, HV_CONFSTR_CHIP_REV);
64 }
65 static DEVICE_ATTR(chip_revision, 0444, chip_revision_show, NULL);
66 
67 
68 static ssize_t type_show(struct device *dev,
69  struct device_attribute *attr,
70  char *page)
71 {
72  return sprintf(page, "tilera\n");
73 }
74 static DEVICE_ATTR(type, 0444, type_show, NULL);
75 
76 #define HV_CONF_ATTR(name, conf) \
77  static ssize_t name ## _show(struct device *dev, \
78  struct device_attribute *attr, \
79  char *page) \
80  { \
81  return get_hv_confstr(page, conf); \
82  } \
83  static DEVICE_ATTR(name, 0444, name ## _show, NULL);
84 
87 
90 HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV)
91 HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC)
94 HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV)
95 HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
98 HV_CONF_ATTR(cpumod_revision, HV_CONFSTR_CPUMOD_REV)
99 HV_CONF_ATTR(cpumod_description,HV_CONFSTR_CPUMOD_DESC)
101 
102 static struct attribute *board_attrs[] = {
103  &dev_attr_board_part.attr,
104  &dev_attr_board_serial.attr,
105  &dev_attr_board_revision.attr,
106  &dev_attr_board_description.attr,
107  &dev_attr_mezz_part.attr,
108  &dev_attr_mezz_serial.attr,
109  &dev_attr_mezz_revision.attr,
110  &dev_attr_mezz_description.attr,
111  &dev_attr_cpumod_part.attr,
112  &dev_attr_cpumod_serial.attr,
113  &dev_attr_cpumod_revision.attr,
114  &dev_attr_cpumod_description.attr,
115  &dev_attr_switch_control.attr,
116  NULL
117 };
118 
119 static struct attribute_group board_attr_group = {
120  .name = "board",
121  .attrs = board_attrs,
122 };
123 
124 
125 static struct bin_attribute hvconfig_bin;
126 
127 static ssize_t
128 hvconfig_bin_read(struct file *filp, struct kobject *kobj,
129  struct bin_attribute *bin_attr,
130  char *buf, loff_t off, size_t count)
131 {
132  static size_t size;
133 
134  /* Lazily learn the true size (minus the trailing NUL). */
135  if (size == 0)
136  size = hv_confstr(HV_CONFSTR_HV_CONFIG, 0, 0) - 1;
137 
138  /* Check and adjust input parameters. */
139  if (off > size)
140  return -EINVAL;
141  if (count > size - off)
142  count = size - off;
143 
144  if (count) {
145  /* Get a copy of the hvc and copy out the relevant portion. */
146  char *hvc;
147 
148  size = off + count;
149  hvc = kmalloc(size, GFP_KERNEL);
150  if (hvc == NULL)
151  return -ENOMEM;
152  hv_confstr(HV_CONFSTR_HV_CONFIG, (unsigned long)hvc, size);
153  memcpy(buf, hvc + off, count);
154  kfree(hvc);
155  }
156 
157  return count;
158 }
159 
160 static int __init create_sysfs_entries(void)
161 {
162  int err = 0;
163 
164 #define create_cpu_attr(name) \
165  if (!err) \
166  err = device_create_file(cpu_subsys.dev_root, &dev_attr_##name);
167  create_cpu_attr(chip_width);
168  create_cpu_attr(chip_height);
169  create_cpu_attr(chip_serial);
170  create_cpu_attr(chip_revision);
171 
172 #define create_hv_attr(name) \
173  if (!err) \
174  err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name.attr);
177  create_hv_attr(config_version);
178 
179  if (!err)
180  err = sysfs_create_group(hypervisor_kobj, &board_attr_group);
181 
182  if (!err) {
183  sysfs_bin_attr_init(&hvconfig_bin);
184  hvconfig_bin.attr.name = "hvconfig";
185  hvconfig_bin.attr.mode = S_IRUGO;
186  hvconfig_bin.read = hvconfig_bin_read;
187  hvconfig_bin.size = PAGE_SIZE;
188  err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin);
189  }
190 
191  return err;
192 }
193 subsys_initcall(create_sysfs_entries);