diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-18 05:07:20 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-18 05:07:20 +0300 |
commit | a409ed156a90093a03fe6a93721ddf4c591eac87 (patch) | |
tree | 2a3c6f6f81c8b233627cf14da7149c7f312b475e /drivers/gpio/gpiolib-cdev.c | |
parent | 345b17acb1aa7a443741d9220f66b30d5ddd7c39 (diff) | |
parent | 7ac554888233468a9fd7c4f28721396952dd9959 (diff) | |
download | linux-a409ed156a90093a03fe6a93721ddf4c591eac87.tar.xz |
Merge tag 'gpio-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij:
"This is the bulk of the GPIO changes for the v5.11 kernel cycle:
Core changes:
- Retired the old set-up function for GPIO IRQ chips. All chips now
use the template struct gpio_irq_chip and pass that to the core to
be set up alongside the gpio_chip. We can finally get rid of the
old cruft.
- Some refactoring and clean up of the core code.
- Support edge event timestamps to be stamped using REALTIME (wall
clock) timestamps. We have found solid use cases for this, so we
support it.
New drivers:
- MStar MSC313 GPIO driver.
- HiSilicon GPIO driver.
Driver improvements:
- The PCA953x driver now also supports the NXP PCAL9554B/C chips.
- The mockup driver can now be probed from the device tree which is
pretty useful for virtual prototyping of devices.
- The Rcar driver now supports .get_multiple()
- The MXC driver dropped some legacy and became a pure device tree
client.
- The Exar driver was moved over to the IDA interface for
enumerating, and also switched over to using regmap for register
access"
* tag 'gpio-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (87 commits)
MAINTAINERS: Remove reference to non-existing file
gpio: hisi: Do not require ACPI for COMPILE_TEST
MAINTAINERS: Add maintainer for HiSilicon GPIO driver
gpio: gpio-hisi: Add HiSilicon GPIO support
gpio: cs5535: Simplify the return expression of cs5535_gpio_probe()
gpiolib: irq hooks: fix recursion in gpiochip_irq_unmask
dt-bindings: mt7621-gpio: convert bindings to YAML format
gpiolib: cdev: Flag invalid GPIOs as used
gpio: put virtual gpio device into their own submenu
drivers: gpio: amd8111: use SPDX-License-Identifier
drivers: gpio: amd8111: prefer dev_err()/dev_info() over raw printk
drivers: gpio: bt8xx: prefer dev_err()/dev_warn() over of raw printk
gpio: Add TODO item for debugfs interface
gpio: just plain warning when nonexisting gpio requested
tools: gpio: add option to report wall-clock time to gpio-event-mon
tools: gpio: add support for reporting realtime event clock to lsgpio
gpiolib: cdev: allow edge event timestamps to be configured as REALTIME
gpio: msc313: MStar MSC313 GPIO driver
dt-bindings: gpio: Binding for MStar MSC313 GPIO controller
dt-bindings: gpio: Add a binding header for the MSC313 GPIO driver
...
Diffstat (limited to 'drivers/gpio/gpiolib-cdev.c')
-rw-r--r-- | drivers/gpio/gpiolib-cdev.c | 79 |
1 files changed, 49 insertions, 30 deletions
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index e9faeaf65d14..12b679ca552c 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -428,6 +428,12 @@ struct line { */ struct linereq *req; unsigned int irq; + /* + * eflags is set by edge_detector_setup(), edge_detector_stop() and + * edge_detector_update(), which are themselves mutually exclusive, + * and is accessed by edge_irq_thread() and debounce_work_func(), + * which can both live with a slightly stale value. + */ u64 eflags; /* * timestamp_ns and req_seqno are accessed only by @@ -504,11 +510,14 @@ struct linereq { (GPIO_V2_LINE_FLAG_EDGE_RISING | \ GPIO_V2_LINE_FLAG_EDGE_FALLING) +#define GPIO_V2_LINE_FLAG_EDGE_BOTH GPIO_V2_LINE_EDGE_FLAGS + #define GPIO_V2_LINE_VALID_FLAGS \ (GPIO_V2_LINE_FLAG_ACTIVE_LOW | \ GPIO_V2_LINE_DIRECTION_FLAGS | \ GPIO_V2_LINE_DRIVE_FLAGS | \ GPIO_V2_LINE_EDGE_FLAGS | \ + GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \ GPIO_V2_LINE_BIAS_FLAGS) static void linereq_put_event(struct linereq *lr, @@ -529,11 +538,20 @@ static void linereq_put_event(struct linereq *lr, pr_debug_ratelimited("event FIFO is full - event dropped\n"); } +static u64 line_event_timestamp(struct line *line) +{ + if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags)) + return ktime_get_real_ns(); + + return ktime_get_ns(); +} + static irqreturn_t edge_irq_thread(int irq, void *p) { struct line *line = p; struct linereq *lr = line->req; struct gpio_v2_line_event le; + u64 eflags; /* Do not leak kernel stack to userspace */ memset(&le, 0, sizeof(le)); @@ -546,14 +564,14 @@ static irqreturn_t edge_irq_thread(int irq, void *p) * which case we didn't get the timestamp from * edge_irq_handler(). */ - le.timestamp_ns = ktime_get_ns(); + le.timestamp_ns = line_event_timestamp(line); if (lr->num_lines != 1) line->req_seqno = atomic_inc_return(&lr->seqno); } line->timestamp_ns = 0; - if (line->eflags == (GPIO_V2_LINE_FLAG_EDGE_RISING | - GPIO_V2_LINE_FLAG_EDGE_FALLING)) { + eflags = READ_ONCE(line->eflags); + if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) { int level = gpiod_get_value_cansleep(line->desc); if (level) @@ -562,10 +580,10 @@ static irqreturn_t edge_irq_thread(int irq, void *p) else /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; - } else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) { + } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) { /* Emit low-to-high event */ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; - } else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) { + } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) { /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; } else { @@ -590,7 +608,7 @@ static irqreturn_t edge_irq_handler(int irq, void *p) * Just store the timestamp in hardirq context so we get it as * close in time as possible to the actual event. */ - line->timestamp_ns = ktime_get_ns(); + line->timestamp_ns = line_event_timestamp(line); if (lr->num_lines != 1) line->req_seqno = atomic_inc_return(&lr->seqno); @@ -634,6 +652,7 @@ static void debounce_work_func(struct work_struct *work) struct line *line = container_of(work, struct line, work.work); struct linereq *lr; int level; + u64 eflags; level = gpiod_get_raw_value_cansleep(line->desc); if (level < 0) { @@ -647,7 +666,8 @@ static void debounce_work_func(struct work_struct *work) WRITE_ONCE(line->level, level); /* -- edge detection -- */ - if (!line->eflags) + eflags = READ_ONCE(line->eflags); + if (!eflags) return; /* switch from physical level to logical - if they differ */ @@ -655,15 +675,15 @@ static void debounce_work_func(struct work_struct *work) level = !level; /* ignore edges that are not being monitored */ - if (((line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) || - ((line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level)) + if (((eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) || + ((eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level)) return; /* Do not leak kernel stack to userspace */ memset(&le, 0, sizeof(le)); lr = line->req; - le.timestamp_ns = ktime_get_ns(); + le.timestamp_ns = line_event_timestamp(line); le.offset = gpio_chip_hwgpio(line->desc); line->line_seqno++; le.line_seqno = line->line_seqno; @@ -755,7 +775,7 @@ static void edge_detector_stop(struct line *line) cancel_delayed_work_sync(&line->work); WRITE_ONCE(line->sw_debounced, 0); - line->eflags = 0; + WRITE_ONCE(line->eflags, 0); /* do not change line->level - see comment in debounced_value() */ } @@ -774,7 +794,7 @@ static int edge_detector_setup(struct line *line, if (ret) return ret; } - line->eflags = eflags; + WRITE_ONCE(line->eflags, eflags); if (gpio_v2_line_config_debounced(lc, line_idx)) { debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx); ret = debounce_setup(line, debounce_period_us); @@ -817,13 +837,13 @@ static int edge_detector_update(struct line *line, unsigned int debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx); - if ((line->eflags == eflags) && !polarity_change && + if ((READ_ONCE(line->eflags) == eflags) && !polarity_change && (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) return 0; /* sw debounced and still will be...*/ if (debounce_period_us && READ_ONCE(line->sw_debounced)) { - line->eflags = eflags; + WRITE_ONCE(line->eflags, eflags); WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); return 0; } @@ -967,6 +987,9 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 flags, 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); } static long linereq_get_values(struct linereq *lr, void __user *ip) @@ -1479,21 +1502,10 @@ static __poll_t lineevent_poll(struct file *file, return events; } -static ssize_t lineevent_get_size(void) -{ -#if defined(CONFIG_X86_64) && !defined(CONFIG_UML) - /* i386 has no padding after 'id' */ - if (in_ia32_syscall()) { - struct compat_gpioeevent_data { - compat_u64 timestamp; - u32 id; - }; - - return sizeof(struct compat_gpioeevent_data); - } -#endif - return sizeof(struct gpioevent_data); -} +struct compat_gpioeevent_data { + compat_u64 timestamp; + u32 id; +}; static ssize_t lineevent_read(struct file *file, char __user *buf, @@ -1515,7 +1527,10 @@ static ssize_t lineevent_read(struct file *file, * actual sizeof() and pass this as an argument to copy_to_user() to * drop unneeded bytes from the output. */ - ge_size = lineevent_get_size(); + if (compat_need_64bit_alignment_fixup()) + ge_size = sizeof(struct compat_gpioeevent_data); + else + ge_size = sizeof(struct gpioevent_data); if (count < ge_size) return -EINVAL; @@ -1910,6 +1925,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, test_bit(FLAG_USED_AS_IRQ, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags) || test_bit(FLAG_SYSFS, &desc->flags) || + !gpiochip_line_is_valid(gc, info->offset) || !ok_for_pinctrl) info->flags |= GPIO_V2_LINE_FLAG_USED; @@ -1938,6 +1954,9 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, if (test_bit(FLAG_EDGE_FALLING, &desc->flags)) info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; + if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags)) + info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME; + debounce_period_us = READ_ONCE(desc->debounce_period_us); if (debounce_period_us) { info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; |