extern struct builtin_fw __start_builtin_fw[];
 extern struct builtin_fw __end_builtin_fw[];
 
-static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+static bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
+                                   void *buf, size_t size)
 {
        struct builtin_fw *b_fw;
 
                if (strcmp(name, b_fw->name) == 0) {
                        fw->size = b_fw->size;
                        fw->data = b_fw->data;
+
+                       if (buf && fw->size <= size)
+                               memcpy(buf, fw->data, fw->size);
                        return true;
                }
        }
 
 #else /* Module case - no builtin firmware support */
 
-static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+static inline bool fw_get_builtin_firmware(struct firmware *fw,
+                                          const char *name, void *buf,
+                                          size_t size)
 {
        return false;
 }
        unsigned long status;
        void *data;
        size_t size;
+       size_t allocated_size;
 #ifdef CONFIG_FW_LOADER_USER_HELPER
        bool is_paged_buf;
        bool need_uevent;
 static struct firmware_cache fw_cache;
 
 static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
-                                             struct firmware_cache *fwc)
+                                             struct firmware_cache *fwc,
+                                             void *dbuf, size_t size)
 {
        struct firmware_buf *buf;
 
 
        kref_init(&buf->ref);
        buf->fwc = fwc;
+       buf->data = dbuf;
+       buf->allocated_size = size;
        init_completion(&buf->completion);
 #ifdef CONFIG_FW_LOADER_USER_HELPER
        INIT_LIST_HEAD(&buf->pending_list);
 
 static int fw_lookup_and_allocate_buf(const char *fw_name,
                                      struct firmware_cache *fwc,
-                                     struct firmware_buf **buf)
+                                     struct firmware_buf **buf, void *dbuf,
+                                     size_t size)
 {
        struct firmware_buf *tmp;
 
                *buf = tmp;
                return 1;
        }
-       tmp = __allocate_fw_buf(fw_name, fwc);
+       tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
        if (tmp)
                list_add(&tmp->list, &fwc->head);
        spin_unlock(&fwc->lock);
                vfree(buf->pages);
        } else
 #endif
+       if (!buf->allocated_size)
                vfree(buf->data);
        kfree_const(buf->fw_id);
        kfree(buf);
        mutex_unlock(&fw_lock);
 }
 
-static int fw_get_filesystem_firmware(struct device *device,
-                                      struct firmware_buf *buf)
+static int
+fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
 {
        loff_t size;
        int i, len;
        int rc = -ENOENT;
        char *path;
+       enum kernel_read_file_id id = READING_FIRMWARE;
+       size_t msize = INT_MAX;
+
+       /* Already populated data member means we're loading into a buffer */
+       if (buf->data) {
+               id = READING_FIRMWARE_PREALLOC_BUFFER;
+               msize = buf->allocated_size;
+       }
 
        path = __getname();
        if (!path)
                }
 
                buf->size = 0;
