Commit 1222390d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'gpio-fixes-for-v6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:

 - protect gpio-aggregator against module unload

 - use raw spinlock in gpio-rcar to fix a lockdep splat

 - fix OF node leak in gpio-rcar

* tag 'gpio-fixes-for-v6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: rcar: Fix missing of_node_put() call
  gpio: rcar: Use raw_spinlock to protect register access
  gpio: aggregator: protect driver attr handlers against module unload
parents 8aed61b8 391b41f9
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -119,10 +119,15 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf,
	struct platform_device *pdev;
	int res, id;

	if (!try_module_get(THIS_MODULE))
		return -ENOENT;

	/* kernfs guarantees string termination, so count + 1 is safe */
	aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL);
	if (!aggr)
		return -ENOMEM;
	if (!aggr) {
		res = -ENOMEM;
		goto put_module;
	}

	memcpy(aggr->args, buf, count + 1);

@@ -161,6 +166,7 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf,
	}

	aggr->pdev = pdev;
	module_put(THIS_MODULE);
	return count;

remove_table:
@@ -175,6 +181,8 @@ static ssize_t new_device_store(struct device_driver *driver, const char *buf,
	kfree(aggr->lookups);
free_ga:
	kfree(aggr);
put_module:
	module_put(THIS_MODULE);
	return res;
}

@@ -203,13 +211,19 @@ static ssize_t delete_device_store(struct device_driver *driver,
	if (error)
		return error;

	if (!try_module_get(THIS_MODULE))
		return -ENOENT;

	mutex_lock(&gpio_aggregator_lock);
	aggr = idr_remove(&gpio_aggregator_idr, id);
	mutex_unlock(&gpio_aggregator_lock);
	if (!aggr)
	if (!aggr) {
		module_put(THIS_MODULE);
		return -ENOENT;
	}

	gpio_aggregator_free(aggr);
	module_put(THIS_MODULE);
	return count;
}
static DRIVER_ATTR_WO(delete_device);
+18 −13
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ struct gpio_rcar_info {

struct gpio_rcar_priv {
	void __iomem *base;
	spinlock_t lock;
	raw_spinlock_t lock;
	struct device *dev;
	struct gpio_chip gpio_chip;
	unsigned int irq_parent;
@@ -123,7 +123,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
	 * "Setting Level-Sensitive Interrupt Input Mode"
	 */

	spin_lock_irqsave(&p->lock, flags);
	raw_spin_lock_irqsave(&p->lock, flags);

	/* Configure positive or negative logic in POSNEG */
	gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
@@ -142,7 +142,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
	if (!level_trigger)
		gpio_rcar_write(p, INTCLR, BIT(hwirq));

	spin_unlock_irqrestore(&p->lock, flags);
	raw_spin_unlock_irqrestore(&p->lock, flags);
}

static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
@@ -246,7 +246,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
	 * "Setting General Input Mode"
	 */

	spin_lock_irqsave(&p->lock, flags);
	raw_spin_lock_irqsave(&p->lock, flags);

	/* Configure positive logic in POSNEG */
	gpio_rcar_modify_bit(p, POSNEG, gpio, false);
@@ -261,7 +261,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
	if (p->info.has_outdtsel && output)
		gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);

	spin_unlock_irqrestore(&p->lock, flags);
	raw_spin_unlock_irqrestore(&p->lock, flags);
}

static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
@@ -347,7 +347,7 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
		return 0;
	}

	spin_lock_irqsave(&p->lock, flags);
	raw_spin_lock_irqsave(&p->lock, flags);
	outputs = gpio_rcar_read(p, INOUTSEL);
	m = outputs & bankmask;
	if (m)
@@ -356,7 +356,7 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
	m = ~outputs & bankmask;
	if (m)
		val |= gpio_rcar_read(p, INDT) & m;
	spin_unlock_irqrestore(&p->lock, flags);
	raw_spin_unlock_irqrestore(&p->lock, flags);

	bits[0] = val;
	return 0;
@@ -367,9 +367,9 @@ static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
	struct gpio_rcar_priv *p = gpiochip_get_data(chip);
	unsigned long flags;

	spin_lock_irqsave(&p->lock, flags);
	raw_spin_lock_irqsave(&p->lock, flags);
	gpio_rcar_modify_bit(p, OUTDT, offset, value);
	spin_unlock_irqrestore(&p->lock, flags);
	raw_spin_unlock_irqrestore(&p->lock, flags);
}

static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
@@ -386,12 +386,12 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
	if (!bankmask)
		return;

	spin_lock_irqsave(&p->lock, flags);
	raw_spin_lock_irqsave(&p->lock, flags);
	val = gpio_rcar_read(p, OUTDT);
	val &= ~bankmask;
	val |= (bankmask & bits[0]);
	gpio_rcar_write(p, OUTDT, val);
	spin_unlock_irqrestore(&p->lock, flags);
	raw_spin_unlock_irqrestore(&p->lock, flags);
}

static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
@@ -468,7 +468,12 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
	p->info = *info;

	ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
	*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
	if (ret) {
		*npins = RCAR_MAX_GPIO_PER_BANK;
	} else {
		*npins = args.args[2];
		of_node_put(args.np);
	}

	if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
		dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",
@@ -505,7 +510,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
		return -ENOMEM;

	p->dev = dev;
	spin_lock_init(&p->lock);
	raw_spin_lock_init(&p->lock);

	/* Get device configuration from DT node */
	ret = gpio_rcar_parse_dt(p, &npins);