mm: fix exec activate_mm vs TLB shootdown and lazy tlb switching race
[linux/fpc-iii.git] / arch / tile / kernel / sysfs.c
blob825867c5385304e3816a7b88f042330522c89443
1 /*
2 * Copyright 2011 Tilera Corporation. All Rights Reserved.
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.
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.
14 * /sys entry support.
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>
24 /* Return a string queried from the hypervisor, truncated to page size. */
25 static ssize_t get_hv_confstr(char *page, int query)
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;
35 static ssize_t chip_width_show(struct device *dev,
36 struct device_attribute *attr,
37 char *page)
39 return sprintf(page, "%u\n", smp_width);
41 static DEVICE_ATTR(chip_width, 0444, chip_width_show, NULL);
43 static ssize_t chip_height_show(struct device *dev,
44 struct device_attribute *attr,
45 char *page)
47 return sprintf(page, "%u\n", smp_height);
49 static DEVICE_ATTR(chip_height, 0444, chip_height_show, NULL);
51 static ssize_t chip_serial_show(struct device *dev,
52 struct device_attribute *attr,
53 char *page)
55 return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM);
57 static DEVICE_ATTR(chip_serial, 0444, chip_serial_show, NULL);
59 static ssize_t chip_revision_show(struct device *dev,
60 struct device_attribute *attr,
61 char *page)
63 return get_hv_confstr(page, HV_CONFSTR_CHIP_REV);
65 static DEVICE_ATTR(chip_revision, 0444, chip_revision_show, NULL);
68 static ssize_t type_show(struct device *dev,
69 struct device_attribute *attr,
70 char *page)
72 return sprintf(page, "tilera\n");
74 static DEVICE_ATTR(type, 0444, type_show, NULL);
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);
85 HV_CONF_ATTR(version, HV_CONFSTR_HV_SW_VER)
86 HV_CONF_ATTR(config_version, HV_CONFSTR_HV_CONFIG_VER)
88 HV_CONF_ATTR(board_part, HV_CONFSTR_BOARD_PART_NUM)
89 HV_CONF_ATTR(board_serial, HV_CONFSTR_BOARD_SERIAL_NUM)
90 HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV)
91 HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC)
92 HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM)
93 HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM)
94 HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV)
95 HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
96 HV_CONF_ATTR(cpumod_part, HV_CONFSTR_CPUMOD_PART_NUM)
97 HV_CONF_ATTR(cpumod_serial, HV_CONFSTR_CPUMOD_SERIAL_NUM)
98 HV_CONF_ATTR(cpumod_revision, HV_CONFSTR_CPUMOD_REV)
99 HV_CONF_ATTR(cpumod_description,HV_CONFSTR_CPUMOD_DESC)
100 HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL)
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
119 static struct attribute_group board_attr_group = {
120 .name = "board",
121 .attrs = board_attrs,
125 static struct bin_attribute hvconfig_bin;
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)
132 static size_t size;
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;
138 /* Check and adjust input parameters. */
139 if (off > size)
140 return -EINVAL;
141 if (count > size - off)
142 count = size - off;
144 if (count) {
145 /* Get a copy of the hvc and copy out the relevant portion. */
146 char *hvc;
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);
157 return count;
160 static ssize_t hv_stats_show(struct device *dev,
161 struct device_attribute *attr,
162 char *page)
164 int cpu = dev->id;
165 long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu));
167 ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS,
168 (unsigned long)page, PAGE_SIZE - 1,
169 lotar, 0);
170 n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1);
171 page[n] = '\0';
172 return n;
175 static ssize_t hv_stats_store(struct device *dev,
176 struct device_attribute *attr,
177 const char *page,
178 size_t count)
180 int cpu = dev->id;
181 long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu));
183 ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, 0, 0, lotar, 1);
184 return n < 0 ? n : count;
187 static DEVICE_ATTR(hv_stats, 0644, hv_stats_show, hv_stats_store);
189 static int hv_stats_device_add(struct device *dev, struct subsys_interface *sif)
191 int err, cpu = dev->id;
193 if (!cpu_online(cpu))
194 return 0;
196 err = sysfs_create_file(&dev->kobj, &dev_attr_hv_stats.attr);
198 return err;
201 static void hv_stats_device_remove(struct device *dev,
202 struct subsys_interface *sif)
204 int cpu = dev->id;
206 if (cpu_online(cpu))
207 sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr);
211 static struct subsys_interface hv_stats_interface = {
212 .name = "hv_stats",
213 .subsys = &cpu_subsys,
214 .add_dev = hv_stats_device_add,
215 .remove_dev = hv_stats_device_remove,
218 static int __init create_sysfs_entries(void)
220 int err = 0;
222 #define create_cpu_attr(name) \
223 if (!err) \
224 err = device_create_file(cpu_subsys.dev_root, &dev_attr_##name);
225 create_cpu_attr(chip_width);
226 create_cpu_attr(chip_height);
227 create_cpu_attr(chip_serial);
228 create_cpu_attr(chip_revision);
230 #define create_hv_attr(name) \
231 if (!err) \
232 err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name.attr);
233 create_hv_attr(type);
234 create_hv_attr(version);
235 create_hv_attr(config_version);
237 if (!err)
238 err = sysfs_create_group(hypervisor_kobj, &board_attr_group);
240 if (!err) {
241 sysfs_bin_attr_init(&hvconfig_bin);
242 hvconfig_bin.attr.name = "hvconfig";
243 hvconfig_bin.attr.mode = S_IRUGO;
244 hvconfig_bin.read = hvconfig_bin_read;
245 hvconfig_bin.size = PAGE_SIZE;
246 err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin);
249 if (!err) {
251 * Don't bother adding the hv_stats files on each CPU if
252 * our hypervisor doesn't supply statistics.
254 int cpu = raw_smp_processor_id();
255 long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu));
256 char dummy;
257 ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS,
258 (unsigned long) &dummy, 1,
259 lotar, 0);
260 if (n >= 0)
261 err = subsys_interface_register(&hv_stats_interface);
264 return err;
266 subsys_initcall(create_sysfs_entries);