-               rc = kernel_read_file_from_path(path, &buf->data, &size,
-                                               INT_MAX, READING_FIRMWARE);
+               rc = kernel_read_file_from_path(path, &buf->data, &size, msize,
+                                               id);
                if (rc) {
                        if (rc == -ENOENT)
                                dev_dbg(device, "loading %s failed with error %d\n",
 
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
 
+static void firmware_rw_buf(struct firmware_buf *buf, char *buffer,
+                          loff_t offset, size_t count, bool read)
+{
+       if (read)
+               memcpy(buffer, buf->data + offset, count);
+       else
+               memcpy(buf->data + offset, buffer, count);
+}
+
 static void firmware_rw(struct firmware_buf *buf, char *buffer,
                        loff_t offset, size_t count, bool read)
 {
 
        ret_count = count;
 
-       firmware_rw(buf, buffer, offset, count, true);
+       if (buf->data)
+               firmware_rw_buf(buf, buffer, offset, count, true);
+       else
+               firmware_rw(buf, buffer, offset, count, true);
 
 out:
        mutex_unlock(&fw_lock);
                goto out;
        }
 
-       retval = fw_realloc_buffer(fw_priv, offset + count);
-       if (retval)
-               goto out;
+       if (buf->data) {
+               if (offset + count > buf->allocated_size) {
+                       retval = -ENOMEM;
+                       goto out;
+               }
+               firmware_rw_buf(buf, buffer, offset, count, false);
+               retval = count;
+       } else {
+               retval = fw_realloc_buffer(fw_priv, offset + count);
+               if (retval)
+                       goto out;
 
-       retval = count;
-       firmware_rw(buf, buffer, offset, count, false);
+               retval = count;
+               firmware_rw(buf, buffer, offset, count, false);
+       }
 
        buf->size = max_t(size_t, offset + count, buf->size);
 out:
        struct firmware_buf *buf = fw_priv->buf;
 
        /* fall back on userspace loading */
-       buf->is_paged_buf = true;
+       if (!buf->data)
+               buf->is_paged_buf = true;
 
        dev_set_uevent_suppress(f_dev, true);
 
 
        if (is_fw_load_aborted(buf))
                retval = -EAGAIN;
-       else if (!buf->data)
+       else if (buf->is_paged_buf && !buf->data)
                retval = -ENOMEM;
 
        device_del(f_dev);
  */
 static int
 _request_firmware_prepare(struct firmware **firmware_p, const char *name,
-                         struct device *device)
+                         struct device *device, void *dbuf, size_t size)
 {
        struct firmware *firmware;
        struct firmware_buf *buf;
                return -ENOMEM;
        }
 
-       if (fw_get_builtin_firmware(firmware, name)) {
+       if (fw_get_builtin_firmware(firmware, name, dbuf, size)) {
                dev_dbg(device, "using built-in %s\n", name);
                return 0; /* assigned */
        }
 
-       ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
+       ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
 
        /*
         * bind with 'buf' now to avoid warning in failure path
 /* called from request_firmware() and request_firmware_work_func() */
 static int
 _request_firmware(const struct firmware **firmware_p, const char *name,
-                 struct device *device, unsigned int opt_flags)
+                 struct device *device, void *buf, size_t size,
+                 unsigned int opt_flags)
 {
        struct firmware *fw = NULL;
        long timeout;
                goto out;
        }
 
-       ret = _request_firmware_prepare(&fw, name, device);
+       ret = _request_firmware_prepare(&fw, name, device, buf, size);
        if (ret <= 0) /* error or already assigned */
                goto out;
 
 
        /* Need to pin this module until return */
        __module_get(THIS_MODULE);
-       ret = _request_firmware(firmware_p, name, device,
+       ret = _request_firmware(firmware_p, name, device, NULL, 0,
                                FW_OPT_UEVENT | FW_OPT_FALLBACK);
        module_put(THIS_MODULE);
        return ret;
        int ret;
 
        __module_get(THIS_MODULE);
-       ret = _request_firmware(firmware_p, name, device,
+       ret = _request_firmware(firmware_p, name, device, NULL, 0,
                                FW_OPT_UEVENT | FW_OPT_NO_WARN);
        module_put(THIS_MODULE);
        return ret;
 }
 EXPORT_SYMBOL_GPL(request_firmware_direct);
 
+/**
+ * request_firmware_into_buf - load firmware into a previously allocated buffer
+ * @firmware_p: pointer to firmware image
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded and DMA region allocated
+ * @buf: address of buffer to load firmware into
+ * @size: size of buffer
+ *
+ * This function works pretty much like request_firmware(), but it doesn't
+ * allocate a buffer to hold the firmware data. Instead, the firmware
+ * is loaded directly into the buffer pointed to by @buf and the @firmware_p
+ * data member is pointed at @buf.
+ *
+ * This function doesn't cache firmware either.
+ */
+int
+request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
+                         struct device *device, void *buf, size_t size)
+{
+       int ret;
+
+       __module_get(THIS_MODULE);
+       ret = _request_firmware(firmware_p, name, device, buf, size,
+                               FW_OPT_UEVENT | FW_OPT_FALLBACK |
+                               FW_OPT_NOCACHE);
+       module_put(THIS_MODULE);
+       return ret;
+}
+EXPORT_SYMBOL(request_firmware_into_buf);
+
 /**
  * release_firmware: - release the resource associated with a firmware image
  * @fw: firmware resource to release
 
        fw_work = container_of(work, struct firmware_work, work);
 
-       _request_firmware(&fw, fw_work->name, fw_work->device,
+       _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0,
                          fw_work->opt_flags);
        fw_work->cont(fw, fw_work->context);
        put_device(fw_work->device); /* taken in request_firmware_nowait() */
 
        pr_debug("%s: %s\n", __func__, fw_name);
 
-       if (fw_get_builtin_firmware(&fw, fw_name))
+       if (fw_get_builtin_firmware(&fw, fw_name, NULL, 0))
                return 0;
 
        buf = fw_lookup_buf(fw_name);