diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch b/target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch new file mode 100644 index 0000000000..ae3c019e25 --- /dev/null +++ b/target/linux/bcm27xx/patches-6.1/950-0841-gpio_fsm-Rework-the-atomic-vs-non-atomic-split.patch @@ -0,0 +1,192 @@ +From f0061ffc98c6e027c5774e2a24ceadcfee4167ea Mon Sep 17 00:00:00 2001 +From: Phil Elwell <phil@raspberrypi.com> +Date: Tue, 5 Sep 2023 12:01:13 +0100 +Subject: [PATCH] gpio_fsm: Rework the atomic-vs-non-atomic split + +Partition the code to separate atomic and non-atomic methods so that +none of them have to handle both cases. The result avoids using deferred +work unless necessary, and should be easier to understand. + +Signed-off-by: Phil Elwell <phil@raspberrypi.com> +--- + drivers/gpio/gpio-fsm.c | 84 ++++++++++++++++++++--------------------- + 1 file changed, 41 insertions(+), 43 deletions(-) + +--- a/drivers/gpio/gpio-fsm.c ++++ b/drivers/gpio/gpio-fsm.c +@@ -193,9 +193,6 @@ static void free_symbols(struct symtab_e + } + } + +-static void gpio_fsm_go_to_state(struct gpio_fsm *gf, +- struct fsm_state *new_state); +- + static void gpio_fsm_set_soft(struct gpio_fsm *gf, + unsigned int off, int val); + +@@ -213,6 +210,7 @@ static void gpio_fsm_enter_state(struct + dev_dbg(gf->dev, "enter_state(%s)\n", state->name); + + gf->current_state = state; ++ gf->delay_target_state = NULL; + + // 1. Apply any listed signals + for (i = 0; i < state->num_signals; i++) { +@@ -271,7 +269,7 @@ static void gpio_fsm_enter_state(struct + dev_info(gf->dev, + "GF_SOFT %d=%d -> %s\n", event->index, + event->value, event->target->name); +- gpio_fsm_go_to_state(gf, event->target); ++ gpio_fsm_enter_state(gf, event->target); + return; + } + } +@@ -284,7 +282,7 @@ static void gpio_fsm_enter_state(struct + inp_state->value = event->value; + inp_state->enabled = true; + +- value = gpiod_get_value(gf->input_gpios->desc[event->index]); ++ value = gpiod_get_value_cansleep(gf->input_gpios->desc[event->index]); + + // Clear stale event state + disable_irq(inp_state->irq); +@@ -299,7 +297,7 @@ static void gpio_fsm_enter_state(struct + dev_info(gf->dev, + "GF_IN %d=%d -> %s\n", event->index, + event->value, event->target->name); +- gpio_fsm_go_to_state(gf, event->target); ++ gpio_fsm_enter_state(gf, event->target); + return; + } + } +@@ -325,6 +323,33 @@ static void gpio_fsm_go_to_state(struct + dev_dbg(gf->dev, "go_to_state(%s)\n", + new_state ? new_state->name : "<unset>"); + ++ state = gf->current_state; ++ ++ /* Disable any enabled GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_events[i]; ++ inp_state = &gf->input_gpio_states[gp_ev->index]; ++ if (inp_state->enabled) { ++ inp_state->enabled = false; ++ irq_set_irq_type(inp_state->irq, ++ IRQF_TRIGGER_NONE); ++ } ++ } ++ ++ gpio_fsm_enter_state(gf, new_state); ++} ++ ++static void gpio_fsm_go_to_state_deferred(struct gpio_fsm *gf, ++ struct fsm_state *new_state) ++{ ++ struct input_gpio_state *inp_state; ++ struct gpio_event *gp_ev; ++ struct fsm_state *state; ++ int i; ++ ++ dev_dbg(gf->dev, "go_to_state_deferred(%s)\n", ++ new_state ? new_state->name : "<unset>"); ++ + spin_lock(&gf->spinlock); + + if (gf->next_state) { +@@ -335,57 +360,31 @@ static void gpio_fsm_go_to_state(struct + + gf->next_state = new_state; + state = gf->current_state; +- gf->delay_target_state = NULL; + +- if (state) { +- /* Disarm any GPIO IRQs */ +- for (i = 0; i < state->num_gpio_events; i++) { +- gp_ev = &state->gpio_events[i]; +- inp_state = &gf->input_gpio_states[gp_ev->index]; +- inp_state->target = NULL; +- } ++ /* Disarm any GPIO IRQs */ ++ for (i = 0; i < state->num_gpio_events; i++) { ++ gp_ev = &state->gpio_events[i]; ++ inp_state = &gf->input_gpio_states[gp_ev->index]; ++ inp_state->target = NULL; + } + + spin_unlock(&gf->spinlock); + +- if (new_state) +- schedule_work(&gf->work); ++ schedule_work(&gf->work); + } + + static void gpio_fsm_work(struct work_struct *work) + { +- struct input_gpio_state *inp_state; + struct fsm_state *new_state; +- struct fsm_state *state; +- struct gpio_event *gp_ev; + struct gpio_fsm *gf; +- int i; + + gf = container_of(work, struct gpio_fsm, work); + spin_lock(&gf->spinlock); +- state = gf->current_state; + new_state = gf->next_state; +- if (!new_state) +- new_state = gf->delay_target_state; + gf->next_state = NULL; +- gf->delay_target_state = NULL; + spin_unlock(&gf->spinlock); + +- if (state) { +- /* Disable any enabled GPIO IRQs */ +- for (i = 0; i < state->num_gpio_events; i++) { +- gp_ev = &state->gpio_events[i]; +- inp_state = &gf->input_gpio_states[gp_ev->index]; +- if (inp_state->enabled) { +- inp_state->enabled = false; +- irq_set_irq_type(inp_state->irq, +- IRQF_TRIGGER_NONE); +- } +- } +- } +- +- if (new_state) +- gpio_fsm_enter_state(gf, new_state); ++ gpio_fsm_go_to_state(gf, new_state); + } + + static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id) +@@ -404,7 +403,7 @@ static irqreturn_t gpio_fsm_gpio_irq_han + if (gf->debug) + dev_info(gf->dev, "GF_IN %d->%d -> %s\n", + inp_state->index, inp_state->value, target->name); +- gpio_fsm_go_to_state(gf, target); ++ gpio_fsm_go_to_state_deferred(gf, target); + return IRQ_HANDLED; + } + +@@ -416,12 +415,11 @@ static void gpio_fsm_timer(struct timer_ + target = gf->delay_target_state; + if (!target) + return; +- + if (gf->debug) + dev_info(gf->dev, "GF_DELAY %d -> %s\n", gf->delay_ms, + target->name); + +- gpio_fsm_go_to_state(gf, target); ++ gpio_fsm_go_to_state_deferred(gf, target); + } + + int gpio_fsm_parse_signals(struct gpio_fsm *gf, struct fsm_state *state, +@@ -1119,7 +1117,7 @@ static int gpio_fsm_probe(struct platfor + if (gf->debug) + dev_info(gf->dev, "Start -> %s\n", gf->start_state->name); + +- gpio_fsm_go_to_state(gf, gf->start_state); ++ gpio_fsm_enter_state(gf, gf->start_state); + + return devm_gpiochip_add_data(dev, &gf->gc, gf); + } |