1/* 2 * Architecture specific sysfs attributes in /sys/kernel 3 * 4 * Copyright (C) 2007, Intel Corp. 5 * Huang Ying <ying.huang@intel.com> 6 * Copyright (C) 2013, 2013 Red Hat, Inc. 7 * Dave Young <dyoung@redhat.com> 8 * 9 * This file is released under the GPLv2 10 */ 11 12#include <linux/kobject.h> 13#include <linux/string.h> 14#include <linux/sysfs.h> 15#include <linux/init.h> 16#include <linux/stat.h> 17#include <linux/slab.h> 18#include <linux/mm.h> 19 20#include <asm/io.h> 21#include <asm/setup.h> 22 23static ssize_t version_show(struct kobject *kobj, 24 struct kobj_attribute *attr, char *buf) 25{ 26 return sprintf(buf, "0x%04x\n", boot_params.hdr.version); 27} 28 29static struct kobj_attribute boot_params_version_attr = __ATTR_RO(version); 30 31static ssize_t boot_params_data_read(struct file *fp, struct kobject *kobj, 32 struct bin_attribute *bin_attr, 33 char *buf, loff_t off, size_t count) 34{ 35 memcpy(buf, (void *)&boot_params + off, count); 36 return count; 37} 38 39static struct bin_attribute boot_params_data_attr = { 40 .attr = { 41 .name = "data", 42 .mode = S_IRUGO, 43 }, 44 .read = boot_params_data_read, 45 .size = sizeof(boot_params), 46}; 47 48static struct attribute *boot_params_version_attrs[] = { 49 &boot_params_version_attr.attr, 50 NULL, 51}; 52 53static struct bin_attribute *boot_params_data_attrs[] = { 54 &boot_params_data_attr, 55 NULL, 56}; 57 58static struct attribute_group boot_params_attr_group = { 59 .attrs = boot_params_version_attrs, 60 .bin_attrs = boot_params_data_attrs, 61}; 62 63static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr) 64{ 65 const char *name; 66 67 name = kobject_name(kobj); 68 return kstrtoint(name, 10, nr); 69} 70 71static int get_setup_data_paddr(int nr, u64 *paddr) 72{ 73 int i = 0; 74 struct setup_data *data; 75 u64 pa_data = boot_params.hdr.setup_data; 76 77 while (pa_data) { 78 if (nr == i) { 79 *paddr = pa_data; 80 return 0; 81 } 82 data = ioremap_cache(pa_data, sizeof(*data)); 83 if (!data) 84 return -ENOMEM; 85 86 pa_data = data->next; 87 iounmap(data); 88 i++; 89 } 90 return -EINVAL; 91} 92 93static int __init get_setup_data_size(int nr, size_t *size) 94{ 95 int i = 0; 96 struct setup_data *data; 97 u64 pa_data = boot_params.hdr.setup_data; 98 99 while (pa_data) { 100 data = ioremap_cache(pa_data, sizeof(*data)); 101 if (!data) 102 return -ENOMEM; 103 if (nr == i) { 104 *size = data->len; 105 iounmap(data); 106 return 0; 107 } 108 109 pa_data = data->next; 110 iounmap(data); 111 i++; 112 } 113 return -EINVAL; 114} 115 116static ssize_t type_show(struct kobject *kobj, 117 struct kobj_attribute *attr, char *buf) 118{ 119 int nr, ret; 120 u64 paddr; 121 struct setup_data *data; 122 123 ret = kobj_to_setup_data_nr(kobj, &nr); 124 if (ret) 125 return ret; 126 127 ret = get_setup_data_paddr(nr, &paddr); 128 if (ret) 129 return ret; 130 data = ioremap_cache(paddr, sizeof(*data)); 131 if (!data) 132 return -ENOMEM; 133 134 ret = sprintf(buf, "0x%x\n", data->type); 135 iounmap(data); 136 return ret; 137} 138 139static ssize_t setup_data_data_read(struct file *fp, 140 struct kobject *kobj, 141 struct bin_attribute *bin_attr, 142 char *buf, 143 loff_t off, size_t count) 144{ 145 int nr, ret = 0; 146 u64 paddr; 147 struct setup_data *data; 148 void *p; 149 150 ret = kobj_to_setup_data_nr(kobj, &nr); 151 if (ret) 152 return ret; 153 154 ret = get_setup_data_paddr(nr, &paddr); 155 if (ret) 156 return ret; 157 data = ioremap_cache(paddr, sizeof(*data)); 158 if (!data) 159 return -ENOMEM; 160 161 if (off > data->len) { 162 ret = -EINVAL; 163 goto out; 164 } 165 166 if (count > data->len - off) 167 count = data->len - off; 168 169 if (!count) 170 goto out; 171 172 ret = count; 173 p = ioremap_cache(paddr + sizeof(*data), data->len); 174 if (!p) { 175 ret = -ENOMEM; 176 goto out; 177 } 178 memcpy(buf, p + off, count); 179 iounmap(p); 180out: 181 iounmap(data); 182 return ret; 183} 184 185static struct kobj_attribute type_attr = __ATTR_RO(type); 186 187static struct bin_attribute data_attr = { 188 .attr = { 189 .name = "data", 190 .mode = S_IRUGO, 191 }, 192 .read = setup_data_data_read, 193}; 194 195static struct attribute *setup_data_type_attrs[] = { 196 &type_attr.attr, 197 NULL, 198}; 199 200static struct bin_attribute *setup_data_data_attrs[] = { 201 &data_attr, 202 NULL, 203}; 204 205static struct attribute_group setup_data_attr_group = { 206 .attrs = setup_data_type_attrs, 207 .bin_attrs = setup_data_data_attrs, 208}; 209 210static int __init create_setup_data_node(struct kobject *parent, 211 struct kobject **kobjp, int nr) 212{ 213 int ret = 0; 214 size_t size; 215 struct kobject *kobj; 216 char name[16]; /* should be enough for setup_data nodes numbers */ 217 snprintf(name, 16, "%d", nr); 218 219 kobj = kobject_create_and_add(name, parent); 220 if (!kobj) 221 return -ENOMEM; 222 223 ret = get_setup_data_size(nr, &size); 224 if (ret) 225 goto out_kobj; 226 227 data_attr.size = size; 228 ret = sysfs_create_group(kobj, &setup_data_attr_group); 229 if (ret) 230 goto out_kobj; 231 *kobjp = kobj; 232 233 return 0; 234out_kobj: 235 kobject_put(kobj); 236 return ret; 237} 238 239static void __init cleanup_setup_data_node(struct kobject *kobj) 240{ 241 sysfs_remove_group(kobj, &setup_data_attr_group); 242 kobject_put(kobj); 243} 244 245static int __init get_setup_data_total_num(u64 pa_data, int *nr) 246{ 247 int ret = 0; 248 struct setup_data *data; 249 250 *nr = 0; 251 while (pa_data) { 252 *nr += 1; 253 data = ioremap_cache(pa_data, sizeof(*data)); 254 if (!data) { 255 ret = -ENOMEM; 256 goto out; 257 } 258 pa_data = data->next; 259 iounmap(data); 260 } 261 262out: 263 return ret; 264} 265 266static int __init create_setup_data_nodes(struct kobject *parent) 267{ 268 struct kobject *setup_data_kobj, **kobjp; 269 u64 pa_data; 270 int i, j, nr, ret = 0; 271 272 pa_data = boot_params.hdr.setup_data; 273 if (!pa_data) 274 return 0; 275 276 setup_data_kobj = kobject_create_and_add("setup_data", parent); 277 if (!setup_data_kobj) { 278 ret = -ENOMEM; 279 goto out; 280 } 281 282 ret = get_setup_data_total_num(pa_data, &nr); 283 if (ret) 284 goto out_setup_data_kobj; 285 286 kobjp = kmalloc(sizeof(*kobjp) * nr, GFP_KERNEL); 287 if (!kobjp) { 288 ret = -ENOMEM; 289 goto out_setup_data_kobj; 290 } 291 292 for (i = 0; i < nr; i++) { 293 ret = create_setup_data_node(setup_data_kobj, kobjp + i, i); 294 if (ret) 295 goto out_clean_nodes; 296 } 297 298 kfree(kobjp); 299 return 0; 300 301out_clean_nodes: 302 for (j = i - 1; j > 0; j--) 303 cleanup_setup_data_node(*(kobjp + j)); 304 kfree(kobjp); 305out_setup_data_kobj: 306 kobject_put(setup_data_kobj); 307out: 308 return ret; 309} 310 311static int __init boot_params_ksysfs_init(void) 312{ 313 int ret; 314 struct kobject *boot_params_kobj; 315 316 boot_params_kobj = kobject_create_and_add("boot_params", 317 kernel_kobj); 318 if (!boot_params_kobj) { 319 ret = -ENOMEM; 320 goto out; 321 } 322 323 ret = sysfs_create_group(boot_params_kobj, &boot_params_attr_group); 324 if (ret) 325 goto out_boot_params_kobj; 326 327 ret = create_setup_data_nodes(boot_params_kobj); 328 if (ret) 329 goto out_create_group; 330 331 return 0; 332out_create_group: 333 sysfs_remove_group(boot_params_kobj, &boot_params_attr_group); 334out_boot_params_kobj: 335 kobject_put(boot_params_kobj); 336out: 337 return ret; 338} 339 340arch_initcall(boot_params_ksysfs_init); 341