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
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;
35 static ssize_t
chip_width_show(struct device
*dev
,
36 struct device_attribute
*attr
,
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
,
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
,
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
,
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
,
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, \
81 return get_hv_confstr(page, conf); \
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
,
119 static struct attribute_group board_attr_group
= {
121 .attrs
= board_attrs
,
125 static struct bin_attribute hvconfig_bin
;
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
)
134 /* Lazily learn the true size (minus the trailing NUL). */
136 size
= hv_confstr(HV_CONFSTR_HV_CONFIG
, 0, 0) - 1;
138 /* Check and adjust input parameters. */
141 if (count
> size
- off
)
145 /* Get a copy of the hvc and copy out the relevant portion. */
149 hvc
= kmalloc(size
, GFP_KERNEL
);
152 hv_confstr(HV_CONFSTR_HV_CONFIG
, (unsigned long)hvc
, size
);
153 memcpy(buf
, hvc
+ off
, count
);
160 static ssize_t
hv_stats_show(struct device
*dev
,
161 struct device_attribute
*attr
,
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,
170 n
= n
< 0 ? 0 : min(n
, (ssize_t
)PAGE_SIZE
- 1);
175 static ssize_t
hv_stats_store(struct device
*dev
,
176 struct device_attribute
*attr
,
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
))
196 err
= sysfs_create_file(&dev
->kobj
, &dev_attr_hv_stats
.attr
);
201 static void hv_stats_device_remove(struct device
*dev
,
202 struct subsys_interface
*sif
)
207 sysfs_remove_file(&dev
->kobj
, &dev_attr_hv_stats
.attr
);
211 static struct subsys_interface hv_stats_interface
= {
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)
222 #define create_cpu_attr(name) \
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) \
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
);
238 err
= sysfs_create_group(hypervisor_kobj
, &board_attr_group
);
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
);
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
));
257 ssize_t n
= hv_confstr(HV_CONFSTR_HV_STATS
,
258 (unsigned long) &dummy
, 1,
261 err
= subsys_interface_register(&hv_stats_interface
);
266 subsys_initcall(create_sysfs_entries
);