* Lookup and potentially load the specified firmware image. * If the firmware is not found in the registry, try to load a kernel * module named as the image name. * If the firmware is located, a reference is returned. The caller must * release this reference for the image to be eligible for removal/unload. */
| 285 | * release this reference for the image to be eligible for removal/unload. |
| 286 | */ |
| 287 | const struct firmware * |
| 288 | firmware_get_flags(const char *imagename, uint32_t flags) |
| 289 | { |
| 290 | struct task fwload_task; |
| 291 | struct thread *td; |
| 292 | struct priv_fw *fp; |
| 293 | |
| 294 | mtx_lock(&firmware_mtx); |
| 295 | fp = lookup(imagename); |
| 296 | if (fp != NULL) |
| 297 | goto found; |
| 298 | /* |
| 299 | * Image not present, try to load the module holding it. |
| 300 | */ |
| 301 | td = curthread; |
| 302 | if (priv_check(td, PRIV_FIRMWARE_LOAD) != 0 || |
| 303 | securelevel_gt(td->td_ucred, 0) != 0) { |
| 304 | mtx_unlock(&firmware_mtx); |
| 305 | printf("%s: insufficient privileges to " |
| 306 | "load firmware image %s\n", __func__, imagename); |
| 307 | return NULL; |
| 308 | } |
| 309 | /* |
| 310 | * Defer load to a thread with known context. linker_reference_module |
| 311 | * may do filesystem i/o which requires root & current dirs, etc. |
| 312 | * Also we must not hold any mtx's over this call which is problematic. |
| 313 | */ |
| 314 | if (!cold) { |
| 315 | struct fw_loadimage fwli; |
| 316 | |
| 317 | fwli.imagename = imagename; |
| 318 | fwli.flags = flags; |
| 319 | TASK_INIT(&fwload_task, 0, loadimage, (void *)&fwli); |
| 320 | taskqueue_enqueue(firmware_tq, &fwload_task); |
| 321 | PHOLD(curproc); |
| 322 | msleep((void *)&fwli, &firmware_mtx, 0, "fwload", 0); |
| 323 | PRELE(curproc); |
| 324 | } |
| 325 | /* |
| 326 | * After attempting to load the module, see if the image is registered. |
| 327 | */ |
| 328 | fp = lookup(imagename); |
| 329 | if (fp == NULL) { |
| 330 | mtx_unlock(&firmware_mtx); |
| 331 | return NULL; |
| 332 | } |
| 333 | found: /* common exit point on success */ |
| 334 | if (fp->refcnt == 0 && fp->parent != NULL) |
| 335 | fp->parent->refcnt++; |
| 336 | fp->refcnt++; |
| 337 | mtx_unlock(&firmware_mtx); |
| 338 | return &fp->fw; |
| 339 | } |
| 340 | |
| 341 | const struct firmware * |
| 342 | firmware_get(const char *imagename) |
no test coverage detected