diff options
author | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2024-10-04 16:43:24 +0200 |
---|---|---|
committer | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2024-10-08 10:21:46 +0200 |
commit | b7adfb6076ff0c1ebbde56d1903daa3d07db92c5 (patch) | |
tree | 7f09c10a96d0462cc2a64c99630ac5ac6ba4ec60 /drivers/gpio/gpiolib-cdev.c | |
parent | fa17f749ee5bc6afdaa9e0ddbe6a816b490dad7d (diff) |
gpio: cdev: update flags at once when reconfiguring from user-space
Make updating the descriptor flags when reconfiguring from user-space
consistent with the rest of the codebase: read the current state
atomically, update it according to user's instructions and write it back
atomically as well.
Reviewed-by: Kent Gibson <warthog618@gmail.com>
Link: https://lore.kernel.org/r/20241004-gpio-notify-in-kernel-events-v1-3-8ac29e1df4fe@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-cdev.c')
-rw-r--r-- | drivers/gpio/gpiolib-cdev.c | 80 |
1 files changed, 44 insertions, 36 deletions
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 6113a283c34a..b0050250ac3a 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -143,18 +143,22 @@ static int linehandle_validate_flags(u32 flags) static void linehandle_flags_to_desc_flags(u32 lflags, unsigned long *flagsp) { - assign_bit(FLAG_ACTIVE_LOW, flagsp, + unsigned long flags = READ_ONCE(*flagsp); + + assign_bit(FLAG_ACTIVE_LOW, &flags, lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); - assign_bit(FLAG_OPEN_DRAIN, flagsp, + assign_bit(FLAG_OPEN_DRAIN, &flags, lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); - assign_bit(FLAG_OPEN_SOURCE, flagsp, + assign_bit(FLAG_OPEN_SOURCE, &flags, lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); - assign_bit(FLAG_PULL_UP, flagsp, + assign_bit(FLAG_PULL_UP, &flags, lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); - assign_bit(FLAG_PULL_DOWN, flagsp, + assign_bit(FLAG_PULL_DOWN, &flags, lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); - assign_bit(FLAG_BIAS_DISABLE, flagsp, + assign_bit(FLAG_BIAS_DISABLE, &flags, lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); + + WRITE_ONCE(*flagsp, flags); } static long linehandle_set_config(struct linehandle_state *lh, @@ -1348,38 +1352,42 @@ static int gpio_v2_line_config_validate(struct gpio_v2_line_config *lc, return 0; } -static void gpio_v2_line_config_flags_to_desc_flags(u64 flags, +static void gpio_v2_line_config_flags_to_desc_flags(u64 lflags, unsigned long *flagsp) { - assign_bit(FLAG_ACTIVE_LOW, flagsp, - flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW); - - if (flags & GPIO_V2_LINE_FLAG_OUTPUT) - set_bit(FLAG_IS_OUT, flagsp); - else if (flags & GPIO_V2_LINE_FLAG_INPUT) - clear_bit(FLAG_IS_OUT, flagsp); - - assign_bit(FLAG_EDGE_RISING, flagsp, - flags & GPIO_V2_LINE_FLAG_EDGE_RISING); - assign_bit(FLAG_EDGE_FALLING, flagsp, - flags & GPIO_V2_LINE_FLAG_EDGE_FALLING); - - assign_bit(FLAG_OPEN_DRAIN, flagsp, - flags & GPIO_V2_LINE_FLAG_OPEN_DRAIN); - assign_bit(FLAG_OPEN_SOURCE, flagsp, - flags & GPIO_V2_LINE_FLAG_OPEN_SOURCE); - - assign_bit(FLAG_PULL_UP, flagsp, - flags & GPIO_V2_LINE_FLAG_BIAS_PULL_UP); - assign_bit(FLAG_PULL_DOWN, flagsp, - flags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN); - assign_bit(FLAG_BIAS_DISABLE, flagsp, - flags & GPIO_V2_LINE_FLAG_BIAS_DISABLED); - - assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp, - flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME); - assign_bit(FLAG_EVENT_CLOCK_HTE, flagsp, - flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); + unsigned long flags = READ_ONCE(*flagsp); + + assign_bit(FLAG_ACTIVE_LOW, &flags, + lflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW); + + if (lflags & GPIO_V2_LINE_FLAG_OUTPUT) + set_bit(FLAG_IS_OUT, &flags); + else if (lflags & GPIO_V2_LINE_FLAG_INPUT) + clear_bit(FLAG_IS_OUT, &flags); + + assign_bit(FLAG_EDGE_RISING, &flags, + lflags & GPIO_V2_LINE_FLAG_EDGE_RISING); + assign_bit(FLAG_EDGE_FALLING, &flags, + lflags & GPIO_V2_LINE_FLAG_EDGE_FALLING); + + assign_bit(FLAG_OPEN_DRAIN, &flags, + lflags & GPIO_V2_LINE_FLAG_OPEN_DRAIN); + assign_bit(FLAG_OPEN_SOURCE, &flags, + lflags & GPIO_V2_LINE_FLAG_OPEN_SOURCE); + + assign_bit(FLAG_PULL_UP, &flags, + lflags & GPIO_V2_LINE_FLAG_BIAS_PULL_UP); + assign_bit(FLAG_PULL_DOWN, &flags, + lflags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN); + assign_bit(FLAG_BIAS_DISABLE, &flags, + lflags & GPIO_V2_LINE_FLAG_BIAS_DISABLED); + + assign_bit(FLAG_EVENT_CLOCK_REALTIME, &flags, + lflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME); + assign_bit(FLAG_EVENT_CLOCK_HTE, &flags, + lflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); + + WRITE_ONCE(*flagsp, flags); } static long linereq_get_values(struct linereq *lr, void __user *ip) |