diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-01-31 05:13:55 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-02-03 20:57:40 -0500 |
commit | 7b1269f778782d2f42994a74bf4014d0cbebbf9f (patch) | |
tree | c6b76a1310fb7c6910a8450c2c6f13f703a2da86 | |
parent | 4e0c92d015235d1dc65f9668a10cef2cea468ba2 (diff) |
firmware: Make user-mode helper optional
This patch adds a new kconfig, CONFIG_FW_LOADER_USER_HELPER, and
guards the user-helper codes in firmware_class.c with ifdefs.
Yeah, yeah, there are lots of ifdefs in this patch. The further
clean-up with code shuffling follows in the next.
Acked-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/base/Kconfig | 11 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 57 |
2 files changed, 55 insertions, 13 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index c8b453939da2..07abd9d76f7f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -145,6 +145,17 @@ config EXTRA_FIRMWARE_DIR | |||
145 | this option you can point it elsewhere, such as /lib/firmware/ or | 145 | this option you can point it elsewhere, such as /lib/firmware/ or |
146 | some other directory containing the firmware files. | 146 | some other directory containing the firmware files. |
147 | 147 | ||
148 | config FW_LOADER_USER_HELPER | ||
149 | bool "Fallback user-helper invocation for firmware loading" | ||
150 | depends on FW_LOADER | ||
151 | default y | ||
152 | help | ||
153 | This option enables / disables the invocation of user-helper | ||
154 | (e.g. udev) for loading firmware files as a fallback after the | ||
155 | direct file loading in kernel fails. The user-mode helper is | ||
156 | no longer required unless you have a special firmware file that | ||
157 | resides in a non-standard path. | ||
158 | |||
148 | config DEBUG_DRIVER | 159 | config DEBUG_DRIVER |
149 | bool "Driver Core verbose debug messages" | 160 | bool "Driver Core verbose debug messages" |
150 | depends on DEBUG_KERNEL | 161 | depends on DEBUG_KERNEL |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 40ec60affd8f..84b1c8d0ea56 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -88,10 +88,12 @@ enum { | |||
88 | FW_STATUS_ABORT, | 88 | FW_STATUS_ABORT, |
89 | }; | 89 | }; |
90 | 90 | ||
91 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
91 | enum fw_buf_fmt { | 92 | enum fw_buf_fmt { |
92 | VMALLOC_BUF, /* used in direct loading */ | 93 | VMALLOC_BUF, /* used in direct loading */ |
93 | PAGE_BUF, /* used in loading via userspace */ | 94 | PAGE_BUF, /* used in loading via userspace */ |
94 | }; | 95 | }; |
96 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
95 | 97 | ||
96 | static int loading_timeout = 60; /* In seconds */ | 98 | static int loading_timeout = 60; /* In seconds */ |
97 | 99 | ||
@@ -128,12 +130,14 @@ struct firmware_buf { | |||
128 | struct completion completion; | 130 | struct completion completion; |
129 | struct firmware_cache *fwc; | 131 | struct firmware_cache *fwc; |
130 | unsigned long status; | 132 | unsigned long status; |
131 | enum fw_buf_fmt fmt; | ||
132 | void *data; | 133 | void *data; |
133 | size_t size; | 134 | size_t size; |
135 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
136 | enum fw_buf_fmt fmt; | ||
134 | struct page **pages; | 137 | struct page **pages; |
135 | int nr_pages; | 138 | int nr_pages; |
136 | int page_array_size; | 139 | int page_array_size; |
140 | #endif | ||
137 | char fw_id[]; | 141 | char fw_id[]; |
138 | }; | 142 | }; |
139 | 143 | ||
@@ -142,6 +146,7 @@ struct fw_cache_entry { | |||
142 | char name[]; | 146 | char name[]; |
143 | }; | 147 | }; |
144 | 148 | ||
149 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
145 | struct firmware_priv { | 150 | struct firmware_priv { |
146 | struct delayed_work timeout_work; | 151 | struct delayed_work timeout_work; |
147 | bool nowait; | 152 | bool nowait; |
@@ -149,6 +154,7 @@ struct firmware_priv { | |||
149 | struct firmware_buf *buf; | 154 | struct firmware_buf *buf; |
150 | struct firmware *fw; | 155 | struct firmware *fw; |
151 | }; | 156 | }; |
157 | #endif | ||
152 | 158 | ||
153 | struct fw_name_devm { | 159 | struct fw_name_devm { |
154 | unsigned long magic; | 160 | unsigned long magic; |
@@ -182,7 +188,9 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, | |||
182 | strcpy(buf->fw_id, fw_name); | 188 | strcpy(buf->fw_id, fw_name); |
183 | buf->fwc = fwc; | 189 | buf->fwc = fwc; |
184 | init_completion(&buf->completion); | 190 | init_completion(&buf->completion); |
191 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
185 | buf->fmt = VMALLOC_BUF; | 192 | buf->fmt = VMALLOC_BUF; |
193 | #endif | ||
186 | 194 | ||
187 | pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); | 195 | pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf); |
188 | 196 | ||
@@ -240,7 +248,6 @@ static void __fw_free_buf(struct kref *ref) | |||
240 | { | 248 | { |
241 | struct firmware_buf *buf = to_fwbuf(ref); | 249 | struct firmware_buf *buf = to_fwbuf(ref); |
242 | struct firmware_cache *fwc = buf->fwc; | 250 | struct firmware_cache *fwc = buf->fwc; |
243 | int i; | ||
244 | 251 | ||
245 | pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", | 252 | pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", |
246 | __func__, buf->fw_id, buf, buf->data, | 253 | __func__, buf->fw_id, buf, buf->data, |
@@ -250,12 +257,15 @@ static void __fw_free_buf(struct kref *ref) | |||
250 | spin_unlock(&fwc->lock); | 257 | spin_unlock(&fwc->lock); |
251 | 258 | ||
252 | 259 | ||
260 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
253 | if (buf->fmt == PAGE_BUF) { | 261 | if (buf->fmt == PAGE_BUF) { |
262 | int i; | ||
254 | vunmap(buf->data); | 263 | vunmap(buf->data); |
255 | for (i = 0; i < buf->nr_pages; i++) | 264 | for (i = 0; i < buf->nr_pages; i++) |
256 | __free_page(buf->pages[i]); | 265 | __free_page(buf->pages[i]); |
257 | kfree(buf->pages); | 266 | kfree(buf->pages); |
258 | } else | 267 | } else |
268 | #endif | ||
259 | vfree(buf->data); | 269 | vfree(buf->data); |
260 | kfree(buf); | 270 | kfree(buf); |
261 | } | 271 | } |
@@ -357,6 +367,19 @@ static bool fw_get_filesystem_firmware(struct device *device, | |||
357 | return success; | 367 | return success; |
358 | } | 368 | } |
359 | 369 | ||
370 | /* firmware holds the ownership of pages */ | ||
371 | static void firmware_free_data(const struct firmware *fw) | ||
372 | { | ||
373 | /* Loaded directly? */ | ||
374 | if (!fw->priv) { | ||
375 | vfree(fw->data); | ||
376 | return; | ||
377 | } | ||
378 | fw_free_buf(fw->priv); | ||
379 | } | ||
380 | |||
381 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
382 | |||
360 | static struct firmware_priv *to_firmware_priv(struct device *dev) | 383 | static struct firmware_priv *to_firmware_priv(struct device *dev) |
361 | { | 384 | { |
362 | return container_of(dev, struct firmware_priv, dev); | 385 | return container_of(dev, struct firmware_priv, dev); |
@@ -446,17 +469,6 @@ static ssize_t firmware_loading_show(struct device *dev, | |||
446 | return sprintf(buf, "%d\n", loading); | 469 | return sprintf(buf, "%d\n", loading); |
447 | } | 470 | } |
448 | 471 | ||
449 | /* firmware holds the ownership of pages */ | ||
450 | static void firmware_free_data(const struct firmware *fw) | ||
451 | { | ||
452 | /* Loaded directly? */ | ||
453 | if (!fw->priv) { | ||
454 | vfree(fw->data); | ||
455 | return; | ||
456 | } | ||
457 | fw_free_buf(fw->priv); | ||
458 | } | ||
459 | |||
460 | /* Some architectures don't have PAGE_KERNEL_RO */ | 472 | /* Some architectures don't have PAGE_KERNEL_RO */ |
461 | #ifndef PAGE_KERNEL_RO | 473 | #ifndef PAGE_KERNEL_RO |
462 | #define PAGE_KERNEL_RO PAGE_KERNEL | 474 | #define PAGE_KERNEL_RO PAGE_KERNEL |
@@ -737,12 +749,15 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, | |||
737 | exit: | 749 | exit: |
738 | return fw_priv; | 750 | return fw_priv; |
739 | } | 751 | } |
752 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
740 | 753 | ||
741 | /* store the pages buffer info firmware from buf */ | 754 | /* store the pages buffer info firmware from buf */ |
742 | static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) | 755 | static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) |
743 | { | 756 | { |
744 | fw->priv = buf; | 757 | fw->priv = buf; |
758 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
745 | fw->pages = buf->pages; | 759 | fw->pages = buf->pages; |
760 | #endif | ||
746 | fw->size = buf->size; | 761 | fw->size = buf->size; |
747 | fw->data = buf->data; | 762 | fw->data = buf->data; |
748 | 763 | ||
@@ -906,6 +921,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device) | |||
906 | return 0; | 921 | return 0; |
907 | } | 922 | } |
908 | 923 | ||
924 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
909 | /* load a firmware via user helper */ | 925 | /* load a firmware via user helper */ |
910 | static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, | 926 | static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, |
911 | long timeout) | 927 | long timeout) |
@@ -978,6 +994,15 @@ static int fw_load_from_user_helper(struct firmware *firmware, | |||
978 | fw_priv->buf = firmware->priv; | 994 | fw_priv->buf = firmware->priv; |
979 | return _request_firmware_load(fw_priv, uevent, timeout); | 995 | return _request_firmware_load(fw_priv, uevent, timeout); |
980 | } | 996 | } |
997 | #else /* CONFIG_FW_LOADER_USER_HELPER */ | ||
998 | static inline int | ||
999 | fw_load_from_user_helper(struct firmware *firmware, const char *name, | ||
1000 | struct device *device, bool uevent, bool nowait, | ||
1001 | long timeout) | ||
1002 | { | ||
1003 | return -ENOENT; | ||
1004 | } | ||
1005 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | ||
981 | 1006 | ||
982 | /* called from request_firmware() and request_firmware_work_func() */ | 1007 | /* called from request_firmware() and request_firmware_work_func() */ |
983 | static int | 1008 | static int |
@@ -1495,7 +1520,11 @@ static void __init fw_cache_init(void) | |||
1495 | static int __init firmware_class_init(void) | 1520 | static int __init firmware_class_init(void) |
1496 | { | 1521 | { |
1497 | fw_cache_init(); | 1522 | fw_cache_init(); |
1523 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
1498 | return class_register(&firmware_class); | 1524 | return class_register(&firmware_class); |
1525 | #else | ||
1526 | return 0; | ||
1527 | #endif | ||
1499 | } | 1528 | } |
1500 | 1529 | ||
1501 | static void __exit firmware_class_exit(void) | 1530 | static void __exit firmware_class_exit(void) |
@@ -1504,7 +1533,9 @@ static void __exit firmware_class_exit(void) | |||
1504 | unregister_syscore_ops(&fw_syscore_ops); | 1533 | unregister_syscore_ops(&fw_syscore_ops); |
1505 | unregister_pm_notifier(&fw_cache.pm_notify); | 1534 | unregister_pm_notifier(&fw_cache.pm_notify); |
1506 | #endif | 1535 | #endif |
1536 | #ifdef CONFIG_FW_LOADER_USER_HELPER | ||
1507 | class_unregister(&firmware_class); | 1537 | class_unregister(&firmware_class); |
1538 | #endif | ||
1508 | } | 1539 | } |
1509 | 1540 | ||
1510 | fs_initcall(firmware_class_init); | 1541 | fs_initcall(firmware_class_init); |