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