Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d48c8e4 authored by Brian Swetland's avatar Brian Swetland
Browse files

defer firmware load until after filesystems are mounted

In some situations a driver could try to request firmware before
/system is mounted.  Previously we'd fail the request.  Now we
will retry the read-from-filesystem every 100ms until we find the
firmware or we've finished the "fs" and "post-fs" stages of init.

Change-Id: Ie32402f7d41c818bf20f3297286ed5f99705b72c
parent e31f2cdd
Loading
Loading
Loading
Loading
+20 −9
Original line number Diff line number Diff line
@@ -551,13 +551,19 @@ out:
    return ret;
}

static int is_booting(void)
{
    return access("/dev/.booting", F_OK) == 0;
}

static void process_firmware_event(struct uevent *uevent)
{
    char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
    int l, loading_fd, data_fd, fw_fd;
    int booting = is_booting();

    log_event_print("firmware event { '%s', '%s' }\n",
                    uevent->path, uevent->firmware);
    INFO("firmware: loading '%s' for '%s'\n",
         uevent->firmware, uevent->path);

    l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
    if (l == -1)
@@ -587,19 +593,29 @@ static void process_firmware_event(struct uevent *uevent)
    if(data_fd < 0)
        goto loading_close_out;

try_loading_again:
    fw_fd = open(file1, O_RDONLY);
    if(fw_fd < 0) {
        fw_fd = open(file2, O_RDONLY);
        if (fw_fd < 0) {
            if (booting) {
                    /* If we're not fully booted, we may be missing
                     * filesystems needed for firmware, wait and retry.
                     */
                usleep(100000);
                booting = is_booting();
                goto try_loading_again;
            }
            INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
            write(loading_fd, "-1", 2);
            goto data_close_out;
        }
    }

    if(!load_firmware(fw_fd, loading_fd, data_fd))
        log_event_print("firmware copy success { '%s', '%s' }\n", root, uevent->firmware);
        INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
    else
        log_event_print("firmware copy failure { '%s', '%s' }\n", root, uevent->firmware);
        INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);

    close(fw_fd);
data_close_out:
@@ -620,7 +636,6 @@ root_free_out:
static void handle_firmware_event(struct uevent *uevent)
{
    pid_t pid;
    int status;
    int ret;

    if(strcmp(uevent->subsystem, "firmware"))
@@ -634,10 +649,6 @@ static void handle_firmware_event(struct uevent *uevent)
    if (!pid) {
        process_firmware_event(uevent);
        exit(EXIT_SUCCESS);
    } else {
        do {
            ret = waitpid(pid, &status, 0);
        } while (ret == -1 && errno == EINTR);
    }
}

+7 −0
Original line number Diff line number Diff line
@@ -651,6 +651,10 @@ static int check_startup_action(int nargs, char **args)
        ERROR("init startup failure\n");
        exit(1);
    }

        /* signal that we hit this point */
    unlink("/dev/.booting");

    return 0;
}

@@ -708,6 +712,9 @@ int main(int argc, char **argv)
    mount("proc", "/proc", "proc", 0, NULL);
    mount("sysfs", "/sys", "sysfs", 0, NULL);

        /* indicate that booting is in progress to background fw loaders, etc */
    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));

        /* We must have some place other than / to create the
         * device nodes for kmsg and null, otherwise we won't
         * be able to remount / read-only later on.
+9 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>

#include <private/android_filesystem_config.h>

#include "ueventd.h"
@@ -37,6 +39,13 @@ int ueventd_main(int argc, char **argv)
    int nr;
    char tmp[32];

        /* Prevent fire-and-forget children from becoming zombies.
         * If we should need to wait() for some children in the future
         * (as opposed to none right now), double-forking here instead
         * of ignoring SIGCHLD may be the better solution.
         */
    signal(SIGCHLD, SIG_IGN);

    open_devnull_stdio();
    log_init();