Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware: Factor out the paged buffer handling code

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>

authored by

Takashi Iwai and committed by
Greg Kroah-Hartman
5342e709 3aa69801

+63 -54
+7 -54
drivers/base/firmware_loader/fallback.c
··· 219 219 return sprintf(buf, "%d\n", loading); 220 220 } 221 221 222 - /* one pages buffer should be mapped/unmapped only once */ 223 - static int map_fw_priv_pages(struct fw_priv *fw_priv) 224 - { 225 - if (!fw_priv->pages) 226 - return 0; 227 - 228 - vunmap(fw_priv->data); 229 - fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, 230 - PAGE_KERNEL_RO); 231 - if (!fw_priv->data) 232 - return -ENOMEM; 233 - 234 - /* page table is no longer needed after mapping, let's free */ 235 - kvfree(fw_priv->pages); 236 - fw_priv->pages = NULL; 237 - 238 - return 0; 239 - } 240 - 241 222 /** 242 223 * firmware_loading_store() - set value in the 'loading' control file 243 224 * @dev: device pointer ··· 264 283 * see the mapped 'buf->data' once the loading 265 284 * is completed. 266 285 * */ 267 - rc = map_fw_priv_pages(fw_priv); 286 + rc = fw_map_paged_buf(fw_priv); 268 287 if (rc) 269 288 dev_err(dev, "%s: map pages failed\n", 270 289 __func__); ··· 369 388 370 389 static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) 371 390 { 372 - struct fw_priv *fw_priv= fw_sysfs->fw_priv; 373 - int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT; 391 + int err; 374 392 375 - /* If the array of pages is too small, grow it... */ 376 - if (fw_priv->page_array_size < pages_needed) { 377 - int new_array_size = max(pages_needed, 378 - fw_priv->page_array_size * 2); 379 - struct page **new_pages; 380 - 381 - new_pages = kvmalloc_array(new_array_size, sizeof(void *), 382 - GFP_KERNEL); 383 - if (!new_pages) { 384 - fw_load_abort(fw_sysfs); 385 - return -ENOMEM; 386 - } 387 - memcpy(new_pages, fw_priv->pages, 388 - fw_priv->page_array_size * sizeof(void *)); 389 - memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * 390 - (new_array_size - fw_priv->page_array_size)); 391 - kvfree(fw_priv->pages); 392 - fw_priv->pages = new_pages; 393 - fw_priv->page_array_size = new_array_size; 394 - } 395 - 396 - while (fw_priv->nr_pages < pages_needed) { 397 - fw_priv->pages[fw_priv->nr_pages] = 398 - alloc_page(GFP_KERNEL | __GFP_HIGHMEM); 399 - 400 - if (!fw_priv->pages[fw_priv->nr_pages]) { 401 - fw_load_abort(fw_sysfs); 402 - return -ENOMEM; 403 - } 404 - fw_priv->nr_pages++; 405 - } 406 - return 0; 393 + err = fw_grow_paged_buf(fw_sysfs->fw_priv, 394 + PAGE_ALIGN(min_size) >> PAGE_SHIFT); 395 + if (err) 396 + fw_load_abort(fw_sysfs); 397 + return err; 407 398 } 408 399 409 400 /**
+4
drivers/base/firmware_loader/firmware.h
··· 135 135 136 136 #ifdef CONFIG_FW_LOADER_USER_HELPER 137 137 void fw_free_paged_buf(struct fw_priv *fw_priv); 138 + int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed); 139 + int fw_map_paged_buf(struct fw_priv *fw_priv); 138 140 #else 139 141 static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {} 142 + int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; } 143 + int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; } 140 144 #endif 141 145 142 146 #endif /* __FIRMWARE_LOADER_H */
+52
drivers/base/firmware_loader/main.c
··· 281 281 fw_priv->page_array_size = 0; 282 282 fw_priv->nr_pages = 0; 283 283 } 284 + 285 + int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) 286 + { 287 + /* If the array of pages is too small, grow it */ 288 + if (fw_priv->page_array_size < pages_needed) { 289 + int new_array_size = max(pages_needed, 290 + fw_priv->page_array_size * 2); 291 + struct page **new_pages; 292 + 293 + new_pages = kvmalloc_array(new_array_size, sizeof(void *), 294 + GFP_KERNEL); 295 + if (!new_pages) 296 + return -ENOMEM; 297 + memcpy(new_pages, fw_priv->pages, 298 + fw_priv->page_array_size * sizeof(void *)); 299 + memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * 300 + (new_array_size - fw_priv->page_array_size)); 301 + kvfree(fw_priv->pages); 302 + fw_priv->pages = new_pages; 303 + fw_priv->page_array_size = new_array_size; 304 + } 305 + 306 + while (fw_priv->nr_pages < pages_needed) { 307 + fw_priv->pages[fw_priv->nr_pages] = 308 + alloc_page(GFP_KERNEL | __GFP_HIGHMEM); 309 + 310 + if (!fw_priv->pages[fw_priv->nr_pages]) 311 + return -ENOMEM; 312 + fw_priv->nr_pages++; 313 + } 314 + 315 + return 0; 316 + } 317 + 318 + int fw_map_paged_buf(struct fw_priv *fw_priv) 319 + { 320 + /* one pages buffer should be mapped/unmapped only once */ 321 + if (!fw_priv->pages) 322 + return 0; 323 + 324 + vunmap(fw_priv->data); 325 + fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, 326 + PAGE_KERNEL_RO); 327 + if (!fw_priv->data) 328 + return -ENOMEM; 329 + 330 + /* page table is no longer needed after mapping, let's free */ 331 + kvfree(fw_priv->pages); 332 + fw_priv->pages = NULL; 333 + 334 + return 0; 335 + } 284 336 #endif 285 337 286 338 /* direct firmware loading support */