1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
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);
}
|