mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 20:34:23 -04:00
Merge tag 'gpio-fixes-for-v6.14-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio fixes from Bartosz Golaszewski:
"The first fix is a backport from my v6.15-rc1 queue that turned out to
be needed in v6.14 as well but as the former diverged from my fixes
branch I had to adjust the patch a bit.
The second one fixes a regression observed in user-space where closing
a file descriptor associated with a GPIO device results in a ~10ms
delay due to the atomic notifier calling rcu_synchronize() when
unregistering.
Summary:
- don't check the return value of gpio_chip::get_direction() when
registering a GPIO chip
- use raw notifier for line state events"
* tag 'gpio-fixes-for-v6.14-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
gpio: cdev: use raw notifier for line state events
gpiolib: don't check the retval of get_direction() when registering a chip
This commit is contained in:
@@ -2729,8 +2729,9 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
|
||||
cdev->gdev = gpio_device_get(gdev);
|
||||
|
||||
cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
|
||||
ret = atomic_notifier_chain_register(&gdev->line_state_notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
scoped_guard(write_lock_irqsave, &gdev->line_state_lock)
|
||||
ret = raw_notifier_chain_register(&gdev->line_state_notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
if (ret)
|
||||
goto out_free_bitmap;
|
||||
|
||||
@@ -2754,8 +2755,9 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
|
||||
blocking_notifier_chain_unregister(&gdev->device_notifier,
|
||||
&cdev->device_unregistered_nb);
|
||||
out_unregister_line_notifier:
|
||||
atomic_notifier_chain_unregister(&gdev->line_state_notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
scoped_guard(write_lock_irqsave, &gdev->line_state_lock)
|
||||
raw_notifier_chain_unregister(&gdev->line_state_notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
out_free_bitmap:
|
||||
gpio_device_put(gdev);
|
||||
bitmap_free(cdev->watched_lines);
|
||||
@@ -2779,8 +2781,9 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file)
|
||||
|
||||
blocking_notifier_chain_unregister(&gdev->device_notifier,
|
||||
&cdev->device_unregistered_nb);
|
||||
atomic_notifier_chain_unregister(&gdev->line_state_notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
scoped_guard(write_lock_irqsave, &gdev->line_state_lock)
|
||||
raw_notifier_chain_unregister(&gdev->line_state_notifier,
|
||||
&cdev->lineinfo_changed_nb);
|
||||
bitmap_free(cdev->watched_lines);
|
||||
gpio_device_put(gdev);
|
||||
kfree(cdev);
|
||||
|
||||
@@ -1025,7 +1025,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
|
||||
rwlock_init(&gdev->line_state_lock);
|
||||
RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
|
||||
|
||||
ret = init_srcu_struct(&gdev->srcu);
|
||||
@@ -1056,24 +1057,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||
|
||||
desc->gdev = gdev;
|
||||
|
||||
if (gc->get_direction && gpiochip_line_is_valid(gc, desc_index)) {
|
||||
ret = gc->get_direction(gc, desc_index);
|
||||
if (ret < 0)
|
||||
/*
|
||||
* FIXME: Bail-out here once all GPIO drivers
|
||||
* are updated to not return errors in
|
||||
* situations that can be considered normal
|
||||
* operation.
|
||||
*/
|
||||
dev_warn(&gdev->dev,
|
||||
"%s: get_direction failed: %d\n",
|
||||
__func__, ret);
|
||||
|
||||
assign_bit(FLAG_IS_OUT, &desc->flags, !ret);
|
||||
} else {
|
||||
/*
|
||||
* We would typically want to check the return value of
|
||||
* get_direction() here but we must not check the return value
|
||||
* and bail-out as pin controllers can have pins configured to
|
||||
* alternate functions and return -EINVAL. Also: there's no
|
||||
* need to take the SRCU lock here.
|
||||
*/
|
||||
if (gc->get_direction && gpiochip_line_is_valid(gc, desc_index))
|
||||
assign_bit(FLAG_IS_OUT, &desc->flags,
|
||||
!gc->get_direction(gc, desc_index));
|
||||
else
|
||||
assign_bit(FLAG_IS_OUT,
|
||||
&desc->flags, !gc->direction_input);
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_gpiochip_add(gc);
|
||||
@@ -4193,8 +4189,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
|
||||
|
||||
void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action)
|
||||
{
|
||||
atomic_notifier_call_chain(&desc->gdev->line_state_notifier,
|
||||
action, desc);
|
||||
guard(read_lock_irqsave)(&desc->gdev->line_state_lock);
|
||||
|
||||
raw_notifier_call_chain(&desc->gdev->line_state_notifier, action, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/srcu.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
@@ -45,6 +46,7 @@
|
||||
* @list: links gpio_device:s together for traversal
|
||||
* @line_state_notifier: used to notify subscribers about lines being
|
||||
* requested, released or reconfigured
|
||||
* @line_state_lock: RW-spinlock protecting the line state notifier
|
||||
* @line_state_wq: used to emit line state events from a separate thread in
|
||||
* process context
|
||||
* @device_notifier: used to notify character device wait queues about the GPIO
|
||||
@@ -72,7 +74,8 @@ struct gpio_device {
|
||||
const char *label;
|
||||
void *data;
|
||||
struct list_head list;
|
||||
struct atomic_notifier_head line_state_notifier;
|
||||
struct raw_notifier_head line_state_notifier;
|
||||
rwlock_t line_state_lock;
|
||||
struct workqueue_struct *line_state_wq;
|
||||
struct blocking_notifier_head device_notifier;
|
||||
struct srcu_struct srcu;
|
||||
|
||||
Reference in New Issue
Block a user