OSDN Git Service

firmware_class: Provide infrastructure to make fw caching optional
authorVikram Mulukutla <markivx@codeaurora.org>
Mon, 5 Aug 2013 18:17:29 +0000 (11:17 -0700)
committerDavid Keitel <dkeitel@codeaurora.org>
Tue, 22 Mar 2016 18:07:34 +0000 (11:07 -0700)
Some low memory systems with complex peripherals cannot
afford to have the relatively large firmware images taking
up valuable memory during suspend and resume. Change the
internal implementation of firmware_class to disallow
caching based on a configurable option. In the near future,
variants of request_firmware will take advantage of this
configurability.

Change-Id: I44be7ce3b308b642fb018086def99fcb800a1109
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
[joshc: reworked to use opt_flags instead of 'nocache' bool in fw_desc]
Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
[vmulukut: adjusted for upstream additions to opt_flags]
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
drivers/base/firmware_class.c

index abb9396..a389eb5 100644 (file)
@@ -111,6 +111,7 @@ static inline long firmware_loading_timeout(void)
 #define FW_OPT_FALLBACK                0
 #endif
 #define FW_OPT_NO_WARN (1U << 3)
+#define FW_OPT_NOCACHE (1U << 4)
 
 struct firmware_cache {
        /* firmware_buf instance will be added into the below list */
@@ -1072,6 +1073,14 @@ _request_firmware_prepare(struct firmware **firmware_p, struct fw_desc *desc)
                return 0; /* assigned */
        }
 
+       if (desc->opt_flags & FW_OPT_NOCACHE) {
+               buf = __allocate_fw_buf(desc->name, NULL);
+               if (!buf)
+                       return -ENOMEM;
+               firmware->priv = buf;
+               return 1;
+       }
+
        ret = fw_lookup_and_allocate_buf(desc->name, &fw_cache, &buf);
 
        /*
@@ -1111,15 +1120,19 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
         * device may has been deleted already, but the problem
         * should be fixed in devres or driver core.
         */
-       /* don't cache firmware handled without uevent */
-       if (device && (opt_flags & FW_OPT_UEVENT))
+       /* don't cache firmware handled without uevent, or when explicitly
+        * disabled
+        */
+       if (device && (opt_flags & FW_OPT_UEVENT)
+           && !(opt_flags & FW_OPT_NOCACHE))
                fw_add_devm_name(device, buf->fw_id);
 
        /*
         * After caching firmware image is started, let it piggyback
         * on request firmware.
         */
-       if (buf->fwc->state == FW_LOADER_START_CACHE) {
+       if (!(opt_flags & FW_OPT_NOCACHE)
+           && (buf->fwc->state == FW_LOADER_START_CACHE)) {
                if (fw_cache_piggyback_on_request(buf->fw_id))
                        kref_get(&buf->ref);
        }
@@ -1299,7 +1312,8 @@ int
 _request_firmware_nowait(
        struct module *module, bool uevent,
        const char *name, struct device *device, gfp_t gfp, void *context,
-       void (*cont)(const struct firmware *fw, void *context))
+       void (*cont)(const struct firmware *fw, void *context),
+       bool nocache)
 {
        struct fw_desc *desc;
 
@@ -1318,6 +1332,8 @@ _request_firmware_nowait(
                desc->opt_flags |= FW_OPT_UEVENT;
        else
                desc->opt_flags |= FW_OPT_USERHELPER;
+       if (nocache)
+               desc->opt_flags |= FW_OPT_NOCACHE;
 
        if (!try_module_get(module)) {
                kfree(desc);
@@ -1360,7 +1376,7 @@ request_firmware_nowait(
        void (*cont)(const struct firmware *fw, void *context))
 {
        return _request_firmware_nowait(module, uevent, name, device, gfp,
-                                       context, cont);
+                                       context, cont, false);
 }
 EXPORT_SYMBOL(request_firmware_nowait);