| .. | .. |
|---|
| 4 | 4 | * |
|---|
| 5 | 5 | * Copyright (c) 2003 Manuel Estrada Sainz |
|---|
| 6 | 6 | * |
|---|
| 7 | | - * Please see Documentation/firmware_class/ for more information. |
|---|
| 7 | + * Please see Documentation/driver-api/firmware/ for more information. |
|---|
| 8 | 8 | * |
|---|
| 9 | 9 | */ |
|---|
| 10 | 10 | |
|---|
| .. | .. |
|---|
| 12 | 12 | |
|---|
| 13 | 13 | #include <linux/capability.h> |
|---|
| 14 | 14 | #include <linux/device.h> |
|---|
| 15 | +#include <linux/kernel_read_file.h> |
|---|
| 15 | 16 | #include <linux/module.h> |
|---|
| 16 | 17 | #include <linux/init.h> |
|---|
| 17 | 18 | #include <linux/timer.h> |
|---|
| .. | .. |
|---|
| 33 | 34 | #include <linux/syscore_ops.h> |
|---|
| 34 | 35 | #include <linux/reboot.h> |
|---|
| 35 | 36 | #include <linux/security.h> |
|---|
| 37 | +#include <linux/xz.h> |
|---|
| 36 | 38 | |
|---|
| 37 | 39 | #include <generated/utsrelease.h> |
|---|
| 38 | 40 | |
|---|
| .. | .. |
|---|
| 89 | 91 | DEFINE_MUTEX(fw_lock); |
|---|
| 90 | 92 | |
|---|
| 91 | 93 | static struct firmware_cache fw_cache; |
|---|
| 94 | +bool fw_load_abort_all; |
|---|
| 92 | 95 | |
|---|
| 93 | 96 | /* Builtin firmware support */ |
|---|
| 94 | 97 | |
|---|
| .. | .. |
|---|
| 163 | 166 | return __fw_state_wait_common(fw_priv, MAX_SCHEDULE_TIMEOUT); |
|---|
| 164 | 167 | } |
|---|
| 165 | 168 | |
|---|
| 166 | | -static int fw_cache_piggyback_on_request(const char *name); |
|---|
| 169 | +static void fw_cache_piggyback_on_request(struct fw_priv *fw_priv); |
|---|
| 167 | 170 | |
|---|
| 168 | 171 | static struct fw_priv *__allocate_fw_priv(const char *fw_name, |
|---|
| 169 | 172 | struct firmware_cache *fwc, |
|---|
| 170 | | - void *dbuf, size_t size) |
|---|
| 173 | + void *dbuf, |
|---|
| 174 | + size_t size, |
|---|
| 175 | + size_t offset, |
|---|
| 176 | + u32 opt_flags) |
|---|
| 171 | 177 | { |
|---|
| 172 | 178 | struct fw_priv *fw_priv; |
|---|
| 179 | + |
|---|
| 180 | + /* For a partial read, the buffer must be preallocated. */ |
|---|
| 181 | + if ((opt_flags & FW_OPT_PARTIAL) && !dbuf) |
|---|
| 182 | + return NULL; |
|---|
| 183 | + |
|---|
| 184 | + /* Only partial reads are allowed to use an offset. */ |
|---|
| 185 | + if (offset != 0 && !(opt_flags & FW_OPT_PARTIAL)) |
|---|
| 186 | + return NULL; |
|---|
| 173 | 187 | |
|---|
| 174 | 188 | fw_priv = kzalloc(sizeof(*fw_priv), GFP_ATOMIC); |
|---|
| 175 | 189 | if (!fw_priv) |
|---|
| .. | .. |
|---|
| 185 | 199 | fw_priv->fwc = fwc; |
|---|
| 186 | 200 | fw_priv->data = dbuf; |
|---|
| 187 | 201 | fw_priv->allocated_size = size; |
|---|
| 202 | + fw_priv->offset = offset; |
|---|
| 203 | + fw_priv->opt_flags = opt_flags; |
|---|
| 188 | 204 | fw_state_init(fw_priv); |
|---|
| 189 | 205 | #ifdef CONFIG_FW_LOADER_USER_HELPER |
|---|
| 190 | 206 | INIT_LIST_HEAD(&fw_priv->pending_list); |
|---|
| .. | .. |
|---|
| 209 | 225 | /* Returns 1 for batching firmware requests with the same name */ |
|---|
| 210 | 226 | static int alloc_lookup_fw_priv(const char *fw_name, |
|---|
| 211 | 227 | struct firmware_cache *fwc, |
|---|
| 212 | | - struct fw_priv **fw_priv, void *dbuf, |
|---|
| 213 | | - size_t size, enum fw_opt opt_flags) |
|---|
| 228 | + struct fw_priv **fw_priv, |
|---|
| 229 | + void *dbuf, |
|---|
| 230 | + size_t size, |
|---|
| 231 | + size_t offset, |
|---|
| 232 | + u32 opt_flags) |
|---|
| 214 | 233 | { |
|---|
| 215 | 234 | struct fw_priv *tmp; |
|---|
| 216 | 235 | |
|---|
| 217 | 236 | spin_lock(&fwc->lock); |
|---|
| 218 | | - if (!(opt_flags & FW_OPT_NOCACHE)) { |
|---|
| 237 | + /* |
|---|
| 238 | + * Do not merge requests that are marked to be non-cached or |
|---|
| 239 | + * are performing partial reads. |
|---|
| 240 | + */ |
|---|
| 241 | + if (!(opt_flags & (FW_OPT_NOCACHE | FW_OPT_PARTIAL))) { |
|---|
| 219 | 242 | tmp = __lookup_fw_priv(fw_name); |
|---|
| 220 | 243 | if (tmp) { |
|---|
| 221 | 244 | kref_get(&tmp->ref); |
|---|
| .. | .. |
|---|
| 226 | 249 | } |
|---|
| 227 | 250 | } |
|---|
| 228 | 251 | |
|---|
| 229 | | - tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size); |
|---|
| 252 | + tmp = __allocate_fw_priv(fw_name, fwc, dbuf, size, offset, opt_flags); |
|---|
| 230 | 253 | if (tmp) { |
|---|
| 231 | 254 | INIT_LIST_HEAD(&tmp->list); |
|---|
| 232 | 255 | if (!(opt_flags & FW_OPT_NOCACHE)) |
|---|
| .. | .. |
|---|
| 252 | 275 | list_del(&fw_priv->list); |
|---|
| 253 | 276 | spin_unlock(&fwc->lock); |
|---|
| 254 | 277 | |
|---|
| 255 | | -#ifdef CONFIG_FW_LOADER_USER_HELPER |
|---|
| 256 | | - if (fw_priv->is_paged_buf) { |
|---|
| 257 | | - int i; |
|---|
| 258 | | - vunmap(fw_priv->data); |
|---|
| 259 | | - for (i = 0; i < fw_priv->nr_pages; i++) |
|---|
| 260 | | - __free_page(fw_priv->pages[i]); |
|---|
| 261 | | - vfree(fw_priv->pages); |
|---|
| 262 | | - } else |
|---|
| 263 | | -#endif |
|---|
| 264 | | - if (!fw_priv->allocated_size) |
|---|
| 278 | + if (fw_is_paged_buf(fw_priv)) |
|---|
| 279 | + fw_free_paged_buf(fw_priv); |
|---|
| 280 | + else if (!fw_priv->allocated_size) |
|---|
| 265 | 281 | vfree(fw_priv->data); |
|---|
| 282 | + |
|---|
| 266 | 283 | kfree_const(fw_priv->fw_name); |
|---|
| 267 | 284 | kfree(fw_priv); |
|---|
| 268 | 285 | } |
|---|
| .. | .. |
|---|
| 274 | 291 | if (!kref_put(&fw_priv->ref, __free_fw_priv)) |
|---|
| 275 | 292 | spin_unlock(&fwc->lock); |
|---|
| 276 | 293 | } |
|---|
| 294 | + |
|---|
| 295 | +#ifdef CONFIG_FW_LOADER_PAGED_BUF |
|---|
| 296 | +bool fw_is_paged_buf(struct fw_priv *fw_priv) |
|---|
| 297 | +{ |
|---|
| 298 | + return fw_priv->is_paged_buf; |
|---|
| 299 | +} |
|---|
| 300 | + |
|---|
| 301 | +void fw_free_paged_buf(struct fw_priv *fw_priv) |
|---|
| 302 | +{ |
|---|
| 303 | + int i; |
|---|
| 304 | + |
|---|
| 305 | + if (!fw_priv->pages) |
|---|
| 306 | + return; |
|---|
| 307 | + |
|---|
| 308 | + vunmap(fw_priv->data); |
|---|
| 309 | + |
|---|
| 310 | + for (i = 0; i < fw_priv->nr_pages; i++) |
|---|
| 311 | + __free_page(fw_priv->pages[i]); |
|---|
| 312 | + kvfree(fw_priv->pages); |
|---|
| 313 | + fw_priv->pages = NULL; |
|---|
| 314 | + fw_priv->page_array_size = 0; |
|---|
| 315 | + fw_priv->nr_pages = 0; |
|---|
| 316 | +} |
|---|
| 317 | + |
|---|
| 318 | +int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) |
|---|
| 319 | +{ |
|---|
| 320 | + /* If the array of pages is too small, grow it */ |
|---|
| 321 | + if (fw_priv->page_array_size < pages_needed) { |
|---|
| 322 | + int new_array_size = max(pages_needed, |
|---|
| 323 | + fw_priv->page_array_size * 2); |
|---|
| 324 | + struct page **new_pages; |
|---|
| 325 | + |
|---|
| 326 | + new_pages = kvmalloc_array(new_array_size, sizeof(void *), |
|---|
| 327 | + GFP_KERNEL); |
|---|
| 328 | + if (!new_pages) |
|---|
| 329 | + return -ENOMEM; |
|---|
| 330 | + memcpy(new_pages, fw_priv->pages, |
|---|
| 331 | + fw_priv->page_array_size * sizeof(void *)); |
|---|
| 332 | + memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) * |
|---|
| 333 | + (new_array_size - fw_priv->page_array_size)); |
|---|
| 334 | + kvfree(fw_priv->pages); |
|---|
| 335 | + fw_priv->pages = new_pages; |
|---|
| 336 | + fw_priv->page_array_size = new_array_size; |
|---|
| 337 | + } |
|---|
| 338 | + |
|---|
| 339 | + while (fw_priv->nr_pages < pages_needed) { |
|---|
| 340 | + fw_priv->pages[fw_priv->nr_pages] = |
|---|
| 341 | + alloc_page(GFP_KERNEL | __GFP_HIGHMEM); |
|---|
| 342 | + |
|---|
| 343 | + if (!fw_priv->pages[fw_priv->nr_pages]) |
|---|
| 344 | + return -ENOMEM; |
|---|
| 345 | + fw_priv->nr_pages++; |
|---|
| 346 | + } |
|---|
| 347 | + |
|---|
| 348 | + return 0; |
|---|
| 349 | +} |
|---|
| 350 | + |
|---|
| 351 | +int fw_map_paged_buf(struct fw_priv *fw_priv) |
|---|
| 352 | +{ |
|---|
| 353 | + /* one pages buffer should be mapped/unmapped only once */ |
|---|
| 354 | + if (!fw_priv->pages) |
|---|
| 355 | + return 0; |
|---|
| 356 | + |
|---|
| 357 | + vunmap(fw_priv->data); |
|---|
| 358 | + fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0, |
|---|
| 359 | + PAGE_KERNEL_RO); |
|---|
| 360 | + if (!fw_priv->data) |
|---|
| 361 | + return -ENOMEM; |
|---|
| 362 | + |
|---|
| 363 | + return 0; |
|---|
| 364 | +} |
|---|
| 365 | +#endif |
|---|
| 366 | + |
|---|
| 367 | +/* |
|---|
| 368 | + * XZ-compressed firmware support |
|---|
| 369 | + */ |
|---|
| 370 | +#ifdef CONFIG_FW_LOADER_COMPRESS |
|---|
| 371 | +/* show an error and return the standard error code */ |
|---|
| 372 | +static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret) |
|---|
| 373 | +{ |
|---|
| 374 | + if (xz_ret != XZ_STREAM_END) { |
|---|
| 375 | + dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret); |
|---|
| 376 | + return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL; |
|---|
| 377 | + } |
|---|
| 378 | + return 0; |
|---|
| 379 | +} |
|---|
| 380 | + |
|---|
| 381 | +/* single-shot decompression onto the pre-allocated buffer */ |
|---|
| 382 | +static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv, |
|---|
| 383 | + size_t in_size, const void *in_buffer) |
|---|
| 384 | +{ |
|---|
| 385 | + struct xz_dec *xz_dec; |
|---|
| 386 | + struct xz_buf xz_buf; |
|---|
| 387 | + enum xz_ret xz_ret; |
|---|
| 388 | + |
|---|
| 389 | + xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1); |
|---|
| 390 | + if (!xz_dec) |
|---|
| 391 | + return -ENOMEM; |
|---|
| 392 | + |
|---|
| 393 | + xz_buf.in_size = in_size; |
|---|
| 394 | + xz_buf.in = in_buffer; |
|---|
| 395 | + xz_buf.in_pos = 0; |
|---|
| 396 | + xz_buf.out_size = fw_priv->allocated_size; |
|---|
| 397 | + xz_buf.out = fw_priv->data; |
|---|
| 398 | + xz_buf.out_pos = 0; |
|---|
| 399 | + |
|---|
| 400 | + xz_ret = xz_dec_run(xz_dec, &xz_buf); |
|---|
| 401 | + xz_dec_end(xz_dec); |
|---|
| 402 | + |
|---|
| 403 | + fw_priv->size = xz_buf.out_pos; |
|---|
| 404 | + return fw_decompress_xz_error(dev, xz_ret); |
|---|
| 405 | +} |
|---|
| 406 | + |
|---|
| 407 | +/* decompression on paged buffer and map it */ |
|---|
| 408 | +static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv, |
|---|
| 409 | + size_t in_size, const void *in_buffer) |
|---|
| 410 | +{ |
|---|
| 411 | + struct xz_dec *xz_dec; |
|---|
| 412 | + struct xz_buf xz_buf; |
|---|
| 413 | + enum xz_ret xz_ret; |
|---|
| 414 | + struct page *page; |
|---|
| 415 | + int err = 0; |
|---|
| 416 | + |
|---|
| 417 | + xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1); |
|---|
| 418 | + if (!xz_dec) |
|---|
| 419 | + return -ENOMEM; |
|---|
| 420 | + |
|---|
| 421 | + xz_buf.in_size = in_size; |
|---|
| 422 | + xz_buf.in = in_buffer; |
|---|
| 423 | + xz_buf.in_pos = 0; |
|---|
| 424 | + |
|---|
| 425 | + fw_priv->is_paged_buf = true; |
|---|
| 426 | + fw_priv->size = 0; |
|---|
| 427 | + do { |
|---|
| 428 | + if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) { |
|---|
| 429 | + err = -ENOMEM; |
|---|
| 430 | + goto out; |
|---|
| 431 | + } |
|---|
| 432 | + |
|---|
| 433 | + /* decompress onto the new allocated page */ |
|---|
| 434 | + page = fw_priv->pages[fw_priv->nr_pages - 1]; |
|---|
| 435 | + xz_buf.out = kmap(page); |
|---|
| 436 | + xz_buf.out_pos = 0; |
|---|
| 437 | + xz_buf.out_size = PAGE_SIZE; |
|---|
| 438 | + xz_ret = xz_dec_run(xz_dec, &xz_buf); |
|---|
| 439 | + kunmap(page); |
|---|
| 440 | + fw_priv->size += xz_buf.out_pos; |
|---|
| 441 | + /* partial decompression means either end or error */ |
|---|
| 442 | + if (xz_buf.out_pos != PAGE_SIZE) |
|---|
| 443 | + break; |
|---|
| 444 | + } while (xz_ret == XZ_OK); |
|---|
| 445 | + |
|---|
| 446 | + err = fw_decompress_xz_error(dev, xz_ret); |
|---|
| 447 | + if (!err) |
|---|
| 448 | + err = fw_map_paged_buf(fw_priv); |
|---|
| 449 | + |
|---|
| 450 | + out: |
|---|
| 451 | + xz_dec_end(xz_dec); |
|---|
| 452 | + return err; |
|---|
| 453 | +} |
|---|
| 454 | + |
|---|
| 455 | +static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv, |
|---|
| 456 | + size_t in_size, const void *in_buffer) |
|---|
| 457 | +{ |
|---|
| 458 | + /* if the buffer is pre-allocated, we can perform in single-shot mode */ |
|---|
| 459 | + if (fw_priv->data) |
|---|
| 460 | + return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer); |
|---|
| 461 | + else |
|---|
| 462 | + return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer); |
|---|
| 463 | +} |
|---|
| 464 | +#endif /* CONFIG_FW_LOADER_COMPRESS */ |
|---|
| 277 | 465 | |
|---|
| 278 | 466 | /* direct firmware loading support */ |
|---|
| 279 | 467 | static char fw_path_para[256]; |
|---|
| .. | .. |
|---|
| 294 | 482 | MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); |
|---|
| 295 | 483 | |
|---|
| 296 | 484 | static int |
|---|
| 297 | | -fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) |
|---|
| 485 | +fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, |
|---|
| 486 | + const char *suffix, |
|---|
| 487 | + int (*decompress)(struct device *dev, |
|---|
| 488 | + struct fw_priv *fw_priv, |
|---|
| 489 | + size_t in_size, |
|---|
| 490 | + const void *in_buffer)) |
|---|
| 298 | 491 | { |
|---|
| 299 | | - loff_t size; |
|---|
| 492 | + size_t size; |
|---|
| 300 | 493 | int i, len; |
|---|
| 301 | 494 | int rc = -ENOENT; |
|---|
| 302 | 495 | char *path; |
|---|
| 303 | | - enum kernel_read_file_id id = READING_FIRMWARE; |
|---|
| 304 | 496 | size_t msize = INT_MAX; |
|---|
| 497 | + void *buffer = NULL; |
|---|
| 305 | 498 | |
|---|
| 306 | 499 | /* Already populated data member means we're loading into a buffer */ |
|---|
| 307 | | - if (fw_priv->data) { |
|---|
| 308 | | - id = READING_FIRMWARE_PREALLOC_BUFFER; |
|---|
| 500 | + if (!decompress && fw_priv->data) { |
|---|
| 501 | + buffer = fw_priv->data; |
|---|
| 309 | 502 | msize = fw_priv->allocated_size; |
|---|
| 310 | 503 | } |
|---|
| 311 | 504 | |
|---|
| .. | .. |
|---|
| 314 | 507 | return -ENOMEM; |
|---|
| 315 | 508 | |
|---|
| 316 | 509 | for (i = 0; i < ARRAY_SIZE(fw_path); i++) { |
|---|
| 510 | + size_t file_size = 0; |
|---|
| 511 | + size_t *file_size_ptr = NULL; |
|---|
| 512 | + |
|---|
| 317 | 513 | /* skip the unset customized path */ |
|---|
| 318 | 514 | if (!fw_path[i][0]) |
|---|
| 319 | 515 | continue; |
|---|
| 320 | 516 | |
|---|
| 321 | | - len = snprintf(path, PATH_MAX, "%s/%s", |
|---|
| 322 | | - fw_path[i], fw_priv->fw_name); |
|---|
| 517 | + len = snprintf(path, PATH_MAX, "%s/%s%s", |
|---|
| 518 | + fw_path[i], fw_priv->fw_name, suffix); |
|---|
| 323 | 519 | if (len >= PATH_MAX) { |
|---|
| 324 | 520 | rc = -ENAMETOOLONG; |
|---|
| 325 | 521 | break; |
|---|
| 326 | 522 | } |
|---|
| 327 | 523 | |
|---|
| 328 | 524 | fw_priv->size = 0; |
|---|
| 329 | | - rc = kernel_read_file_from_path(path, &fw_priv->data, &size, |
|---|
| 330 | | - msize, id); |
|---|
| 331 | | - if (rc) { |
|---|
| 332 | | - if (rc == -ENOENT) |
|---|
| 333 | | - dev_dbg(device, "loading %s failed with error %d\n", |
|---|
| 334 | | - path, rc); |
|---|
| 335 | | - else |
|---|
| 525 | + |
|---|
| 526 | + /* |
|---|
| 527 | + * The total file size is only examined when doing a partial |
|---|
| 528 | + * read; the "full read" case needs to fail if the whole |
|---|
| 529 | + * firmware was not completely loaded. |
|---|
| 530 | + */ |
|---|
| 531 | + if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && buffer) |
|---|
| 532 | + file_size_ptr = &file_size; |
|---|
| 533 | + |
|---|
| 534 | + /* load firmware files from the mount namespace of init */ |
|---|
| 535 | + rc = kernel_read_file_from_path_initns(path, fw_priv->offset, |
|---|
| 536 | + &buffer, msize, |
|---|
| 537 | + file_size_ptr, |
|---|
| 538 | + READING_FIRMWARE); |
|---|
| 539 | + if (rc < 0) { |
|---|
| 540 | + if (rc != -ENOENT) |
|---|
| 336 | 541 | dev_warn(device, "loading %s failed with error %d\n", |
|---|
| 337 | 542 | path, rc); |
|---|
| 543 | + else |
|---|
| 544 | + dev_dbg(device, "loading %s failed for no such file or directory.\n", |
|---|
| 545 | + path); |
|---|
| 338 | 546 | continue; |
|---|
| 339 | 547 | } |
|---|
| 340 | | - dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name); |
|---|
| 341 | | - fw_priv->size = size; |
|---|
| 548 | + size = rc; |
|---|
| 549 | + rc = 0; |
|---|
| 550 | + |
|---|
| 551 | + dev_dbg(device, "Loading firmware from %s\n", path); |
|---|
| 552 | + if (decompress) { |
|---|
| 553 | + dev_dbg(device, "f/w decompressing %s\n", |
|---|
| 554 | + fw_priv->fw_name); |
|---|
| 555 | + rc = decompress(device, fw_priv, size, buffer); |
|---|
| 556 | + /* discard the superfluous original content */ |
|---|
| 557 | + vfree(buffer); |
|---|
| 558 | + buffer = NULL; |
|---|
| 559 | + if (rc) { |
|---|
| 560 | + fw_free_paged_buf(fw_priv); |
|---|
| 561 | + continue; |
|---|
| 562 | + } |
|---|
| 563 | + } else { |
|---|
| 564 | + dev_dbg(device, "direct-loading %s\n", |
|---|
| 565 | + fw_priv->fw_name); |
|---|
| 566 | + if (!fw_priv->data) |
|---|
| 567 | + fw_priv->data = buffer; |
|---|
| 568 | + fw_priv->size = size; |
|---|
| 569 | + } |
|---|
| 342 | 570 | fw_state_done(fw_priv); |
|---|
| 343 | 571 | break; |
|---|
| 344 | 572 | } |
|---|
| .. | .. |
|---|
| 362 | 590 | static void fw_set_page_data(struct fw_priv *fw_priv, struct firmware *fw) |
|---|
| 363 | 591 | { |
|---|
| 364 | 592 | fw->priv = fw_priv; |
|---|
| 365 | | -#ifdef CONFIG_FW_LOADER_USER_HELPER |
|---|
| 366 | | - fw->pages = fw_priv->pages; |
|---|
| 367 | | -#endif |
|---|
| 368 | 593 | fw->size = fw_priv->size; |
|---|
| 369 | 594 | fw->data = fw_priv->data; |
|---|
| 370 | 595 | |
|---|
| .. | .. |
|---|
| 449 | 674 | } |
|---|
| 450 | 675 | #endif |
|---|
| 451 | 676 | |
|---|
| 452 | | -int assign_fw(struct firmware *fw, struct device *device, |
|---|
| 453 | | - enum fw_opt opt_flags) |
|---|
| 677 | +int assign_fw(struct firmware *fw, struct device *device) |
|---|
| 454 | 678 | { |
|---|
| 455 | 679 | struct fw_priv *fw_priv = fw->priv; |
|---|
| 456 | 680 | int ret; |
|---|
| .. | .. |
|---|
| 469 | 693 | * should be fixed in devres or driver core. |
|---|
| 470 | 694 | */ |
|---|
| 471 | 695 | /* don't cache firmware handled without uevent */ |
|---|
| 472 | | - if (device && (opt_flags & FW_OPT_UEVENT) && |
|---|
| 473 | | - !(opt_flags & FW_OPT_NOCACHE)) { |
|---|
| 696 | + if (device && (fw_priv->opt_flags & FW_OPT_UEVENT) && |
|---|
| 697 | + !(fw_priv->opt_flags & FW_OPT_NOCACHE)) { |
|---|
| 474 | 698 | ret = fw_add_devm_name(device, fw_priv->fw_name); |
|---|
| 475 | 699 | if (ret) { |
|---|
| 476 | 700 | mutex_unlock(&fw_lock); |
|---|
| .. | .. |
|---|
| 482 | 706 | * After caching firmware image is started, let it piggyback |
|---|
| 483 | 707 | * on request firmware. |
|---|
| 484 | 708 | */ |
|---|
| 485 | | - if (!(opt_flags & FW_OPT_NOCACHE) && |
|---|
| 486 | | - fw_priv->fwc->state == FW_LOADER_START_CACHE) { |
|---|
| 487 | | - if (fw_cache_piggyback_on_request(fw_priv->fw_name)) |
|---|
| 488 | | - kref_get(&fw_priv->ref); |
|---|
| 489 | | - } |
|---|
| 709 | + if (!(fw_priv->opt_flags & FW_OPT_NOCACHE) && |
|---|
| 710 | + fw_priv->fwc->state == FW_LOADER_START_CACHE) |
|---|
| 711 | + fw_cache_piggyback_on_request(fw_priv); |
|---|
| 490 | 712 | |
|---|
| 491 | 713 | /* pass the pages buffer to driver at the last minute */ |
|---|
| 492 | 714 | fw_set_page_data(fw_priv, fw); |
|---|
| .. | .. |
|---|
| 501 | 723 | static int |
|---|
| 502 | 724 | _request_firmware_prepare(struct firmware **firmware_p, const char *name, |
|---|
| 503 | 725 | struct device *device, void *dbuf, size_t size, |
|---|
| 504 | | - enum fw_opt opt_flags) |
|---|
| 726 | + size_t offset, u32 opt_flags) |
|---|
| 505 | 727 | { |
|---|
| 506 | 728 | struct firmware *firmware; |
|---|
| 507 | 729 | struct fw_priv *fw_priv; |
|---|
| .. | .. |
|---|
| 520 | 742 | } |
|---|
| 521 | 743 | |
|---|
| 522 | 744 | ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size, |
|---|
| 523 | | - opt_flags); |
|---|
| 745 | + offset, opt_flags); |
|---|
| 524 | 746 | |
|---|
| 525 | 747 | /* |
|---|
| 526 | 748 | * bind with 'priv' now to avoid warning in failure path |
|---|
| .. | .. |
|---|
| 569 | 791 | static int |
|---|
| 570 | 792 | _request_firmware(const struct firmware **firmware_p, const char *name, |
|---|
| 571 | 793 | struct device *device, void *buf, size_t size, |
|---|
| 572 | | - enum fw_opt opt_flags) |
|---|
| 794 | + size_t offset, u32 opt_flags) |
|---|
| 573 | 795 | { |
|---|
| 574 | 796 | struct firmware *fw = NULL; |
|---|
| 797 | + bool nondirect = false; |
|---|
| 575 | 798 | int ret; |
|---|
| 576 | 799 | |
|---|
| 577 | 800 | if (!firmware_p) |
|---|
| .. | .. |
|---|
| 583 | 806 | } |
|---|
| 584 | 807 | |
|---|
| 585 | 808 | ret = _request_firmware_prepare(&fw, name, device, buf, size, |
|---|
| 586 | | - opt_flags); |
|---|
| 809 | + offset, opt_flags); |
|---|
| 587 | 810 | if (ret <= 0) /* error or already assigned */ |
|---|
| 588 | 811 | goto out; |
|---|
| 589 | 812 | |
|---|
| 590 | | - ret = fw_get_filesystem_firmware(device, fw->priv); |
|---|
| 813 | + ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); |
|---|
| 814 | + |
|---|
| 815 | + /* Only full reads can support decompression, platform, and sysfs. */ |
|---|
| 816 | + if (!(opt_flags & FW_OPT_PARTIAL)) |
|---|
| 817 | + nondirect = true; |
|---|
| 818 | + |
|---|
| 819 | +#ifdef CONFIG_FW_LOADER_COMPRESS |
|---|
| 820 | + if (ret == -ENOENT && nondirect) |
|---|
| 821 | + ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", |
|---|
| 822 | + fw_decompress_xz); |
|---|
| 823 | +#endif |
|---|
| 824 | + if (ret == -ENOENT && nondirect) |
|---|
| 825 | + ret = firmware_fallback_platform(fw->priv); |
|---|
| 826 | + |
|---|
| 591 | 827 | if (ret) { |
|---|
| 592 | 828 | if (!(opt_flags & FW_OPT_NO_WARN)) |
|---|
| 593 | 829 | dev_warn(device, |
|---|
| 594 | 830 | "Direct firmware load for %s failed with error %d\n", |
|---|
| 595 | 831 | name, ret); |
|---|
| 596 | | - ret = firmware_fallback_sysfs(fw, name, device, opt_flags, ret); |
|---|
| 832 | + if (nondirect) |
|---|
| 833 | + ret = firmware_fallback_sysfs(fw, name, device, |
|---|
| 834 | + opt_flags, ret); |
|---|
| 597 | 835 | } else |
|---|
| 598 | | - ret = assign_fw(fw, device, opt_flags); |
|---|
| 836 | + ret = assign_fw(fw, device); |
|---|
| 599 | 837 | |
|---|
| 600 | 838 | out: |
|---|
| 601 | 839 | if (ret < 0) { |
|---|
| .. | .. |
|---|
| 636 | 874 | |
|---|
| 637 | 875 | /* Need to pin this module until return */ |
|---|
| 638 | 876 | __module_get(THIS_MODULE); |
|---|
| 639 | | - ret = _request_firmware(firmware_p, name, device, NULL, 0, |
|---|
| 877 | + ret = _request_firmware(firmware_p, name, device, NULL, 0, 0, |
|---|
| 640 | 878 | FW_OPT_UEVENT); |
|---|
| 641 | 879 | module_put(THIS_MODULE); |
|---|
| 642 | 880 | return ret; |
|---|
| .. | .. |
|---|
| 649 | 887 | * @name: name of firmware file |
|---|
| 650 | 888 | * @device: device for which firmware is being loaded |
|---|
| 651 | 889 | * |
|---|
| 652 | | - * This function is similar in behaviour to request_firmware(), except |
|---|
| 653 | | - * it doesn't produce warning messages when the file is not found. |
|---|
| 654 | | - * The sysfs fallback mechanism is enabled if direct filesystem lookup fails, |
|---|
| 655 | | - * however, however failures to find the firmware file with it are still |
|---|
| 656 | | - * suppressed. It is therefore up to the driver to check for the return value |
|---|
| 657 | | - * of this call and to decide when to inform the users of errors. |
|---|
| 890 | + * This function is similar in behaviour to request_firmware(), except it |
|---|
| 891 | + * doesn't produce warning messages when the file is not found. The sysfs |
|---|
| 892 | + * fallback mechanism is enabled if direct filesystem lookup fails. However, |
|---|
| 893 | + * failures to find the firmware file with it are still suppressed. It is |
|---|
| 894 | + * therefore up to the driver to check for the return value of this call and to |
|---|
| 895 | + * decide when to inform the users of errors. |
|---|
| 658 | 896 | **/ |
|---|
| 659 | 897 | int firmware_request_nowarn(const struct firmware **firmware, const char *name, |
|---|
| 660 | 898 | struct device *device) |
|---|
| .. | .. |
|---|
| 663 | 901 | |
|---|
| 664 | 902 | /* Need to pin this module until return */ |
|---|
| 665 | 903 | __module_get(THIS_MODULE); |
|---|
| 666 | | - ret = _request_firmware(firmware, name, device, NULL, 0, |
|---|
| 904 | + ret = _request_firmware(firmware, name, device, NULL, 0, 0, |
|---|
| 667 | 905 | FW_OPT_UEVENT | FW_OPT_NO_WARN); |
|---|
| 668 | 906 | module_put(THIS_MODULE); |
|---|
| 669 | 907 | return ret; |
|---|
| .. | .. |
|---|
| 687 | 925 | int ret; |
|---|
| 688 | 926 | |
|---|
| 689 | 927 | __module_get(THIS_MODULE); |
|---|
| 690 | | - ret = _request_firmware(firmware_p, name, device, NULL, 0, |
|---|
| 928 | + ret = _request_firmware(firmware_p, name, device, NULL, 0, 0, |
|---|
| 691 | 929 | FW_OPT_UEVENT | FW_OPT_NO_WARN | |
|---|
| 692 | | - FW_OPT_NOFALLBACK); |
|---|
| 930 | + FW_OPT_NOFALLBACK_SYSFS); |
|---|
| 693 | 931 | module_put(THIS_MODULE); |
|---|
| 694 | 932 | return ret; |
|---|
| 695 | 933 | } |
|---|
| 696 | 934 | EXPORT_SYMBOL_GPL(request_firmware_direct); |
|---|
| 935 | + |
|---|
| 936 | +/** |
|---|
| 937 | + * firmware_request_platform() - request firmware with platform-fw fallback |
|---|
| 938 | + * @firmware: pointer to firmware image |
|---|
| 939 | + * @name: name of firmware file |
|---|
| 940 | + * @device: device for which firmware is being loaded |
|---|
| 941 | + * |
|---|
| 942 | + * This function is similar in behaviour to request_firmware, except that if |
|---|
| 943 | + * direct filesystem lookup fails, it will fallback to looking for a copy of the |
|---|
| 944 | + * requested firmware embedded in the platform's main (e.g. UEFI) firmware. |
|---|
| 945 | + **/ |
|---|
| 946 | +int firmware_request_platform(const struct firmware **firmware, |
|---|
| 947 | + const char *name, struct device *device) |
|---|
| 948 | +{ |
|---|
| 949 | + int ret; |
|---|
| 950 | + |
|---|
| 951 | + /* Need to pin this module until return */ |
|---|
| 952 | + __module_get(THIS_MODULE); |
|---|
| 953 | + ret = _request_firmware(firmware, name, device, NULL, 0, 0, |
|---|
| 954 | + FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM); |
|---|
| 955 | + module_put(THIS_MODULE); |
|---|
| 956 | + return ret; |
|---|
| 957 | +} |
|---|
| 958 | +EXPORT_SYMBOL_GPL(firmware_request_platform); |
|---|
| 697 | 959 | |
|---|
| 698 | 960 | /** |
|---|
| 699 | 961 | * firmware_request_cache() - cache firmware for suspend so resume can use it |
|---|
| .. | .. |
|---|
| 744 | 1006 | return -EOPNOTSUPP; |
|---|
| 745 | 1007 | |
|---|
| 746 | 1008 | __module_get(THIS_MODULE); |
|---|
| 747 | | - ret = _request_firmware(firmware_p, name, device, buf, size, |
|---|
| 1009 | + ret = _request_firmware(firmware_p, name, device, buf, size, 0, |
|---|
| 748 | 1010 | FW_OPT_UEVENT | FW_OPT_NOCACHE); |
|---|
| 749 | 1011 | module_put(THIS_MODULE); |
|---|
| 750 | 1012 | return ret; |
|---|
| 751 | 1013 | } |
|---|
| 752 | 1014 | EXPORT_SYMBOL(request_firmware_into_buf); |
|---|
| 1015 | + |
|---|
| 1016 | +/** |
|---|
| 1017 | + * request_partial_firmware_into_buf() - load partial firmware into a previously allocated buffer |
|---|
| 1018 | + * @firmware_p: pointer to firmware image |
|---|
| 1019 | + * @name: name of firmware file |
|---|
| 1020 | + * @device: device for which firmware is being loaded and DMA region allocated |
|---|
| 1021 | + * @buf: address of buffer to load firmware into |
|---|
| 1022 | + * @size: size of buffer |
|---|
| 1023 | + * @offset: offset into file to read |
|---|
| 1024 | + * |
|---|
| 1025 | + * This function works pretty much like request_firmware_into_buf except |
|---|
| 1026 | + * it allows a partial read of the file. |
|---|
| 1027 | + */ |
|---|
| 1028 | +int |
|---|
| 1029 | +request_partial_firmware_into_buf(const struct firmware **firmware_p, |
|---|
| 1030 | + const char *name, struct device *device, |
|---|
| 1031 | + void *buf, size_t size, size_t offset) |
|---|
| 1032 | +{ |
|---|
| 1033 | + int ret; |
|---|
| 1034 | + |
|---|
| 1035 | + if (fw_cache_is_setup(device, name)) |
|---|
| 1036 | + return -EOPNOTSUPP; |
|---|
| 1037 | + |
|---|
| 1038 | + __module_get(THIS_MODULE); |
|---|
| 1039 | + ret = _request_firmware(firmware_p, name, device, buf, size, offset, |
|---|
| 1040 | + FW_OPT_UEVENT | FW_OPT_NOCACHE | |
|---|
| 1041 | + FW_OPT_PARTIAL); |
|---|
| 1042 | + module_put(THIS_MODULE); |
|---|
| 1043 | + return ret; |
|---|
| 1044 | +} |
|---|
| 1045 | +EXPORT_SYMBOL(request_partial_firmware_into_buf); |
|---|
| 753 | 1046 | |
|---|
| 754 | 1047 | /** |
|---|
| 755 | 1048 | * release_firmware() - release the resource associated with a firmware image |
|---|
| .. | .. |
|---|
| 773 | 1066 | struct device *device; |
|---|
| 774 | 1067 | void *context; |
|---|
| 775 | 1068 | void (*cont)(const struct firmware *fw, void *context); |
|---|
| 776 | | - enum fw_opt opt_flags; |
|---|
| 1069 | + u32 opt_flags; |
|---|
| 777 | 1070 | }; |
|---|
| 778 | 1071 | |
|---|
| 779 | 1072 | static void request_firmware_work_func(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 783 | 1076 | |
|---|
| 784 | 1077 | fw_work = container_of(work, struct firmware_work, work); |
|---|
| 785 | 1078 | |
|---|
| 786 | | - _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, |
|---|
| 1079 | + _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0, |
|---|
| 787 | 1080 | fw_work->opt_flags); |
|---|
| 788 | 1081 | fw_work->cont(fw, fw_work->context); |
|---|
| 789 | 1082 | put_device(fw_work->device); /* taken in request_firmware_nowait() */ |
|---|
| .. | .. |
|---|
| 964 | 1257 | return 0; |
|---|
| 965 | 1258 | } |
|---|
| 966 | 1259 | |
|---|
| 967 | | -static int fw_cache_piggyback_on_request(const char *name) |
|---|
| 1260 | +static void fw_cache_piggyback_on_request(struct fw_priv *fw_priv) |
|---|
| 968 | 1261 | { |
|---|
| 969 | | - struct firmware_cache *fwc = &fw_cache; |
|---|
| 1262 | + const char *name = fw_priv->fw_name; |
|---|
| 1263 | + struct firmware_cache *fwc = fw_priv->fwc; |
|---|
| 970 | 1264 | struct fw_cache_entry *fce; |
|---|
| 971 | | - int ret = 0; |
|---|
| 972 | 1265 | |
|---|
| 973 | 1266 | spin_lock(&fwc->name_lock); |
|---|
| 974 | 1267 | if (__fw_entry_found(name)) |
|---|
| .. | .. |
|---|
| 976 | 1269 | |
|---|
| 977 | 1270 | fce = alloc_fw_cache_entry(name); |
|---|
| 978 | 1271 | if (fce) { |
|---|
| 979 | | - ret = 1; |
|---|
| 980 | 1272 | list_add(&fce->list, &fwc->fw_names); |
|---|
| 1273 | + kref_get(&fw_priv->ref); |
|---|
| 981 | 1274 | pr_debug("%s: fw: %s\n", __func__, name); |
|---|
| 982 | 1275 | } |
|---|
| 983 | 1276 | found: |
|---|
| 984 | 1277 | spin_unlock(&fwc->name_lock); |
|---|
| 985 | | - return ret; |
|---|
| 986 | 1278 | } |
|---|
| 987 | 1279 | |
|---|
| 988 | 1280 | static void free_fw_cache_entry(struct fw_cache_entry *fce) |
|---|
| .. | .. |
|---|
| 1151 | 1443 | case PM_SUSPEND_PREPARE: |
|---|
| 1152 | 1444 | case PM_RESTORE_PREPARE: |
|---|
| 1153 | 1445 | /* |
|---|
| 1154 | | - * kill pending fallback requests with a custom fallback |
|---|
| 1155 | | - * to avoid stalling suspend. |
|---|
| 1446 | + * Here, kill pending fallback requests will only kill |
|---|
| 1447 | + * non-uevent firmware request to avoid stalling suspend. |
|---|
| 1156 | 1448 | */ |
|---|
| 1157 | | - kill_pending_fw_fallback_reqs(true); |
|---|
| 1449 | + kill_pending_fw_fallback_reqs(false); |
|---|
| 1158 | 1450 | device_cache_fw_images(); |
|---|
| 1159 | 1451 | break; |
|---|
| 1160 | 1452 | |
|---|
| .. | .. |
|---|
| 1213 | 1505 | unregister_pm_notifier(&fw_cache.pm_notify); |
|---|
| 1214 | 1506 | } |
|---|
| 1215 | 1507 | #else |
|---|
| 1216 | | -static int fw_cache_piggyback_on_request(const char *name) |
|---|
| 1508 | +static void fw_cache_piggyback_on_request(struct fw_priv *fw_priv) |
|---|
| 1217 | 1509 | { |
|---|
| 1218 | | - return 0; |
|---|
| 1219 | 1510 | } |
|---|
| 1220 | 1511 | static inline int register_fw_pm_ops(void) |
|---|
| 1221 | 1512 | { |
|---|
| .. | .. |
|---|
| 1240 | 1531 | * Kill all pending fallback requests to avoid both stalling shutdown, |
|---|
| 1241 | 1532 | * and avoid a deadlock with the usermode_lock. |
|---|
| 1242 | 1533 | */ |
|---|
| 1243 | | - kill_pending_fw_fallback_reqs(false); |
|---|
| 1534 | + kill_pending_fw_fallback_reqs(true); |
|---|
| 1244 | 1535 | |
|---|
| 1245 | 1536 | return NOTIFY_DONE; |
|---|
| 1246 | 1537 | } |
|---|