gpio fixes for v7.1-rc6

- fix interrupt handling in gpio-mxc
 - fix scoped_guard() usage in gpio-adnp
 - don't accept partial writes in gpio-virtuser debugfs interface as they
   can't really work correctly
 - fix resource leaks in gpio-rockchip
 - fix locking issues in remove path in shared GPIO management
 - undo the vote of a GPIO shared proxy virtual device on GPIO release
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmoYQrwACgkQBZ0uy/82
 hMOLoA/+L86ir6t3Q5dzKk527gRRZY1xnBj3wVyD/6s3HMpAcbm7NUBLGxNNetJl
 YxYIQZPHI6NtFH3VpcKQSBx1ECaXhIhBFucWX/qEW7VToQS0+0KV+ys+xR8Tp7fP
 4qypSk7v8H1tR4yP0pDnzKUdYm8nA5pDGHwVv+VoV5SdwRVAIjZDL4yRy2/NhtWD
 qcWL9x0+lWgTt7gXLd3VGfKKbewsNyzDs5FBYaEUsPoYAj/AH4ezFSnNodc/5Ds+
 M3bv7bEef3WrYeL2zdSWF4wHy3ABqOtBW/o9F5hYUYVDhRc7ACArYj6ayhPQQRs0
 YtyYsnQZkFqu4lFvInQ+5quJfAhxJmWq+fQZbPidXeR+KlDk8N22L4jwWsabEuPj
 rNI8ijUo88h5VkU7ARstXWCQCZWcxibMS+zPaX0TqV5LhvRZPpuHPbpzACL1HOSr
 LiFI9npnJNsHkQ7mBhVIrUtbUd+CO549/KIarN7ldX4svwSOGN1lWF3041hRkPXO
 WGj13ledyw8WdbcqWIqTXKt3po0ILcM/nOfI+vqVqqOLVB2m7sJfdGMR8WQwX2GV
 g3xdPHAP270LAwkDRbwgYmeAFaiVLLTRV/hag5R6MIdL51pCJC67dB6eUNTqUCmB
 U2wepAFXRn0HB3XYf9Wmzzh8QbzUTVkqpnjujBq0sVmKvF5zMCE=
 =hkRD
 -----END PGP SIGNATURE-----

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

Pull gpio fixes from Bartosz Golaszewski:

 - fix interrupt handling in gpio-mxc

 - fix scoped_guard() usage in gpio-adnp

 - don't accept partial writes in gpio-virtuser debugfs interface as
   they can't really work correctly

 - fix resource leaks in gpio-rockchip

 - fix locking issues in remove path in shared GPIO management

 - undo the vote of a GPIO shared proxy virtual device on GPIO release

* tag 'gpio-fixes-for-v7.1-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpio: rockchip: teardown bugs and resource leaks
  gpio: rockchip: convert bank->clk to devm_clk_get_enabled()
  gpio: virtuser: Fix uninitialized data bug in gpio_virtuser_direction_do_write()
  gpio: shared: fix lockdep false positive by removing unneeded lock
  gpio: shared: fix deadlock on shared proxy's parent removal
  gpio: adnp: fix flow control regression caused by scoped_guard()
  gpio: shared: undo the vote of the proxy on GPIO free
  gpio: mxc: fix irq_high handling
This commit is contained in:
Linus Torvalds 2026-05-28 12:36:39 -07:00
commit b0f908d785
6 changed files with 35 additions and 16 deletions

View File

