mirror of
https://github.com/torvalds/linux.git
synced 2026-01-24 23:16:46 +00:00
Merge tag 'gpio-fixes-for-v6.19-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio fixes from Bartosz Golaszewski:
"Some fixes to resource leaks in the character device handling and
another small fix for shared GPIO management:
- fix resource leaks in error paths in GPIO character device code
- return -ENOMEM and not -ENODEV on memory allocation failure
- fix an audio issue on Qualcomm platforms due to configuration not
being propagated to pinctrl from shared GPIO proxy"
* tag 'gpio-fixes-for-v6.19-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
gpio: shared: propagate configuration to pinctrl
gpio: cdev: Fix resource leaks on errors in gpiolib_cdev_register()
gpio: cdev: Fix resource leaks on errors in lineinfo_changed_notify()
gpio: cdev: Correct return code on memory allocation failure
This commit is contained in:
@@ -2549,6 +2549,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx) {
|
||||
pr_err("Failed to allocate memory for line info notification\n");
|
||||
fput(fp);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
@@ -2696,7 +2697,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
|
||||
|
||||
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
|
||||
if (!cdev)
|
||||
return -ENODEV;
|
||||
return -ENOMEM;
|
||||
|
||||
cdev->watched_lines = bitmap_zalloc(gdev->ngpio, GFP_KERNEL);
|
||||
if (!cdev->watched_lines)
|
||||
@@ -2796,13 +2797,18 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cdev_device_add(&gdev->chrdev, &gdev->dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
destroy_workqueue(gdev->line_state_wq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
guard(srcu)(&gdev->srcu);
|
||||
gc = srcu_dereference(gdev->chip, &gdev->srcu);
|
||||
if (!gc)
|
||||
if (!gc) {
|
||||
cdev_device_del(&gdev->chrdev, &gdev->dev);
|
||||
destroy_workqueue(gdev->line_state_wq);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpiochip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id);
|
||||
|
||||
|
||||
@@ -515,7 +515,7 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
struct gpio_shared_ref *ref;
|
||||
unsigned long *flags;
|
||||
struct gpio_desc *desc;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
@@ -543,15 +543,17 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||
if (list_count_nodes(&entry->refs) <= 1)
|
||||
continue;
|
||||
|
||||
flags = &gdev->descs[entry->offset].flags;
|
||||
desc = &gdev->descs[entry->offset];
|
||||
|
||||
__set_bit(GPIOD_FLAG_SHARED, flags);
|
||||
__set_bit(GPIOD_FLAG_SHARED, &desc->flags);
|
||||
/*
|
||||
* Shared GPIOs are not requested via the normal path. Make
|
||||
* them inaccessible to anyone even before we register the
|
||||
* chip.
|
||||
*/
|
||||
__set_bit(GPIOD_FLAG_REQUESTED, flags);
|
||||
ret = gpiod_request_commit(desc, "shared");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
|
||||
entry->offset, gpio_device_get_label(gdev));
|
||||
@@ -562,8 +564,10 @@ int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||
ref->con_id ?: "(none)");
|
||||
|
||||
ret = gpio_shared_make_adev(gdev, entry, ref);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
gpiod_free_commit(desc);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,6 +583,8 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
|
||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||
continue;
|
||||
|
||||
gpiod_free_commit(&gdev->descs[entry->offset]);
|
||||
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
guard(mutex)(&ref->lock);
|
||||
|
||||
|
||||
@@ -2453,7 +2453,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
|
||||
* on each other, and help provide better diagnostics in debugfs.
|
||||
* They're called even less than the "set direction" calls.
|
||||
*/
|
||||
static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
||||
int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
||||
{
|
||||
unsigned int offset;
|
||||
int ret;
|
||||
@@ -2515,7 +2515,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gpiod_free_commit(struct gpio_desc *desc)
|
||||
void gpiod_free_commit(struct gpio_desc *desc)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
@@ -244,7 +244,9 @@ DEFINE_CLASS(gpio_chip_guard,
|
||||
struct gpio_desc *desc)
|
||||
|
||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||
int gpiod_request_commit(struct gpio_desc *desc, const char *label);
|
||||
void gpiod_free(struct gpio_desc *desc);
|
||||
void gpiod_free_commit(struct gpio_desc *desc);
|
||||
|
||||
static inline int gpiod_request_user(struct gpio_desc *desc, const char *label)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user