firmware: Factor out the paged buffer handling code
authorTakashi Iwai <tiwai@suse.de>
Tue, 11 Jun 2019 12:26:24 +0000 (14:26 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Jun 2019 07:11:21 +0000 (09:11 +0200)
This is merely a preparation for the upcoming compressed firmware
support and no functional changes.  It moves the code to handle the
paged buffer allocation and mapping out of fallback.c into the main
code, so that they can be used commonly.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/firmware_loader/fallback.c
drivers/base/firmware_loader/firmware.h
drivers/base/firmware_loader/main.c

index 29becea1910dfb781e063c7fe15b3c3fcd2d26b7..62ee90b4db56e9ae30f5f17d365db1b2af67cd88 100644 (file)
@@ -219,25 +219,6 @@ static ssize_t firmware_loading_show(struct device *dev,
        return sprintf(buf, "%d\n", loading);
 }
 
-/* one pages buffer should be mapped/unmapped only once */
-static int map_fw_priv_pages(struct fw_priv *fw_priv)
-{
-       if (!fw_priv->pages)
-               return 0;
-
-       vunmap(fw_priv->data);
-       fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
-                            PAGE_KERNEL_RO);
-       if (!fw_priv->data)
-               return -ENOMEM;
-
-       /* page table is no longer needed after mapping, let's free */
-       kvfree(fw_priv->pages);
-       fw_priv->pages = NULL;
-
-       return 0;
-}
-
 /**
  * firmware_loading_store() - set value in the 'loading' control file
  * @dev: device pointer
@@ -283,7 +264,7 @@ static ssize_t firmware_loading_store(struct device *dev,
                         * see the mapped 'buf->data' once the loading
                         * is completed.
                         * */
-                       rc = map_fw_priv_pages(fw_priv);
+                       rc = fw_map_paged_buf(fw_priv);
                        if (rc)
                                dev_err(dev, "%s: map pages failed\n",
                                        __func__);
@@ -388,41 +369,13 @@ out:
 
 static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size)
 {
-       struct fw_priv *fw_priv= fw_sysfs->fw_priv;
-       int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT;
-
-       /* If the array of pages is too small, grow it... */
-       if (fw_priv->page_array_size < pages_needed) {
-               int new_array_size = max(pages_needed,
-                                        fw_priv->page_array_size * 2);
-               struct page **new_pages;
+       int err;
 
-               new_pages = kvmalloc_array(new_array_size, sizeof(void *),
-                                          GFP_KERNEL);
-               if (!new_pages) {
-                       fw_load_abort(fw_sysfs);
-                       return -ENOMEM;
-               }
-               memcpy(new_pages, fw_priv->pages,
-                      fw_priv->page_array_size * sizeof(void *));
-               memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
-                      (new_array_size - fw_priv->page_array_size));
-               kvfree(fw_priv->pages);
-               fw_priv->pages = new_pages;
-               fw_priv->page_array_size = new_array_size;
-       }
-
-       while (fw_priv->nr_pages < pages_needed) {
-               fw_priv->pages[fw_priv->nr_pages] =
-                       alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-
-               if (!fw_priv->pages[fw_priv->nr_pages]) {
-                       fw_load_abort(fw_sysfs);
-                       return -ENOMEM;
-               }
-               fw_priv->nr_pages++;
-       }
-       return 0;
+       err = fw_grow_paged_buf(fw_sysfs->fw_priv,
+                               PAGE_ALIGN(min_size) >> PAGE_SHIFT);
+       if (err)
+               fw_load_abort(fw_sysfs);
+       return err;
 }
 
 /**
index d20d4e7f9e71c57924aaeed5b529ed66307361d9..35f4e58b2d987161809f91292f135070d2fe32d6 100644 (file)
@@ -135,8 +135,12 @@ int assign_fw(struct firmware *fw, struct device *device,
 
 #ifdef CONFIG_FW_LOADER_USER_HELPER
 void fw_free_paged_buf(struct fw_priv *fw_priv);
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
+int fw_map_paged_buf(struct fw_priv *fw_priv);
 #else
 static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
+int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
 #endif
 
 #endif /* __FIRMWARE_LOADER_H */
index 2e74a1b73dae866f8c8b7926b26628e867351c10..7e12732f470548a5b6c2384f9d90cd9ea704af8b 100644 (file)
@@ -281,6 +281,58 @@ void fw_free_paged_buf(struct fw_priv *fw_priv)
        fw_priv->page_array_size = 0;
        fw_priv->nr_pages = 0;
 }
+
+int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed)
+{
+       /* If the array of pages is too small, grow it */
+       if (fw_priv->page_array_size < pages_needed) {
+               int new_array_size = max(pages_needed,
+                                        fw_priv->page_array_size * 2);
+               struct page **new_pages;
+
+               new_pages = kvmalloc_array(new_array_size, sizeof(void *),
+                                          GFP_KERNEL);
+               if (!new_pages)
+                       return -ENOMEM;
+               memcpy(new_pages, fw_priv->pages,
+                      fw_priv->page_array_size * sizeof(void *));
+               memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
+                      (new_array_size - fw_priv->page_array_size));
+               kvfree(fw_priv->pages);
+               fw_priv->pages = new_pages;
+               fw_priv->page_array_size = new_array_size;
+       }
+
+       while (fw_priv->nr_pages < pages_needed) {
+               fw_priv->pages[fw_priv->nr_pages] =
+                       alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+
+               if (!fw_priv->pages[fw_priv->nr_pages])
+                       return -ENOMEM;
+               fw_priv->nr_pages++;
+       }
+
+       return 0;
+}
+
+int fw_map_paged_buf(struct fw_priv *fw_priv)
+{
+       /* one pages buffer should be mapped/unmapped only once */
+       if (!fw_priv->pages)
+               return 0;
+
+       vunmap(fw_priv->data);
+       fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
+                            PAGE_KERNEL_RO);
+       if (!fw_priv->data)
+               return -ENOMEM;
+
+       /* page table is no longer needed after mapping, let's free */
+       kvfree(fw_priv->pages);
+       fw_priv->pages = NULL;
+
+       return 0;
+}
 #endif
 
 /* direct firmware loading support */