diff options
| -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); |
