Commit 1f664bbd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 6e49f9e0 4918cc05
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -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);

+11 −5
Original line number Diff line number Diff line
@@ -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,10 +564,12 @@ 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;
			}
		}
	}

	return 0;
}
@@ -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);

+2 −2
Original line number Diff line number Diff line
@@ -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;

+2 −0
Original line number Diff line number Diff line
@@ -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)
{