diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2020-09-25 08:06:22 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2020-09-25 08:06:22 +0200 |
commit | faddac631a0e521780854ecf9a53f96481a32716 (patch) | |
tree | 292c866315fd161df41d90f4bbde1572b14415d1 /common | |
parent | 1ab2e649dc0ccef7ee990b999e1d8f8c32e7cd24 (diff) | |
parent | 0d4d157cf0d42206491b7a1b417c9904a9abd553 (diff) | |
download | barebox-faddac631a0e521780854ecf9a53f96481a32716.tar.gz barebox-faddac631a0e521780854ecf9a53f96481a32716.tar.xz |
Merge branch 'for-next/net' into master
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile | 2 | ||||
-rw-r--r-- | common/fastboot.c | 57 | ||||
-rw-r--r-- | common/globalvar.c | 54 | ||||
-rw-r--r-- | common/hush.c | 6 | ||||
-rw-r--r-- | common/poller.c | 11 | ||||
-rw-r--r-- | common/ratp/ratp.c | 57 | ||||
-rw-r--r-- | common/slice.c | 335 | ||||
-rw-r--r-- | common/startup.c | 3 | ||||
-rw-r--r-- | common/usbgadget.c | 21 | ||||
-rw-r--r-- | common/workqueue.c | 61 |
10 files changed, 572 insertions, 35 deletions
diff --git a/common/Makefile b/common/Makefile index faf0415ef3..c3ae3ca1b9 100644 --- a/common/Makefile +++ b/common/Makefile @@ -11,6 +11,8 @@ obj-y += bootsource.o obj-$(CONFIG_ELF) += elf.o obj-y += restart.o obj-y += poweroff.o +obj-y += slice.o +obj-y += workqueue.o obj-$(CONFIG_MACHINE_ID) += machine_id.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o obj-y += version.o diff --git a/common/fastboot.c b/common/fastboot.c index 86e7997a0b..bcfadfad3d 100644 --- a/common/fastboot.c +++ b/common/fastboot.c @@ -46,6 +46,8 @@ #define FASTBOOT_VERSION "0.4" static unsigned int fastboot_max_download_size = SZ_8M; +static int fastboot_bbu; +static char *fastboot_partitions; struct fb_variable { char *name; @@ -169,6 +171,8 @@ int fastboot_generic_init(struct fastboot *fb, bool export_bbu) struct file_list_entry *fentry; struct fb_variable *var; + INIT_LIST_HEAD(&fb->variables); + var = fb_addvar(fb, "version"); fb_setvar(var, "0.4"); var = fb_addvar(fb, "bootloader-version"); @@ -241,6 +245,7 @@ static char *fastboot_msg[] = { [FASTBOOT_MSG_FAIL] = "FAIL", [FASTBOOT_MSG_INFO] = "INFO", [FASTBOOT_MSG_DATA] = "DATA", + [FASTBOOT_MSG_NONE] = "", }; int fastboot_tx_print(struct fastboot *fb, enum fastboot_msg_type type, @@ -269,6 +274,7 @@ int fastboot_tx_print(struct fastboot *fb, enum fastboot_msg_type type, case FASTBOOT_MSG_INFO: pr_info("%pV\n", &vaf); break; + case FASTBOOT_MSG_NONE: case FASTBOOT_MSG_DATA: break; } @@ -283,6 +289,7 @@ int fastboot_tx_print(struct fastboot *fb, enum fastboot_msg_type type, static void cb_reboot(struct fastboot *fb, const char *cmd) { + fastboot_tx_print(fb, FASTBOOT_MSG_OKAY, ""); restart_machine(); } @@ -335,6 +342,7 @@ int fastboot_handle_download_data(struct fastboot *fb, const void *buffer, void fastboot_download_finished(struct fastboot *fb) { close(fb->download_fd); + fb->download_fd = 0; printf("\n"); @@ -344,6 +352,18 @@ void fastboot_download_finished(struct fastboot *fb) fastboot_tx_print(fb, FASTBOOT_MSG_OKAY, ""); } +void fastboot_abort(struct fastboot *fb) +{ + if (fb->download_fd > 0) { + close(fb->download_fd); + fb->download_fd = 0; + } + + fb->active = false; + + unlink(fb->tempname); +} + static void cb_download(struct fastboot *fb, const char *cmd) { fb->download_size = simple_strtoul(cmd, NULL, 16); @@ -354,6 +374,11 @@ static void cb_download(struct fastboot *fb, const char *cmd) init_progression_bar(fb->download_size); + if (fb->download_fd > 0) { + pr_err("%s called and %s is still opened\n", __func__, fb->tempname); + close(fb->download_fd); + } + fb->download_fd = open(fb->tempname, O_WRONLY | O_CREAT | O_TRUNC); if (fb->download_fd < 0) { fastboot_tx_print(fb, FASTBOOT_MSG_FAIL, "internal error"); @@ -903,17 +928,43 @@ void fastboot_exec_cmd(struct fastboot *fb, const char *cmdbuf) ARRAY_SIZE(cmd_dispatch_info)); } +bool get_fastboot_bbu(void) +{ + return fastboot_bbu; +} + +const char *get_fastboot_partitions(void) +{ + return fastboot_partitions; +} + static int fastboot_globalvars_init(void) { if (IS_ENABLED(CONFIG_FASTBOOT_SPARSE)) - globalvar_add_simple_int("usbgadget.fastboot_max_download_size", + globalvar_add_simple_int("fastboot.max_download_size", &fastboot_max_download_size, "%u"); + globalvar_add_simple_bool("fastboot.bbu", &fastboot_bbu); + globalvar_add_simple_string("fastboot.partitions", + &fastboot_partitions); + + globalvar_alias_deprecated("usbgadget.fastboot_function", + "fastboot.partitions"); + globalvar_alias_deprecated("usbgadget.fastboot_bbu", + "fastboot.bbu"); + globalvar_alias_deprecated("usbgadget.fastboot_max_download_size", + "fastboot.max_download_size"); return 0; } device_initcall(fastboot_globalvars_init); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_max_download_size, - global.usbgadget.fastboot_max_download_size, +BAREBOX_MAGICVAR_NAMED(global_fastboot_max_download_size, + global.fastboot.max_download_size, "Fastboot maximum download size"); +BAREBOX_MAGICVAR_NAMED(global_fastboot_partitions, + global.fastboot.partitions, + "Partitions exported for update via fastboot"); +BAREBOX_MAGICVAR_NAMED(global_fastboot_bbu, + global.fastboot.bbu, + "Export barebox update handlers via fastboot"); diff --git a/common/globalvar.c b/common/globalvar.c index eefee73e7a..5bde86aad0 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -293,6 +293,53 @@ int nvvar_remove(const char *name) return ret; } +struct globalvar_deprecated { + char *newname; + char *oldname; + struct list_head list; +}; + +static LIST_HEAD(globalvar_deprecated_list); + +/* + * globalvar_alias_deprecated - add an alias + * + * @oldname: The old name for the variable + * @newname: The new name for the variable + * + * This function is a helper for globalvars that are renamed from one + * release to another. when a variable @oldname is found in the persistent + * environment a warning is issued and its value is written to @newname. + * + * Note that when both @oldname and @newname contain values then the values + * existing in @newname are overwritten. + */ +void globalvar_alias_deprecated(const char *oldname, const char *newname) +{ + struct globalvar_deprecated *gd; + + gd = xzalloc(sizeof(*gd)); + gd->newname = xstrdup(newname); + gd->oldname = xstrdup(oldname); + list_add_tail(&gd->list, &globalvar_deprecated_list); +} + +static const char *globalvar_new_name(const char *oldname) +{ + struct globalvar_deprecated *gd; + + list_for_each_entry(gd, &globalvar_deprecated_list, list) { + if (!strcmp(oldname, gd->oldname)) { + pr_warn("nv.%s is deprecated, converting to nv.%s\n", oldname, + gd->newname); + nv_dirty = 1; + return gd->newname; + } + } + + return oldname; +} + int nvvar_load(void) { char *val; @@ -308,6 +355,8 @@ int nvvar_load(void) return -ENOENT; while ((d = readdir(dir))) { + const char *n; + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; @@ -316,10 +365,11 @@ int nvvar_load(void) pr_debug("%s: Setting \"%s\" to \"%s\"\n", __func__, d->d_name, val); - ret = __nvvar_add(d->d_name, val); + n = globalvar_new_name(d->d_name); + ret = __nvvar_add(n, val); if (ret) pr_err("failed to create nv variable %s: %s\n", - d->d_name, strerror(-ret)); + n, strerror(-ret)); } closedir(dir); diff --git a/common/hush.c b/common/hush.c index c24b2c7cd2..ec0d5129b7 100644 --- a/common/hush.c +++ b/common/hush.c @@ -121,6 +121,7 @@ #include <libbb.h> #include <password.h> #include <glob.h> +#include <slice.h> #include <getopt.h> #include <libfile.h> #include <libbb.h> @@ -460,7 +461,12 @@ static void get_user_input(struct in_str *i) else prompt = CONFIG_PROMPT_HUSH_PS2; + command_slice_release(); + n = readline(prompt, console_buffer, CONFIG_CBSIZE); + + command_slice_acquire(); + if (n == -1 ) { i->interrupt = 1; n = 0; diff --git a/common/poller.c b/common/poller.c index 95f828b439..50c518697b 100644 --- a/common/poller.c +++ b/common/poller.c @@ -12,9 +12,11 @@ #include <param.h> #include <poller.h> #include <clock.h> +#include <work.h> +#include <slice.h> static LIST_HEAD(poller_list); -static int poller_active; +int poller_active; int poller_register(struct poller_struct *poller, const char *name) { @@ -110,15 +112,22 @@ int poller_async_unregister(struct poller_async *pa) void poller_call(void) { struct poller_struct *poller, *tmp; + bool run_workqueues = !slice_acquired(&command_slice); if (poller_active) return; + command_slice_acquire(); + + if (run_workqueues) + wq_do_all_works(); + poller_active = 1; list_for_each_entry_safe(poller, tmp, &poller_list, list) poller->func(poller); + command_slice_release(); poller_active = 0; } diff --git a/common/ratp/ratp.c b/common/ratp/ratp.c index 9ca299eef2..424c9406d2 100644 --- a/common/ratp/ratp.c +++ b/common/ratp/ratp.c @@ -22,6 +22,7 @@ #include <environment.h> #include <kfifo.h> #include <poller.h> +#include <work.h> #include <linux/sizes.h> #include <ratp_bb.h> #include <fs.h> @@ -49,9 +50,11 @@ struct ratp_ctx { struct ratp_bb_pkt *fs_rx; struct poller_struct poller; + struct work_queue wq; bool console_registered; bool poller_registered; + bool wq_registered; }; static int compare_ratp_command(struct list_head *a, struct list_head *b) @@ -193,9 +196,14 @@ static int ratp_bb_send_command_return(struct ratp_ctx *ctx, uint32_t errno) return ret; } -static char *ratp_command; static struct ratp_ctx *ratp_ctx; +struct ratp_work { + struct work_struct work; + struct ratp_ctx *ctx; + char *command; +}; + static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len) { const struct ratp_bb *rbb = buf; @@ -204,6 +212,7 @@ static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len) int ret = 0; uint16_t type = be16_to_cpu(rbb->type); struct ratp_command *cmd; + struct ratp_work *rw; /* See if there's a command registered to this type */ cmd = find_ratp_request(type); @@ -221,12 +230,16 @@ static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len) switch (type) { case BB_RATP_TYPE_COMMAND: - if (!IS_ENABLED(CONFIG_CONSOLE_RATP) || ratp_command) + if (!IS_ENABLED(CONFIG_CONSOLE_RATP)) return 0; - ratp_command = xstrndup((const char *)rbb->data, dlen); - ratp_ctx = ctx; - pr_debug("got command: %s\n", ratp_command); + rw = xzalloc(sizeof(*rw)); + rw->ctx = ctx; + rw->command = xstrndup((const char *)rbb->data, dlen); + + wq_queue_work(&ctx->wq, &rw->work); + + pr_debug("got command: %s\n", rw->command); break; @@ -297,21 +310,20 @@ static void ratp_console_putc(struct console_device *cdev, char c) kfifo_putc(ctx->console_transmit_fifo, c); } -void barebox_ratp_command_run(void) +static void ratp_command_run(struct work_struct *w) { + struct ratp_work *rw = container_of(w, struct ratp_work, work); + struct ratp_ctx *ctx = rw->ctx; int ret; - if (!ratp_command) - return; - - pr_debug("running command: %s\n", ratp_command); + pr_debug("running command: %s\n", rw->command); - ret = run_command(ratp_command); + ret = run_command(rw->command); - free(ratp_command); - ratp_command = NULL; + free(rw->command); + free(rw); - ratp_bb_send_command_return(ratp_ctx, ret); + ratp_bb_send_command_return(ctx, ret); } static const char *ratpfs_mount_path; @@ -336,6 +348,9 @@ static void ratp_unregister(struct ratp_ctx *ctx) if (ctx->poller_registered) poller_unregister(&ctx->poller); + if (ctx->wq_registered) + wq_unregister(&ctx->wq); + ratp_close(&ctx->ratp); console_set_active(ctx->cdev, ctx->old_active); @@ -368,6 +383,7 @@ static void ratp_poller(struct poller_struct *poller) ret = ratp_poll(&ctx->ratp); if (ret == -EINTR) goto out; + if (ratp_closed(&ctx->ratp)) goto out; @@ -423,6 +439,14 @@ int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx) return 0; } +static void ratp_work_cancel(struct work_struct *w) +{ + struct ratp_work *rw = container_of(w, struct ratp_work, work); + + free(rw->command); + free(rw); +} + int barebox_ratp(struct console_device *cdev) { int ret; @@ -466,6 +490,11 @@ int barebox_ratp(struct console_device *cdev) if (ret < 0) goto out; + ctx->wq.fn = ratp_command_run; + ctx->wq.cancel = ratp_work_cancel; + wq_register(&ctx->wq); + ctx->wq_registered = true; + ret = poller_register(&ctx->poller, "ratp"); if (ret) goto out; diff --git a/common/slice.c b/common/slice.c new file mode 100644 index 0000000000..9d7e0d16cf --- /dev/null +++ b/common/slice.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) "slice: " fmt + +#include <common.h> +#include <init.h> +#include <slice.h> + +/* + * slices, the barebox idea of locking + * + * barebox has pollers which execute code in the background whenever one of the + * delay functions (udelay, mdelay, ...) or is_timeout() are called. This + * introduces resource problems when some device triggers a poller by calling + * a delay function and then the poller code calls into the same device again. + * + * As an example consider a I2C GPIO expander which drives a LED which shall + * be used as a heartbeat LED: + * + * poller -> LED on/off -> GPIO high/low -> I2C transfer + * + * The I2C controller has a timeout loop using is_timeout() and thus can trigger + * a poller run. With this the following can happen during an unrelated I2C + * transfer: + * + * I2C transfer -> is_timeout() -> poller -> LED on/off -> GPIO high/low -> I2C transfer + * + * We end up with issuing an I2C transfer during another I2C transfer and + * things go downhill. + * + * Due to the lack of interrupts we can't do real locking in barebox. We use + * a mechanism called slices instead. A slice describes a resource to which + * other slices can be attached. Whenever a slice is needed it must be acquired. + * Acquiring a slice never fails, it just increases the acquired counter of + * the slice and its dependent slices. when a slice shall be used inside a + * poller it must first be tested if the slice is already in use. If it is, + * we can't do the operation on the slice now and must return and hope that + * we have more luck in the next poller call. + * + * slices can be attached other slices as dependencies. In the example above + * LED driver would add a dependency to the GPIO controller and the GPIO driver + * would add a dependency to the I2C bus: + * + * GPIO driver probe: + * + * slice_depends_on(&gpio->slice, i2c_device_slice(i2cdev)); + * + * LED driver probe: + * + * slice_depends_on(&led->slice, gpio_slice(gpio)); + * + * The GPIO code would call slice_acquire(&gpio->slice) before doing any + * operation on the GPIO chip providing this GPIO, likewise the I2C core + * would call slice_acquire(&i2cbus->slice) before doing an operation on + * this I2C bus. + * + * The heartbeat poller code would call slice_acquired(led_slice(led)) and + * only continue when the slice is not acquired. + */ + +/* + * slices are not required to have a device and thus a name, but it really + * helps debugging when it has one. + */ +static const char *slice_name(struct slice *slice) +{ + return slice->name; +} + +static void __slice_acquire(struct slice *slice, int add) +{ + slice->acquired += add; + + if (slice->acquired < 0) { + pr_err("Slice %s acquired count drops below zero\n", + slice_name(slice)); + dump_stack(); + slice->acquired = 0; + return; + } +} + +/** + * slice_acquire: acquire a slice + * @slice: The slice to acquire + * + * This acquires a slice and its dependencies + */ +void slice_acquire(struct slice *slice) +{ + __slice_acquire(slice, 1); +} + +/** + * slice_release: release a slice + * @slice: The slice to release + * + * This releases a slice and its dependencies + */ +void slice_release(struct slice *slice) +{ + __slice_acquire(slice, -1); +} + +/** + * slice_acquired: test if a slice is acquired + * @slice: The slice to test + * + * This tests if a slice is acquired. Returns true if it is, false otherwise + */ +bool slice_acquired(struct slice *slice) +{ + struct slice_entry *se; + bool ret = false; + + if (slice->acquired > 0) + return true; + + if (slice->acquired < 0) { + pr_err("Recursive dependency detected in slice %s\n", + slice_name(slice)); + panic("Cannot continue"); + } + + slice->acquired = -1; + + list_for_each_entry(se, &slice->deps, list) + if (slice_acquired(se->slice)) { + ret = true; + break; + } + + slice->acquired = 0; + + return ret; +} + +static void __slice_debug_acquired(struct slice *slice, int level) +{ + struct slice_entry *se; + + pr_debug("%*s%s: %d\n", level * 4, "", + slice_name(slice), + slice->acquired); + + list_for_each_entry(se, &slice->deps, list) + __slice_debug_acquired(se->slice, level + 1); +} + +/** + * slice_debug_acquired: print the acquired state of a slice + * + * @slice: The slice to print + * + * This prints the acquired state of a slice and its dependencies. + */ +void slice_debug_acquired(struct slice *slice) +{ + if (!slice_acquired(slice)) + return; + + __slice_debug_acquired(slice, 0); +} + +/** + * slice_depends_on: Add a dependency to a slice + * + * @slice: The slice to add the dependency to + * @dep: The slice @slice depends on + * + * This makes @slice dependent on @dep. In other words, acquiring @slice + * will lead to also acquiring @dep. + */ +void slice_depends_on(struct slice *slice, struct slice *dep) +{ + struct slice_entry *se = xzalloc(sizeof(*se)); + + pr_debug("Adding dependency %s (%d) to slice %s (%d)\n", + slice_name(dep), dep->acquired, + slice_name(slice), slice->acquired); + + se->slice = dep; + + list_add_tail(&se->list, &slice->deps); +} + +static LIST_HEAD(slices); + +/** + * slice_init - initialize a slice before usage + * @slice: The slice to initialize + * @name: The name of the slice + * + * This initializes a slice before usage. @name should be a meaningful name, when + * a device context is available to the caller it is recommended to pass its + * dev_name() as name argument. + */ +void slice_init(struct slice *slice, const char *name) +{ + INIT_LIST_HEAD(&slice->deps); + slice->name = xstrdup(name); + list_add_tail(&slice->list, &slices); +} + +/** + * slice_exit: Remove a slice + * @slice: The slice to remove the dependency from + */ +void slice_exit(struct slice *slice) +{ + struct slice *s; + struct slice_entry *se, *tmp; + + list_del(&slice->list); + + /* remove our dependencies */ + list_for_each_entry_safe(se, tmp, &slice->deps, list) { + list_del(&se->list); + free(se); + } + + /* remove this slice from other slices dependencies */ + list_for_each_entry(s, &slices, list) { + list_for_each_entry_safe(se, tmp, &s->deps, list) { + if (se->slice == slice) { + list_del(&se->list); + free(se); + } + } + } + + free(slice->name); +} + +struct slice command_slice; + +/** + * command_slice_acquire - acquire the command slice + * + * The command slice is acquired by default. It is only released + * at certain points we know it's safe to execute code in the + * background, like when the shell is waiting for input. + */ +void command_slice_acquire(void) +{ + slice_acquire(&command_slice); +} + +/** + * command_slice_release - release the command slice + */ +void command_slice_release(void) +{ + slice_release(&command_slice); +} + +static int command_slice_init(void) +{ + slice_init(&command_slice, "command"); + slice_acquire(&command_slice); + return 0; +} + +pure_initcall(command_slice_init); + +#if defined CONFIG_CMD_SLICE + +#include <command.h> +#include <getopt.h> + +static void slice_info(void) +{ + struct slice *slice; + struct slice_entry *se; + + list_for_each_entry(slice, &slices, list) { + printf("slice %s: acquired=%d\n", + slice_name(slice), slice->acquired); + list_for_each_entry(se, &slice->deps, list) + printf(" dep: %s\n", slice_name(se->slice)); + } +} + +static int __slice_acquire_name(const char *name, int add) +{ + struct slice *slice; + + list_for_each_entry(slice, &slices, list) { + if (!strcmp(slice->name, name)) { + __slice_acquire(slice, add); + return 0; + } + } + + printf("No such slice: %s\n", name); + + return 1; +} + +BAREBOX_CMD_HELP_START(slice) +BAREBOX_CMD_HELP_TEXT("slice debugging command") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-i", "Print information about slices") +BAREBOX_CMD_HELP_OPT ("-a <devname>", "acquire a slice") +BAREBOX_CMD_HELP_OPT ("-r <devname>", "release a slice") +BAREBOX_CMD_HELP_END + +static int do_slice(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "a:r:i")) > 0) { + switch (opt) { + case 'a': + return __slice_acquire_name(optarg, 1); + case 'r': + return __slice_acquire_name(optarg, -1); + case 'i': + slice_info(); + return 0; + } + } + + return COMMAND_ERROR_USAGE; +} + +BAREBOX_CMD_START(slice) + .cmd = do_slice, + BAREBOX_CMD_DESC("debug slices") + BAREBOX_CMD_OPTS("[-ari]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_slice_help) +BAREBOX_CMD_END +#endif diff --git a/common/startup.c b/common/startup.c index 6cb0588ae6..ea7ce6b8da 100644 --- a/common/startup.c +++ b/common/startup.c @@ -34,6 +34,7 @@ #include <debug_ll.h> #include <fs.h> #include <errno.h> +#include <slice.h> #include <linux/stat.h> #include <envfs.h> #include <magicvar.h> @@ -272,8 +273,10 @@ enum autoboot_state do_autoboot_countdown(void) break; } + command_slice_release(); ret = console_countdown(global_autoboot_timeout, flags, abortkeys, &outkey); + command_slice_acquire(); if (ret == 0) autoboot_state = AUTOBOOT_BOOT; diff --git a/common/usbgadget.c b/common/usbgadget.c index a8f104cf1c..b4f4ba04ca 100644 --- a/common/usbgadget.c +++ b/common/usbgadget.c @@ -30,8 +30,6 @@ static int autostart; static int acm; static char *dfu_function; -static char *fastboot_function; -static int fastboot_bbu; static struct file_list *parse(const char *files) { @@ -51,13 +49,14 @@ int usbgadget_register(bool dfu, const char *dfu_opts, int ret; struct device_d *dev; struct f_multi_opts *opts; + const char *fastboot_partitions = get_fastboot_partitions(); if (dfu && !dfu_opts && dfu_function && *dfu_function) dfu_opts = dfu_function; - if (fastboot && !fastboot_opts && - fastboot_function && *fastboot_function) - fastboot_opts = fastboot_function; + if (IS_ENABLED(CONFIG_FASTBOOT_BASE) && fastboot && !fastboot_opts && + fastboot_partitions && *fastboot_partitions) + fastboot_opts = fastboot_partitions; if (!dfu_opts && !fastboot_opts && !acm) return COMMAND_ERROR_USAGE; @@ -104,6 +103,8 @@ int usbgadget_register(bool dfu, const char *dfu_opts, static int usbgadget_autostart(void) { + bool fastboot_bbu = get_fastboot_bbu(); + if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART) || !autostart) return 0; @@ -116,12 +117,8 @@ static int usbgadget_globalvars_init(void) if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART)) { globalvar_add_simple_bool("usbgadget.autostart", &autostart); globalvar_add_simple_bool("usbgadget.acm", &acm); - globalvar_add_simple_bool("usbgadget.fastboot_bbu", - &fastboot_bbu); } globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function); - globalvar_add_simple_string("usbgadget.fastboot_function", - &fastboot_function); return 0; } @@ -136,9 +133,3 @@ BAREBOX_MAGICVAR_NAMED(global_usbgadget_acm, BAREBOX_MAGICVAR_NAMED(global_usbgadget_dfu_function, global.usbgadget.dfu_function, "usbgadget: Create DFU function"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_function, - global.usbgadget.fastboot_function, - "usbgadget: Create Android Fastboot function"); -BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_bbu, - global.usbgadget.fastboot_bbu, - "usbgadget: export barebox update handlers via fastboot"); diff --git a/common/workqueue.c b/common/workqueue.c new file mode 100644 index 0000000000..dc6941dec1 --- /dev/null +++ b/common/workqueue.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <common.h> +#include <work.h> + +static void wq_do_pending_work(struct work_queue *wq) +{ + struct work_struct *work, *tmp; + + list_for_each_entry_safe(work, tmp, &wq->work, list) { + if (work->delayed && get_time_ns() < work->timeout) + continue; + + list_del(&work->list); + wq->fn(work); + } +} + +void wq_cancel_work(struct work_queue *wq) +{ + struct work_struct *work, *tmp; + + list_for_each_entry_safe(work, tmp, &wq->work, list) { + list_del(&work->list); + wq->cancel(work); + } +} + +static LIST_HEAD(work_queues); + +/** + * wq_do_all_works - do all pending work + * + * This calls all pending work functions + */ +void wq_do_all_works(void) +{ + struct work_queue *wq; + + list_for_each_entry(wq, &work_queues, list) + wq_do_pending_work(wq); +} + +/** + * wq_register - register a new work queue + * @wq: The work queue + */ +void wq_register(struct work_queue *wq) +{ + INIT_LIST_HEAD(&wq->work); + list_add_tail(&wq->list, &work_queues); +} + +/** + * wq_unregister - unregister a work queue + * @wq: The work queue + */ +void wq_unregister(struct work_queue *wq) +{ + wq_cancel_work(wq); + list_del(&wq->list); +} |