blob: 5de6bb406fb673629d2c00054e5c2a956bc94f4e [file] [log] [blame]
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -05001/*
2 * drivers/firmware/qemu_fw_cfg.c
3 *
4 * Copyright 2015 Carnegie Mellon University
5 *
6 * Expose entries from QEMU's firmware configuration (fw_cfg) device in
7 * sysfs (read-only, under "/sys/firmware/qemu_fw_cfg/...").
8 *
9 * The fw_cfg device may be instantiated via either an ACPI node (on x86
10 * and select subsets of aarch64), a Device Tree node (on arm), or using
11 * a kernel module (or command line) parameter with the following syntax:
12 *
Marc-André Lureauc1d0c3f2017-11-13 20:29:54 +010013 * [qemu_fw_cfg.]ioport=<size>@<base>[:<ctrl_off>:<data_off>]
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050014 * or
Marc-André Lureauc1d0c3f2017-11-13 20:29:54 +010015 * [qemu_fw_cfg.]mmio=<size>@<base>[:<ctrl_off>:<data_off>]
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050016 *
17 * where:
18 * <size> := size of ioport or mmio range
19 * <base> := physical base address of ioport or mmio range
20 * <ctrl_off> := (optional) offset of control register
21 * <data_off> := (optional) offset of data register
22 *
23 * e.g.:
Marc-André Lureauc1d0c3f2017-11-13 20:29:54 +010024 * qemu_fw_cfg.ioport=2@0x510:0:1 (the default on x86)
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050025 * or
Marc-André Lureauc1d0c3f2017-11-13 20:29:54 +010026 * qemu_fw_cfg.mmio=0xA@0x9020000:8:0 (the default on arm)
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050027 */
28
29#include <linux/module.h>
30#include <linux/platform_device.h>
31#include <linux/acpi.h>
32#include <linux/slab.h>
33#include <linux/io.h>
34#include <linux/ioport.h>
Marc-André Lureau1f57bc12018-02-28 16:06:11 +010035#include <uapi/linux/qemu_fw_cfg.h>
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050036
37MODULE_AUTHOR("Gabriel L. Somlo <somlo@cmu.edu>");
38MODULE_DESCRIPTION("QEMU fw_cfg sysfs support");
39MODULE_LICENSE("GPL");
40
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050041/* fw_cfg device i/o register addresses */
42static bool fw_cfg_is_mmio;
43static phys_addr_t fw_cfg_p_base;
44static resource_size_t fw_cfg_p_size;
45static void __iomem *fw_cfg_dev_base;
46static void __iomem *fw_cfg_reg_ctrl;
47static void __iomem *fw_cfg_reg_data;
48
49/* atomic access to fw_cfg device (potentially slow i/o, so using mutex) */
50static DEFINE_MUTEX(fw_cfg_dev_lock);
51
52/* pick appropriate endianness for selector key */
Marc-André Lureau8d59d5b2018-02-28 16:06:05 +010053static void fw_cfg_sel_endianness(u16 key)
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050054{
Marc-André Lureau8d59d5b2018-02-28 16:06:05 +010055 if (fw_cfg_is_mmio)
56 iowrite16be(key, fw_cfg_reg_ctrl);
57 else
58 iowrite16(key, fw_cfg_reg_ctrl);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050059}
60
61/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
Marc-André Lureaub1cc4092018-02-28 16:06:10 +010062static ssize_t fw_cfg_read_blob(u16 key,
63 void *buf, loff_t pos, size_t count)
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050064{
Dan Carpenterd4f6e272016-04-14 12:33:37 +030065 u32 glk = -1U;
Gabriel Somlodef7ac82016-03-08 13:30:50 -050066 acpi_status status;
67
68 /* If we have ACPI, ensure mutual exclusion against any potential
69 * device access by the firmware, e.g. via AML methods:
70 */
71 status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk);
72 if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
73 /* Should never get here */
74 WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
75 memset(buf, 0, count);
Marc-André Lureaub1cc4092018-02-28 16:06:10 +010076 return -EINVAL;
Gabriel Somlodef7ac82016-03-08 13:30:50 -050077 }
78
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050079 mutex_lock(&fw_cfg_dev_lock);
Marc-André Lureau8d59d5b2018-02-28 16:06:05 +010080 fw_cfg_sel_endianness(key);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050081 while (pos-- > 0)
82 ioread8(fw_cfg_reg_data);
83 ioread8_rep(fw_cfg_reg_data, buf, count);
84 mutex_unlock(&fw_cfg_dev_lock);
Gabriel Somlodef7ac82016-03-08 13:30:50 -050085
86 acpi_release_global_lock(glk);
Marc-André Lureaub1cc4092018-02-28 16:06:10 +010087 return count;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -050088}
89
90/* clean up fw_cfg device i/o */
91static void fw_cfg_io_cleanup(void)
92{
93 if (fw_cfg_is_mmio) {
94 iounmap(fw_cfg_dev_base);
95 release_mem_region(fw_cfg_p_base, fw_cfg_p_size);
96 } else {
97 ioport_unmap(fw_cfg_dev_base);
98 release_region(fw_cfg_p_base, fw_cfg_p_size);
99 }
100}
101
102/* arch-specific ctrl & data register offsets are not available in ACPI, DT */
Valentin Rothberg9b3ec232016-02-11 12:19:03 +0100103#if !(defined(FW_CFG_CTRL_OFF) && defined(FW_CFG_DATA_OFF))
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500104# if (defined(CONFIG_ARM) || defined(CONFIG_ARM64))
105# define FW_CFG_CTRL_OFF 0x08
106# define FW_CFG_DATA_OFF 0x00
107# elif (defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC32)) /* ppc/mac,sun4m */
108# define FW_CFG_CTRL_OFF 0x00
109# define FW_CFG_DATA_OFF 0x02
110# elif (defined(CONFIG_X86) || defined(CONFIG_SPARC64)) /* x86, sun4u */
111# define FW_CFG_CTRL_OFF 0x00
112# define FW_CFG_DATA_OFF 0x01
113# else
Gabriel Somlo00411b72016-02-22 16:18:18 -0500114# error "QEMU FW_CFG not available on this architecture!"
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500115# endif
116#endif
117
118/* initialize fw_cfg device i/o from platform data */
119static int fw_cfg_do_platform_probe(struct platform_device *pdev)
120{
121 char sig[FW_CFG_SIG_SIZE];
122 struct resource *range, *ctrl, *data;
123
124 /* acquire i/o range details */
125 fw_cfg_is_mmio = false;
126 range = platform_get_resource(pdev, IORESOURCE_IO, 0);
127 if (!range) {
128 fw_cfg_is_mmio = true;
129 range = platform_get_resource(pdev, IORESOURCE_MEM, 0);
130 if (!range)
131 return -EINVAL;
132 }
133 fw_cfg_p_base = range->start;
134 fw_cfg_p_size = resource_size(range);
135
136 if (fw_cfg_is_mmio) {
137 if (!request_mem_region(fw_cfg_p_base,
138 fw_cfg_p_size, "fw_cfg_mem"))
139 return -EBUSY;
140 fw_cfg_dev_base = ioremap(fw_cfg_p_base, fw_cfg_p_size);
141 if (!fw_cfg_dev_base) {
142 release_mem_region(fw_cfg_p_base, fw_cfg_p_size);
143 return -EFAULT;
144 }
145 } else {
146 if (!request_region(fw_cfg_p_base,
147 fw_cfg_p_size, "fw_cfg_io"))
148 return -EBUSY;
149 fw_cfg_dev_base = ioport_map(fw_cfg_p_base, fw_cfg_p_size);
150 if (!fw_cfg_dev_base) {
151 release_region(fw_cfg_p_base, fw_cfg_p_size);
152 return -EFAULT;
153 }
154 }
155
156 /* were custom register offsets provided (e.g. on the command line)? */
157 ctrl = platform_get_resource_byname(pdev, IORESOURCE_REG, "ctrl");
158 data = platform_get_resource_byname(pdev, IORESOURCE_REG, "data");
159 if (ctrl && data) {
160 fw_cfg_reg_ctrl = fw_cfg_dev_base + ctrl->start;
161 fw_cfg_reg_data = fw_cfg_dev_base + data->start;
162 } else {
163 /* use architecture-specific offsets */
164 fw_cfg_reg_ctrl = fw_cfg_dev_base + FW_CFG_CTRL_OFF;
165 fw_cfg_reg_data = fw_cfg_dev_base + FW_CFG_DATA_OFF;
166 }
167
168 /* verify fw_cfg device signature */
Marc-André Lureaub1cc4092018-02-28 16:06:10 +0100169 if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
170 0, FW_CFG_SIG_SIZE) < 0 ||
171 memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500172 fw_cfg_io_cleanup();
173 return -ENODEV;
174 }
175
176 return 0;
177}
178
179/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */
180static u32 fw_cfg_rev;
181
182static ssize_t fw_cfg_showrev(struct kobject *k, struct attribute *a, char *buf)
183{
184 return sprintf(buf, "%u\n", fw_cfg_rev);
185}
186
187static const struct {
188 struct attribute attr;
189 ssize_t (*show)(struct kobject *k, struct attribute *a, char *buf);
190} fw_cfg_rev_attr = {
191 .attr = { .name = "rev", .mode = S_IRUSR },
192 .show = fw_cfg_showrev,
193};
194
195/* fw_cfg_sysfs_entry type */
196struct fw_cfg_sysfs_entry {
197 struct kobject kobj;
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100198 u32 size;
199 u16 select;
200 char name[FW_CFG_MAX_FILE_PATH];
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500201 struct list_head list;
202};
203
204/* get fw_cfg_sysfs_entry from kobject member */
205static inline struct fw_cfg_sysfs_entry *to_entry(struct kobject *kobj)
206{
207 return container_of(kobj, struct fw_cfg_sysfs_entry, kobj);
208}
209
210/* fw_cfg_sysfs_attribute type */
211struct fw_cfg_sysfs_attribute {
212 struct attribute attr;
213 ssize_t (*show)(struct fw_cfg_sysfs_entry *entry, char *buf);
214};
215
216/* get fw_cfg_sysfs_attribute from attribute member */
217static inline struct fw_cfg_sysfs_attribute *to_attr(struct attribute *attr)
218{
219 return container_of(attr, struct fw_cfg_sysfs_attribute, attr);
220}
221
222/* global cache of fw_cfg_sysfs_entry objects */
223static LIST_HEAD(fw_cfg_entry_cache);
224
225/* kobjects removed lazily by kernel, mutual exclusion needed */
226static DEFINE_SPINLOCK(fw_cfg_cache_lock);
227
228static inline void fw_cfg_sysfs_cache_enlist(struct fw_cfg_sysfs_entry *entry)
229{
230 spin_lock(&fw_cfg_cache_lock);
231 list_add_tail(&entry->list, &fw_cfg_entry_cache);
232 spin_unlock(&fw_cfg_cache_lock);
233}
234
235static inline void fw_cfg_sysfs_cache_delist(struct fw_cfg_sysfs_entry *entry)
236{
237 spin_lock(&fw_cfg_cache_lock);
238 list_del(&entry->list);
239 spin_unlock(&fw_cfg_cache_lock);
240}
241
242static void fw_cfg_sysfs_cache_cleanup(void)
243{
244 struct fw_cfg_sysfs_entry *entry, *next;
245
246 list_for_each_entry_safe(entry, next, &fw_cfg_entry_cache, list) {
247 /* will end up invoking fw_cfg_sysfs_cache_delist()
248 * via each object's release() method (i.e. destructor)
249 */
250 kobject_put(&entry->kobj);
251 }
252}
253
254/* default_attrs: per-entry attributes and show methods */
255
256#define FW_CFG_SYSFS_ATTR(_attr) \
257struct fw_cfg_sysfs_attribute fw_cfg_sysfs_attr_##_attr = { \
258 .attr = { .name = __stringify(_attr), .mode = S_IRUSR }, \
259 .show = fw_cfg_sysfs_show_##_attr, \
260}
261
262static ssize_t fw_cfg_sysfs_show_size(struct fw_cfg_sysfs_entry *e, char *buf)
263{
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100264 return sprintf(buf, "%u\n", e->size);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500265}
266
267static ssize_t fw_cfg_sysfs_show_key(struct fw_cfg_sysfs_entry *e, char *buf)
268{
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100269 return sprintf(buf, "%u\n", e->select);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500270}
271
272static ssize_t fw_cfg_sysfs_show_name(struct fw_cfg_sysfs_entry *e, char *buf)
273{
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100274 return sprintf(buf, "%s\n", e->name);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500275}
276
277static FW_CFG_SYSFS_ATTR(size);
278static FW_CFG_SYSFS_ATTR(key);
279static FW_CFG_SYSFS_ATTR(name);
280
281static struct attribute *fw_cfg_sysfs_entry_attrs[] = {
282 &fw_cfg_sysfs_attr_size.attr,
283 &fw_cfg_sysfs_attr_key.attr,
284 &fw_cfg_sysfs_attr_name.attr,
285 NULL,
286};
287
288/* sysfs_ops: find fw_cfg_[entry, attribute] and call appropriate show method */
289static ssize_t fw_cfg_sysfs_attr_show(struct kobject *kobj, struct attribute *a,
290 char *buf)
291{
292 struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
293 struct fw_cfg_sysfs_attribute *attr = to_attr(a);
294
295 return attr->show(entry, buf);
296}
297
298static const struct sysfs_ops fw_cfg_sysfs_attr_ops = {
299 .show = fw_cfg_sysfs_attr_show,
300};
301
302/* release: destructor, to be called via kobject_put() */
303static void fw_cfg_sysfs_release_entry(struct kobject *kobj)
304{
305 struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
306
307 fw_cfg_sysfs_cache_delist(entry);
308 kfree(entry);
309}
310
311/* kobj_type: ties together all properties required to register an entry */
312static struct kobj_type fw_cfg_sysfs_entry_ktype = {
313 .default_attrs = fw_cfg_sysfs_entry_attrs,
314 .sysfs_ops = &fw_cfg_sysfs_attr_ops,
315 .release = fw_cfg_sysfs_release_entry,
316};
317
318/* raw-read method and attribute */
319static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, struct kobject *kobj,
320 struct bin_attribute *bin_attr,
321 char *buf, loff_t pos, size_t count)
322{
323 struct fw_cfg_sysfs_entry *entry = to_entry(kobj);
324
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100325 if (pos > entry->size)
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500326 return -EINVAL;
327
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100328 if (count > entry->size - pos)
329 count = entry->size - pos;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500330
Marc-André Lureaub1cc4092018-02-28 16:06:10 +0100331 return fw_cfg_read_blob(entry->select, buf, pos, count);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500332}
333
334static struct bin_attribute fw_cfg_sysfs_attr_raw = {
335 .attr = { .name = "raw", .mode = S_IRUSR },
336 .read = fw_cfg_sysfs_read_raw,
337};
338
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500339/*
340 * Create a kset subdirectory matching each '/' delimited dirname token
341 * in 'name', starting with sysfs kset/folder 'dir'; At the end, create
342 * a symlink directed at the given 'target'.
343 * NOTE: We do this on a best-effort basis, since 'name' is not guaranteed
344 * to be a well-behaved path name. Whenever a symlink vs. kset directory
345 * name collision occurs, the kernel will issue big scary warnings while
346 * refusing to add the offending link or directory. We follow up with our
347 * own, slightly less scary error messages explaining the situation :)
348 */
349static int fw_cfg_build_symlink(struct kset *dir,
350 struct kobject *target, const char *name)
351{
352 int ret;
353 struct kset *subdir;
354 struct kobject *ko;
355 char *name_copy, *p, *tok;
356
357 if (!dir || !target || !name || !*name)
358 return -EINVAL;
359
360 /* clone a copy of name for parsing */
361 name_copy = p = kstrdup(name, GFP_KERNEL);
362 if (!name_copy)
363 return -ENOMEM;
364
365 /* create folders for each dirname token, then symlink for basename */
366 while ((tok = strsep(&p, "/")) && *tok) {
367
368 /* last (basename) token? If so, add symlink here */
369 if (!p || !*p) {
370 ret = sysfs_create_link(&dir->kobj, target, tok);
371 break;
372 }
373
374 /* does the current dir contain an item named after tok ? */
375 ko = kset_find_obj(dir, tok);
376 if (ko) {
377 /* drop reference added by kset_find_obj */
378 kobject_put(ko);
379
380 /* ko MUST be a kset - we're about to use it as one ! */
381 if (ko->ktype != dir->kobj.ktype) {
382 ret = -EINVAL;
383 break;
384 }
385
386 /* descend into already existing subdirectory */
387 dir = to_kset(ko);
388 } else {
389 /* create new subdirectory kset */
390 subdir = kzalloc(sizeof(struct kset), GFP_KERNEL);
391 if (!subdir) {
392 ret = -ENOMEM;
393 break;
394 }
395 subdir->kobj.kset = dir;
396 subdir->kobj.ktype = dir->kobj.ktype;
397 ret = kobject_set_name(&subdir->kobj, "%s", tok);
398 if (ret) {
399 kfree(subdir);
400 break;
401 }
402 ret = kset_register(subdir);
403 if (ret) {
404 kfree(subdir);
405 break;
406 }
407
408 /* descend into newly created subdirectory */
409 dir = subdir;
410 }
411 }
412
413 /* we're done with cloned copy of name */
414 kfree(name_copy);
415 return ret;
416}
417
418/* recursively unregister fw_cfg/by_name/ kset directory tree */
419static void fw_cfg_kset_unregister_recursive(struct kset *kset)
420{
421 struct kobject *k, *next;
422
423 list_for_each_entry_safe(k, next, &kset->list, entry)
424 /* all set members are ksets too, but check just in case... */
425 if (k->ktype == kset->kobj.ktype)
426 fw_cfg_kset_unregister_recursive(to_kset(k));
427
428 /* symlinks are cleanly and automatically removed with the directory */
429 kset_unregister(kset);
430}
431
432/* kobjects & kset representing top-level, by_key, and by_name folders */
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500433static struct kobject *fw_cfg_top_ko;
434static struct kobject *fw_cfg_sel_ko;
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500435static struct kset *fw_cfg_fname_kset;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500436
437/* register an individual fw_cfg file */
438static int fw_cfg_register_file(const struct fw_cfg_file *f)
439{
440 int err;
441 struct fw_cfg_sysfs_entry *entry;
442
443 /* allocate new entry */
444 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
445 if (!entry)
446 return -ENOMEM;
447
448 /* set file entry information */
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100449 entry->size = be32_to_cpu(f->size);
450 entry->select = be16_to_cpu(f->select);
451 memcpy(entry->name, f->name, FW_CFG_MAX_FILE_PATH);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500452
453 /* register entry under "/sys/firmware/qemu_fw_cfg/by_key/" */
454 err = kobject_init_and_add(&entry->kobj, &fw_cfg_sysfs_entry_ktype,
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100455 fw_cfg_sel_ko, "%d", entry->select);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500456 if (err)
457 goto err_register;
458
459 /* add raw binary content access */
460 err = sysfs_create_bin_file(&entry->kobj, &fw_cfg_sysfs_attr_raw);
461 if (err)
462 goto err_add_raw;
463
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500464 /* try adding "/sys/firmware/qemu_fw_cfg/by_name/" symlink */
Marc-André Lureaud174ea7d2018-02-28 16:06:06 +0100465 fw_cfg_build_symlink(fw_cfg_fname_kset, &entry->kobj, entry->name);
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500466
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500467 /* success, add entry to global cache */
468 fw_cfg_sysfs_cache_enlist(entry);
469 return 0;
470
471err_add_raw:
472 kobject_del(&entry->kobj);
473err_register:
474 kfree(entry);
475 return err;
476}
477
478/* iterate over all fw_cfg directory entries, registering each one */
479static int fw_cfg_register_dir_entries(void)
480{
481 int ret = 0;
Marc-André Lureau3d47a342018-02-28 16:06:08 +0100482 __be32 files_count;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500483 u32 count, i;
484 struct fw_cfg_file *dir;
485 size_t dir_size;
486
Marc-André Lureaub1cc4092018-02-28 16:06:10 +0100487 ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, &files_count,
488 0, sizeof(files_count));
489 if (ret < 0)
490 return ret;
491
Marc-André Lureau3d47a342018-02-28 16:06:08 +0100492 count = be32_to_cpu(files_count);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500493 dir_size = count * sizeof(struct fw_cfg_file);
494
495 dir = kmalloc(dir_size, GFP_KERNEL);
496 if (!dir)
497 return -ENOMEM;
498
Marc-André Lureaub1cc4092018-02-28 16:06:10 +0100499 ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
500 sizeof(files_count), dir_size);
501 if (ret < 0)
502 goto end;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500503
504 for (i = 0; i < count; i++) {
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500505 ret = fw_cfg_register_file(&dir[i]);
506 if (ret)
507 break;
508 }
509
Marc-André Lureaub1cc4092018-02-28 16:06:10 +0100510end:
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500511 kfree(dir);
512 return ret;
513}
514
515/* unregister top-level or by_key folder */
516static inline void fw_cfg_kobj_cleanup(struct kobject *kobj)
517{
518 kobject_del(kobj);
519 kobject_put(kobj);
520}
521
522static int fw_cfg_sysfs_probe(struct platform_device *pdev)
523{
524 int err;
Marc-André Lureauf295c8d2018-02-28 16:06:07 +0100525 __le32 rev;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500526
527 /* NOTE: If we supported multiple fw_cfg devices, we'd first create
528 * a subdirectory named after e.g. pdev->id, then hang per-device
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500529 * by_key (and by_name) subdirectories underneath it. However, only
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500530 * one fw_cfg device exist system-wide, so if one was already found
531 * earlier, we might as well stop here.
532 */
533 if (fw_cfg_sel_ko)
534 return -EBUSY;
535
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500536 /* create by_key and by_name subdirs of /sys/firmware/qemu_fw_cfg/ */
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500537 err = -ENOMEM;
538 fw_cfg_sel_ko = kobject_create_and_add("by_key", fw_cfg_top_ko);
539 if (!fw_cfg_sel_ko)
540 goto err_sel;
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500541 fw_cfg_fname_kset = kset_create_and_add("by_name", NULL, fw_cfg_top_ko);
542 if (!fw_cfg_fname_kset)
543 goto err_name;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500544
545 /* initialize fw_cfg device i/o from platform data */
546 err = fw_cfg_do_platform_probe(pdev);
547 if (err)
548 goto err_probe;
549
550 /* get revision number, add matching top-level attribute */
Marc-André Lureaub1cc4092018-02-28 16:06:10 +0100551 err = fw_cfg_read_blob(FW_CFG_ID, &rev, 0, sizeof(rev));
552 if (err < 0)
553 goto err_probe;
554
Marc-André Lureauf295c8d2018-02-28 16:06:07 +0100555 fw_cfg_rev = le32_to_cpu(rev);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500556 err = sysfs_create_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);
557 if (err)
558 goto err_rev;
559
560 /* process fw_cfg file directory entry, registering each file */
561 err = fw_cfg_register_dir_entries();
562 if (err)
563 goto err_dir;
564
565 /* success */
566 pr_debug("fw_cfg: loaded.\n");
567 return 0;
568
569err_dir:
570 fw_cfg_sysfs_cache_cleanup();
571 sysfs_remove_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);
572err_rev:
573 fw_cfg_io_cleanup();
574err_probe:
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500575 fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
576err_name:
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500577 fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
578err_sel:
579 return err;
580}
581
582static int fw_cfg_sysfs_remove(struct platform_device *pdev)
583{
584 pr_debug("fw_cfg: unloading.\n");
585 fw_cfg_sysfs_cache_cleanup();
Marc-André Lureau23f1b8d2017-11-20 10:55:15 +0100586 sysfs_remove_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);
587 fw_cfg_io_cleanup();
Gabriel Somlo246c46e2016-01-28 09:23:13 -0500588 fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500589 fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500590 return 0;
591}
592
593static const struct of_device_id fw_cfg_sysfs_mmio_match[] = {
594 { .compatible = "qemu,fw-cfg-mmio", },
595 {},
596};
597MODULE_DEVICE_TABLE(of, fw_cfg_sysfs_mmio_match);
598
599#ifdef CONFIG_ACPI
600static const struct acpi_device_id fw_cfg_sysfs_acpi_match[] = {
Marc-André Lureau1f57bc12018-02-28 16:06:11 +0100601 { FW_CFG_ACPI_DEVICE_ID, },
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500602 {},
603};
604MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
605#endif
606
607static struct platform_driver fw_cfg_sysfs_driver = {
608 .probe = fw_cfg_sysfs_probe,
609 .remove = fw_cfg_sysfs_remove,
610 .driver = {
611 .name = "fw_cfg",
612 .of_match_table = fw_cfg_sysfs_mmio_match,
613 .acpi_match_table = ACPI_PTR(fw_cfg_sysfs_acpi_match),
614 },
615};
616
617#ifdef CONFIG_FW_CFG_SYSFS_CMDLINE
618
619static struct platform_device *fw_cfg_cmdline_dev;
620
621/* this probably belongs in e.g. include/linux/types.h,
622 * but right now we are the only ones doing it...
623 */
624#ifdef CONFIG_PHYS_ADDR_T_64BIT
625#define __PHYS_ADDR_PREFIX "ll"
626#else
627#define __PHYS_ADDR_PREFIX ""
628#endif
629
630/* use special scanf/printf modifier for phys_addr_t, resource_size_t */
631#define PH_ADDR_SCAN_FMT "@%" __PHYS_ADDR_PREFIX "i%n" \
632 ":%" __PHYS_ADDR_PREFIX "i" \
633 ":%" __PHYS_ADDR_PREFIX "i%n"
634
635#define PH_ADDR_PR_1_FMT "0x%" __PHYS_ADDR_PREFIX "x@" \
636 "0x%" __PHYS_ADDR_PREFIX "x"
637
638#define PH_ADDR_PR_3_FMT PH_ADDR_PR_1_FMT \
639 ":%" __PHYS_ADDR_PREFIX "u" \
640 ":%" __PHYS_ADDR_PREFIX "u"
641
642static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
643{
644 struct resource res[3] = {};
645 char *str;
646 phys_addr_t base;
647 resource_size_t size, ctrl_off, data_off;
648 int processed, consumed = 0;
649
650 /* only one fw_cfg device can exist system-wide, so if one
651 * was processed on the command line already, we might as
652 * well stop here.
653 */
654 if (fw_cfg_cmdline_dev) {
655 /* avoid leaking previously registered device */
656 platform_device_unregister(fw_cfg_cmdline_dev);
657 return -EINVAL;
658 }
659
660 /* consume "<size>" portion of command line argument */
661 size = memparse(arg, &str);
662
663 /* get "@<base>[:<ctrl_off>:<data_off>]" chunks */
664 processed = sscanf(str, PH_ADDR_SCAN_FMT,
665 &base, &consumed,
666 &ctrl_off, &data_off, &consumed);
667
668 /* sscanf() must process precisely 1 or 3 chunks:
669 * <base> is mandatory, optionally followed by <ctrl_off>
670 * and <data_off>;
671 * there must be no extra characters after the last chunk,
672 * so str[consumed] must be '\0'.
673 */
674 if (str[consumed] ||
675 (processed != 1 && processed != 3))
676 return -EINVAL;
677
678 res[0].start = base;
679 res[0].end = base + size - 1;
680 res[0].flags = !strcmp(kp->name, "mmio") ? IORESOURCE_MEM :
681 IORESOURCE_IO;
682
683 /* insert register offsets, if provided */
684 if (processed > 1) {
685 res[1].name = "ctrl";
686 res[1].start = ctrl_off;
687 res[1].flags = IORESOURCE_REG;
688 res[2].name = "data";
689 res[2].start = data_off;
690 res[2].flags = IORESOURCE_REG;
691 }
692
693 /* "processed" happens to nicely match the number of resources
694 * we need to pass in to this platform device.
695 */
696 fw_cfg_cmdline_dev = platform_device_register_simple("fw_cfg",
697 PLATFORM_DEVID_NONE, res, processed);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500698
Vasyl Gomonovych0a9e63a2017-11-28 22:40:27 +0100699 return PTR_ERR_OR_ZERO(fw_cfg_cmdline_dev);
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500700}
701
702static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
703{
704 /* stay silent if device was not configured via the command
705 * line, or if the parameter name (ioport/mmio) doesn't match
706 * the device setting
707 */
708 if (!fw_cfg_cmdline_dev ||
709 (!strcmp(kp->name, "mmio") ^
710 (fw_cfg_cmdline_dev->resource[0].flags == IORESOURCE_MEM)))
711 return 0;
712
713 switch (fw_cfg_cmdline_dev->num_resources) {
714 case 1:
715 return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_1_FMT,
716 resource_size(&fw_cfg_cmdline_dev->resource[0]),
717 fw_cfg_cmdline_dev->resource[0].start);
718 case 3:
719 return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_3_FMT,
720 resource_size(&fw_cfg_cmdline_dev->resource[0]),
721 fw_cfg_cmdline_dev->resource[0].start,
722 fw_cfg_cmdline_dev->resource[1].start,
723 fw_cfg_cmdline_dev->resource[2].start);
724 }
725
726 /* Should never get here */
727 WARN(1, "Unexpected number of resources: %d\n",
728 fw_cfg_cmdline_dev->num_resources);
729 return 0;
730}
731
732static const struct kernel_param_ops fw_cfg_cmdline_param_ops = {
733 .set = fw_cfg_cmdline_set,
734 .get = fw_cfg_cmdline_get,
735};
736
737device_param_cb(ioport, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
738device_param_cb(mmio, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
739
740#endif /* CONFIG_FW_CFG_SYSFS_CMDLINE */
741
742static int __init fw_cfg_sysfs_init(void)
743{
Michael S. Tsirkine8aabc62016-04-03 15:22:08 +0300744 int ret;
745
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500746 /* create /sys/firmware/qemu_fw_cfg/ top level directory */
747 fw_cfg_top_ko = kobject_create_and_add("qemu_fw_cfg", firmware_kobj);
748 if (!fw_cfg_top_ko)
749 return -ENOMEM;
750
Michael S. Tsirkine8aabc62016-04-03 15:22:08 +0300751 ret = platform_driver_register(&fw_cfg_sysfs_driver);
752 if (ret)
753 fw_cfg_kobj_cleanup(fw_cfg_top_ko);
754
755 return ret;
Gabriel Somlo75f3e8e2016-01-28 09:23:11 -0500756}
757
758static void __exit fw_cfg_sysfs_exit(void)
759{
760 platform_driver_unregister(&fw_cfg_sysfs_driver);
761
762#ifdef CONFIG_FW_CFG_SYSFS_CMDLINE
763 platform_device_unregister(fw_cfg_cmdline_dev);
764#endif
765
766 /* clean up /sys/firmware/qemu_fw_cfg/ */
767 fw_cfg_kobj_cleanup(fw_cfg_top_ko);
768}
769
770module_init(fw_cfg_sysfs_init);
771module_exit(fw_cfg_sysfs_exit);