@ -237,7 +237,9 @@ static irqreturn_t adnp_irq(int irq, void *data)
unsigned long pending;
int err;
scoped_guard(mutex, &adnp->i2c_lock) {
{
guard(mutex)(&adnp->i2c_lock);
err = adnp_read(adnp, GPIO_PLR(adnp) + i, &level);
if (err < 0)
continue;

View File

@ -469,7 +469,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
* the handler is needed only once, but doing it for every port
* is more robust and easier.
*/
port->irq_high = -1;
port->irq_high = 0;
port->mx_irq_handler = mx2_gpio_irq_handler;
} else
port->mx_irq_handler = mx3_gpio_irq_handler;

View File

@ -638,10 +638,17 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank)
return ret;
}
static void rockchip_clk_put(void *data)
{
struct clk *clk = data;
clk_put(clk);
}
static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
{
struct resource res;
int id = 0;
int id = 0, ret;
if (of_address_to_resource(bank->of_node, 0, &res)) {
dev_err(bank->dev, "cannot find IO resource for bank\n");
@ -656,11 +663,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
if (!bank->irq)
return -EINVAL;
bank->clk = of_clk_get(bank->of_node, 0);
bank->clk = devm_clk_get_enabled(bank->dev, NULL);
if (IS_ERR(bank->clk))
return PTR_ERR(bank->clk);
clk_prepare_enable(bank->clk);
id = readl(bank->reg_base + gpio_regs_v2.version_id);
switch (id) {
@ -672,9 +678,13 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
bank->db_clk = of_clk_get(bank->of_node, 1);
if (IS_ERR(bank->db_clk)) {
dev_err(bank->dev, "cannot find debounce clk\n");
clk_disable_unprepare(bank->clk);
return -EINVAL;
}
ret = devm_add_action_or_reset(bank->dev, rockchip_clk_put,
bank->db_clk);
if (ret)
return ret;
break;
case GPIO_TYPE_V1:
bank->gpio_regs = &gpio_regs_v1;
@ -751,7 +761,6 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
ret = rockchip_gpiolib_register(bank);
if (ret) {
clk_disable_unprepare(bank->clk);
mutex_unlock(&bank->deferred_lock);
return ret;
}
@ -792,7 +801,9 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
{
struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
clk_disable_unprepare(bank->clk);
irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
if (bank->domain)
irq_domain_remove(bank->domain);
gpiochip_remove(&bank->gpio_chip);
}

View File

@ -103,9 +103,18 @@ static void gpio_shared_proxy_free(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
int ret;
guard(gpio_shared_desc_lock)(shared_desc);
if (proxy->voted_high) {
ret = gpio_shared_proxy_set_unlocked(proxy,
shared_desc->can_sleep ? gpiod_set_value_cansleep : gpiod_set_value, 0);
if (ret)
dev_err(proxy->dev,
"Failed to unset the shared GPIO value on release: %d\n", ret);
}
proxy->shared_desc->usecnt--;
dev_dbg(proxy->dev, "Shared GPIO freed, number of users: %u\n",

View File

@ -397,7 +397,7 @@ static ssize_t gpio_virtuser_direction_do_write(struct file *file,
char buf[32], *trimmed;
int ret, dir, val = 0;
if (count >= sizeof(buf))
if (*ppos != 0 || count >= sizeof(buf))
return -EINVAL;
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
@ -622,7 +622,7 @@ static ssize_t gpio_virtuser_consumer_write(struct file *file,
char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2];
int ret;
if (count >= sizeof(buf))
if (*ppos != 0 || count >= sizeof(buf))
return -EINVAL;
ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos,

View File

@ -53,7 +53,7 @@ struct gpio_shared_entry {
unsigned int offset;
/* Index in the property value array. */
size_t index;
/* Synchronizes the modification of shared_desc. */
/* Synchronizes the modification of shared_desc and offset. */
struct mutex lock;
struct gpio_shared_desc *shared_desc;
struct kref ref;
@ -598,16 +598,13 @@ void gpio_device_teardown_shared(struct gpio_device *gdev)
struct gpio_shared_ref *ref;
list_for_each_entry(entry, &gpio_shared_list, list) {
guard(mutex)(&entry->lock);
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
continue;
gpiod_free_commit(&gdev->descs[entry->offset]);
scoped_guard(mutex, &entry->lock)
gpiod_free_commit(&gdev->descs[entry->offset]);
list_for_each_entry(ref, &entry->refs, list) {
guard(mutex)(&ref->lock);
if (ref->lookup) {
gpiod_remove_lookup_table(ref->lookup);
kfree(ref->lookup->table[0].key);