FAILED: patch "[PATCH] gpio: tegra: do not call pinctrl for GPIO direction" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x d3e91a95b2b0fc6336dbf3ec90d831a1654d2720
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026072048-grudge-mongoose-71aa@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From d3e91a95b2b0fc6336dbf3ec90d831a1654d2720 Mon Sep 17 00:00:00 2001
From: Runyu Xiao <[email protected]>
Date: Fri, 19 Jun 2026 23:24:39 +0800
Subject: [PATCH] gpio: tegra: do not call pinctrl for GPIO direction
tegra_gpio_direction_input() and tegra_gpio_direction_output() already program the GPIO controller direction registers directly. The additional pinctrl_gpio_direction_input/output() calls do not add a Tegra pinctrl operation, because the Tegra pinmux ops provide GPIO request/free handling but no gpio_set_direction hook.
The extra call still enters the pinctrl core and takes pctldev->mutex. Shared GPIO users can call the direction path while holding their per-line spinlock, so this otherwise redundant pinctrl direction call can sleep in an atomic context.
This was found by our static analysis tool and then confirmed by manual review of tegra_gpio_probe(), the Tegra GPIO direction callbacks and the Tegra pinctrl ops. The reviewed path has a default non-sleeping struct gpio_chip while the direction callback still enters the pinctrl mutex path.
A directed runtime validation kept the same non-sleeping chip registration and drove:
gpio_shared_proxy_direction_output()
gpiod_direction_output_raw_commit()
tegra_gpio_direction_output()
pinctrl_gpio_direction_output()
Lockdep reported a sleep-in-atomic warning with the shared GPIO spinlock held and pinctrl_get_device_gpio_range() plus tegra_gpio_direction_output() on the stack.
Do not mark the whole chip as can_sleep to paper over this: can_sleep describes whether get()/set() may sleep, and Tegra value access is MMIO. Remove the redundant pinctrl direction calls and keep pinctrl involvement in the existing request/free path.
drivers/gpio/gpio-tegra.c +2 -16
@@ -172,18 +172,11 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) {struct tegra_gpio_info *tgi =gpiochip_get_data (chip); -int ret;tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,0 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_input (chip, offset); -if (ret <0 ) -dev_err (tgi->dev, -"Failed to set pinctrl input direction of GPIO %d: %d" , - chip->base + offset, ret); - -return ret; +return 0 ; } static int tegra_gpio_direction_output(struct gpio_chip *chip,
@@ -191,19 +184,12 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, int value) {struct tegra_gpio_info *tgi =gpiochip_get_data (chip); -int ret;tegra_gpio_set (chip, offset, value);tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,1 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_output (chip, offset); -if (ret <0 ) -dev_err (tgi->dev, -"Failed to set pinctrl output direction of GPIO %d: %d" , - chip->base + offset, ret); - -return ret; +return 0 ; } static int tegra_gpio_get_direction(struct gpio_chip *chip,
Sasha Levin
maintainerPATCH 1/2 treewide: rename pinctrl_gpio_direction_output_new()
From: Bartosz Golaszewski <[email protected]>
[ Upstream commit b679d6c06b2b29187374f9f4da7eea1961c2eeaa ]
Now that pinctrl_gpio_direction_output() is no longer used, let's drop the '_new' suffix from its improved variant.
Stable-dep-of: d3e91a95b2b0 ("gpio: tegra: do not call pinctrl for GPIO direction")
--- drivers/gpio/gpio-mvebu.c | 4 ++-- drivers/gpio/gpio-pxa.c | 4 ++-- drivers/gpio/gpio-rockchip.c | 4 ++-- drivers/gpio/gpio-tegra.c | 4 ++-- drivers/gpio/gpio-vf610.c | 4 ++-- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 4 ++-- drivers/pinctrl/cirrus/pinctrl-lochnagar.c | 2 +- drivers/pinctrl/core.c | 15 +++++++++------ drivers/pinctrl/intel/pinctrl-cherryview.c | 4 ++-- drivers/pinctrl/intel/pinctrl-intel.c | 4 ++-- drivers/pinctrl/intel/pinctrl-lynxpoint.c | 4 ++-- drivers/pinctrl/mediatek/pinctrl-moore.c | 4 ++-- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 4 ++-- drivers/pinctrl/mediatek/pinctrl-paris.c | 4 ++-- drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c | 4 ++-- drivers/pinctrl/pinctrl-as3722.c | 4 ++-- drivers/pinctrl/pinctrl-axp209.c | 2 +- drivers/pinctrl/pinctrl-ingenic.c | 11 ++++++++--- drivers/pinctrl/pinctrl-ocelot.c | 4 ++-- drivers/pinctrl/pinctrl-rk805.c | 4 ++-- drivers/pinctrl/pinctrl-st.c | 4 ++-- drivers/pinctrl/renesas/gpio.c | 4 ++-- drivers/pinctrl/stm32/pinctrl-stm32.c | 4 ++-- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 4 ++-- drivers/pinctrl/vt8500/pinctrl-wmt.c | 4 ++-- include/linux/pinctrl/consumer.h | 13 +++++++++---- 26 files changed, 70 insertions(+), 57 deletions(-)
drivers/gpio/gpio-mvebu.c +2 -2
@@ -348,7 +348,7 @@ static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)* Check with the pinctrl driver whether this pin is usable as * an input GPIO */ - ret =pinctrl_gpio_direction_input (chip->base + pin); + ret =pinctrl_gpio_direction_input (chip, pin);if (ret)return ret;
@@ -368,7 +368,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,* Check with the pinctrl driver whether this pin is usable as * an output GPIO */ - ret =pinctrl_gpio_direction_output (chip->base + pin); + ret =pinctrl_gpio_direction_output (chip, pin);if (ret)return ret;
drivers/gpio/gpio-pxa.c +2 -2
@@ -266,7 +266,7 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)int ret;if (pxa_gpio_has_pinctrl ()) { - ret =pinctrl_gpio_direction_input (chip->base + offset); + ret =pinctrl_gpio_direction_input (chip, offset);if (ret)return ret; }
@@ -295,7 +295,7 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,writel_relaxed (mask, base + (value ?GPSR_OFFSET :GPCR_OFFSET ));if (pxa_gpio_has_pinctrl ()) { - ret =pinctrl_gpio_direction_output (chip->base + offset); + ret =pinctrl_gpio_direction_output (chip, offset);if (ret)return ret; }
drivers/gpio/gpio-rockchip.c +2 -2
@@ -158,9 +158,9 @@ static int rockchip_gpio_set_direction(struct gpio_chip *chip,if (input) -pinctrl_gpio_direction_input (bank->pin_base + offset); +pinctrl_gpio_direction_input (chip, offset);else -pinctrl_gpio_direction_output (bank->pin_base + offset); +pinctrl_gpio_direction_output (chip, offset);raw_spin_lock_irqsave (&bank->slock, flags);rockchip_gpio_writel_bit (bank, offset, data, bank->gpio_regs->port_ddr);
drivers/gpio/gpio-tegra.c +2 -2
@@ -179,7 +179,7 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip,tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,0 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_input (chip->base + offset); + ret =pinctrl_gpio_direction_input (chip, offset);if (ret <0 ) dev_err(tgi->dev, "Failed to set pinctrl input direction of GPIO %d: %d",
@@ -199,7 +199,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip,tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,1 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_output (chip->base + offset); + ret =pinctrl_gpio_direction_output (chip, offset);if (ret <0 ) dev_err(tgi->dev, "Failed to set pinctrl output direction of GPIO %d: %d",
drivers/gpio/gpio-vf610.c +2 -2
@@ -117,7 +117,7 @@ static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)vf610_gpio_writel (val, port->gpio_base +GPIO_PDDR ); } -return pinctrl_gpio_direction_input (chip->base + gpio); +return pinctrl_gpio_direction_input (chip, gpio); } static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
@@ -135,7 +135,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,vf610_gpio_writel (val, port->gpio_base +GPIO_PDDR ); } -return pinctrl_gpio_direction_output (chip->base + gpio); +return pinctrl_gpio_direction_output (chip, gpio); }static void vf610_gpio_irq_handler (struct irq_desc *desc)
drivers/pinctrl/bcm/pinctrl-bcm2835.c +2 -2
@@ -312,7 +312,7 @@ static inline void bcm2835_pinctrl_fsel_set(static int bcm2835_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int bcm2835_gpio_get (struct gpio_chip *chip,unsigned offset)
@@ -348,7 +348,7 @@ static int bcm2835_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) {bcm2835_gpio_set (chip ,offset ,value ); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); } static int bcm2835_of_gpio_ranges_fallback(struct gpio_chip *gc,
drivers/pinctrl/cirrus/pinctrl-lochnagar.c +1 -1
@@ -1096,7 +1096,7 @@ static int lochnagar_gpio_direction_out(struct gpio_chip *chip, {lochnagar_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int lochnagar_fill_func_groups (struct lochnagar_pin_priv *priv)
drivers/pinctrl/core.c +9 -6
@@ -22,6 +22,7 @@#include <linux/list.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/gpio/driver.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/machine.h>
@@ -864,29 +865,31 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)/** * pinctrl_gpio_direction_input() - request a GPIO pin to go into input mode -* @gpio: the GPIO pin number from the GPIO subsystem number space +* @gc: GPIO chip structure from the GPIO subsystem +* @offset: hardware offset of the GPIO relative to the controller * * This function should *ONLY* be used from gpiolib-based GPIO drivers, * as part of their gpio_direction_input() semantics, platforms and individual * drivers shall *NOT* touch pin control GPIO calls. */ -int pinctrl_gpio_direction_input (unsigned gpio) +int pinctrl_gpio_direction_input (struct gpio_chip *gc,unsigned int offset) { -return pinctrl_gpio_direction (gpio, true); +return pinctrl_gpio_direction (gc->base + offset, true); }EXPORT_SYMBOL_GPL (pinctrl_gpio_direction_input);/** * pinctrl_gpio_direction_output() - request a GPIO pin to go into output mode -* @gpio: the GPIO pin number from the GPIO subsystem number space +* @gc: GPIO chip structure from the GPIO subsystem +* @offset: hardware offset of the GPIO relative to the controller * * This function should *ONLY* be used from gpiolib-based GPIO drivers, * as part of their gpio_direction_output() semantics, platforms and individual * drivers shall *NOT* touch pin control GPIO calls. */ -int pinctrl_gpio_direction_output (unsigned gpio) +int pinctrl_gpio_direction_output (struct gpio_chip *gc,unsigned int offset) { -return pinctrl_gpio_direction (gpio, false); +return pinctrl_gpio_direction (gc->base + offset, false); }EXPORT_SYMBOL_GPL (pinctrl_gpio_direction_output);
drivers/pinctrl/intel/pinctrl-cherryview.c +2 -2
@@ -1220,14 +1220,14 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)static int chv_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int chv_gpio_direction_output (struct gpio_chip *chip,unsigned int offset,int value) {chv_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip chv_gpio_chip = {
drivers/pinctrl/intel/pinctrl-intel.c +2 -2
@@ -1000,14 +1000,14 @@ static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)static int intel_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int intel_gpio_direction_output (struct gpio_chip *chip,unsigned int offset,int value) {intel_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip intel_gpio_chip = {
drivers/pinctrl/intel/pinctrl-lynxpoint.c +2 -2
@@ -614,7 +614,7 @@ static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)static int lp_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
@@ -622,7 +622,7 @@ static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, {lp_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int lp_gpio_get_direction (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/mediatek/pinctrl-moore.c +2 -2
@@ -471,7 +471,7 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)static int mtk_gpio_direction_input (struct gpio_chip *chip,unsigned int gpio) { -return pinctrl_gpio_direction_input (chip->base + gpio); +return pinctrl_gpio_direction_input (chip, gpio); } static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
@@ -479,7 +479,7 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, {mtk_gpio_set (chip, gpio, value); -return pinctrl_gpio_direction_output (chip->base + gpio); +return pinctrl_gpio_direction_output (chip, gpio); }static int mtk_gpio_to_irq (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/mediatek/pinctrl-mtk-common.c +2 -2
@@ -778,14 +778,14 @@ static const struct pinmux_ops mtk_pmx_ops = {static int mtk_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int mtk_gpio_direction_output (struct gpio_chip *chip,unsigned offset,int value) {mtk_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int mtk_gpio_get_direction (struct gpio_chip *chip,unsigned offset)
drivers/pinctrl/mediatek/pinctrl-paris.c +2 -2
@@ -786,7 +786,7 @@ static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)if (gpio >= hw->soc->npins)return -EINVAL ; -return pinctrl_gpio_direction_input (chip->base + gpio); +return pinctrl_gpio_direction_input (chip, gpio); } static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
@@ -799,7 +799,7 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,mtk_gpio_set (chip, gpio, value); -return pinctrl_gpio_direction_output (chip->base + gpio); +return pinctrl_gpio_direction_output (chip, gpio); }static int mtk_gpio_to_irq (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +2 -2
@@ -168,7 +168,7 @@ static int npcmgpio_direction_input(struct gpio_chip *chip, unsigned int offset)struct npcm7xx_gpio *bank =gpiochip_get_data (chip);int ret; - ret =pinctrl_gpio_direction_input (offset + chip->base); + ret =pinctrl_gpio_direction_input (chip, offset);if (ret)return ret;
@@ -185,7 +185,7 @@ static int npcmgpio_direction_output(struct gpio_chip *chip,dev_dbg (chip->parent,"gpio_direction_output: offset%d = %x\n" , offset, value); - ret =pinctrl_gpio_direction_output (offset + chip->base); + ret =pinctrl_gpio_direction_output (chip, offset);if (ret)return ret;
drivers/pinctrl/pinctrl-as3722.c +2 -2
@@ -514,14 +514,14 @@ static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,static int as3722_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int as3722_gpio_direction_output (struct gpio_chip *chip,unsigned offset,int value) {as3722_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int as3722_gpio_to_irq (struct gpio_chip *chip,unsigned offset)
drivers/pinctrl/pinctrl-axp209.c +1 -1
@@ -112,7 +112,7 @@ static int axp20x_gpio_get_reg(unsigned int offset)static int axp20x_gpio_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int axp20x_gpio_get (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/pinctrl-ingenic.c +8 -3
@@ -130,6 +130,8 @@ struct ingenic_pinctrl {struct pinctrl_pin_desc *pdesc;const struct ingenic_chip_info *info; + +struct gpio_chip *gc; };struct ingenic_gpio_chip {
@@ -3530,14 +3532,14 @@ static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)static int ingenic_gpio_direction_input (struct gpio_chip *gc,unsigned int offset) { -return pinctrl_gpio_direction_input (gc->base + offset); +return pinctrl_gpio_direction_input (gc, offset); }static int ingenic_gpio_direction_output (struct gpio_chip *gc,unsigned int offset,int value) {ingenic_gpio_set (gc, offset, value); -return pinctrl_gpio_direction_output (gc->base + offset); +return pinctrl_gpio_direction_output (gc, offset); } static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
@@ -3998,7 +4000,8 @@ static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,break ;case PIN_CONFIG_OUTPUT : - ret =pinctrl_gpio_direction_output (pin); + ret =pinctrl_gpio_direction_output (jzpc->gc, + pin - jzpc->gc->base);if (ret)return ret;
@@ -4118,6 +4121,8 @@ static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc,if (!jzgc)return -ENOMEM ; + jzpc->gc = &jzgc->gc; + jzgc->jzpc = jzpc; jzgc->reg_base = bank * jzpc->info->reg_offset;
drivers/pinctrl/pinctrl-ocelot.c +2 -2
@@ -1174,7 +1174,7 @@ static int ocelot_gpio_get_direction(struct gpio_chip *chip,static int ocelot_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int ocelot_gpio_direction_output(struct gpio_chip *chip,
@@ -1190,7 +1190,7 @@ static int ocelot_gpio_direction_output(struct gpio_chip *chip,regmap_write (info->map,REG (OCELOT_GPIO_OUT_CLR , info, offset), pin); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip ocelot_gpiolib_chip = {
drivers/pinctrl/pinctrl-rk805.c +2 -2
@@ -166,14 +166,14 @@ static void rk805_gpio_set(struct gpio_chip *chip,static int rk805_gpio_direction_input (struct gpio_chip *chip,unsigned int offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int rk805_gpio_direction_output (struct gpio_chip *chip,unsigned int offset,int value) {rk805_gpio_set (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static int rk805_gpio_get_direction (struct gpio_chip *chip,unsigned int offset)
drivers/pinctrl/pinctrl-st.c +2 -2
@@ -715,7 +715,7 @@ static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)static int st_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -pinctrl_gpio_direction_input (chip->base + offset); +pinctrl_gpio_direction_input (chip, offset);return 0 ; }
@@ -726,7 +726,7 @@ static int st_gpio_direction_output(struct gpio_chip *chip,struct st_gpio_bank *bank =gpiochip_get_data (chip);__st_gpio_set (bank, offset, value); -pinctrl_gpio_direction_output (chip->base + offset); +pinctrl_gpio_direction_output (chip, offset);return 0 ; }
drivers/pinctrl/renesas/gpio.c +2 -2
@@ -165,7 +165,7 @@ static void gpio_pin_set_value(struct sh_pfc_chip *chip, unsigned offset,static int gpio_pin_direction_input (struct gpio_chip *gc,unsigned offset) { -return pinctrl_gpio_direction_input (offset); +return pinctrl_gpio_direction_input (gc, offset); } static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
@@ -173,7 +173,7 @@ static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset, {gpio_pin_set_value (gpiochip_get_data (gc), offset, value); -return pinctrl_gpio_direction_output (offset); +return pinctrl_gpio_direction_output (gc, offset); }static int gpio_pin_get (struct gpio_chip *gc,unsigned offset)
drivers/pinctrl/stm32/pinctrl-stm32.c +2 -2
@@ -255,7 +255,7 @@ static void stm32_gpio_set(struct gpio_chip *chip, unsigned offset, int value)static int stm32_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); } static int stm32_gpio_direction_output(struct gpio_chip *chip,
@@ -264,7 +264,7 @@ static int stm32_gpio_direction_output(struct gpio_chip *chip,struct stm32_gpio_bank *bank =gpiochip_get_data (chip);__stm32_gpio_set (bank, offset, value); -pinctrl_gpio_direction_output (chip->base + offset); +pinctrl_gpio_direction_output (chip, offset);return 0 ; }
drivers/pinctrl/sunxi/pinctrl-sunxi.c +2 -2
@@ -850,7 +850,7 @@ static const struct pinmux_ops sunxi_pmx_ops = {static int sunxi_pinctrl_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int sunxi_pinctrl_gpio_get (struct gpio_chip *chip,unsigned offset)
@@ -901,7 +901,7 @@ static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) {sunxi_pinctrl_gpio_set (chip ,offset ,value ); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); } static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
drivers/pinctrl/vt8500/pinctrl-wmt.c +2 -2
@@ -528,14 +528,14 @@ static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,static int wmt_gpio_direction_input (struct gpio_chip *chip,unsigned offset) { -return pinctrl_gpio_direction_input (chip->base + offset); +return pinctrl_gpio_direction_input (chip, offset); }static int wmt_gpio_direction_output (struct gpio_chip *chip,unsigned offset,int value) {wmt_gpio_set_value (chip, offset, value); -return pinctrl_gpio_direction_output (chip->base + offset); +return pinctrl_gpio_direction_output (chip, offset); }static const struct gpio_chip wmt_gpio_chip = {
include/linux/pinctrl/consumer.h +9 -4
@@ -20,6 +20,7 @@struct pinctrl ;struct pinctrl_state ;struct device ; +struct gpio_chip ;#ifdef CONFIG_PINCTRL
@@ -27,8 +28,10 @@ struct device;extern bool pinctrl_gpio_can_use_line (unsigned gpio);extern int pinctrl_gpio_request (unsigned gpio);extern void pinctrl_gpio_free (unsigned gpio); -extern int pinctrl_gpio_direction_input (unsigned gpio); -extern int pinctrl_gpio_direction_output (unsigned gpio); +extern int pinctrl_gpio_direction_input (struct gpio_chip *gc, +unsigned int offset); +extern int pinctrl_gpio_direction_output (struct gpio_chip *gc, +unsigned int offset);extern int pinctrl_gpio_set_config (unsigned gpio,unsigned long config);extern struct pinctrl *__must_check pinctrl_get (struct device *dev);
@@ -77,12 +80,14 @@ static inline void pinctrl_gpio_free(unsigned gpio) { } -static inline int pinctrl_gpio_direction_input (unsigned gpio) +static inline int pinctrl_gpio_direction_input (struct gpio_chip *gc, +unsigned int offset) {return 0 ; } -static inline int pinctrl_gpio_direction_output (unsigned gpio) +static inline int pinctrl_gpio_direction_output (struct gpio_chip *gc, +unsigned int offset) {return 0 ; }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 gpio: tegra: do not call pinctrl for GPIO direction
From: Runyu Xiao <[email protected]>
[ Upstream commit d3e91a95b2b0fc6336dbf3ec90d831a1654d2720 ]
tegra_gpio_direction_input() and tegra_gpio_direction_output() already program the GPIO controller direction registers directly. The additional pinctrl_gpio_direction_input/output() calls do not add a Tegra pinctrl operation, because the Tegra pinmux ops provide GPIO request/free handling but no gpio_set_direction hook.
The extra call still enters the pinctrl core and takes pctldev->mutex. Shared GPIO users can call the direction path while holding their per-line spinlock, so this otherwise redundant pinctrl direction call can sleep in an atomic context.
This was found by our static analysis tool and then confirmed by manual review of tegra_gpio_probe(), the Tegra GPIO direction callbacks and the Tegra pinctrl ops. The reviewed path has a default non-sleeping struct gpio_chip while the direction callback still enters the pinctrl mutex path.
A directed runtime validation kept the same non-sleeping chip registration and drove:
gpio_shared_proxy_direction_output()
gpiod_direction_output_raw_commit()
tegra_gpio_direction_output()
pinctrl_gpio_direction_output()
Lockdep reported a sleep-in-atomic warning with the shared GPIO spinlock held and pinctrl_get_device_gpio_range() plus tegra_gpio_direction_output() on the stack.
Do not mark the whole chip as can_sleep to paper over this: can_sleep describes whether get()/set() may sleep, and Tegra value access is MMIO. Remove the redundant pinctrl direction calls and keep pinctrl involvement in the existing request/free path.
--- drivers/gpio/gpio-tegra.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-)
drivers/gpio/gpio-tegra.c +2 -16
@@ -174,18 +174,11 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) {struct tegra_gpio_info *tgi =gpiochip_get_data (chip); -int ret;tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,0 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_input (chip, offset); -if (ret <0 ) -dev_err (tgi->dev, -"Failed to set pinctrl input direction of GPIO %d: %d" , - chip->base + offset, ret); - -return ret; +return 0 ; } static int tegra_gpio_direction_output(struct gpio_chip *chip,
@@ -193,19 +186,12 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, int value) {struct tegra_gpio_info *tgi =gpiochip_get_data (chip); -int ret;tegra_gpio_set (chip, offset, value);tegra_gpio_mask_write (tgi,GPIO_MSK_OE (tgi, offset), offset,1 );tegra_gpio_enable (tgi, offset); - ret =pinctrl_gpio_direction_output (chip, offset); -if (ret <0 ) -dev_err (tgi->dev, -"Failed to set pinctrl output direction of GPIO %d: %d" , - chip->base + offset, ret); - -return ret; +return 0 ; } static int tegra_gpio_get_direction(struct gpio_chip *chip,
Signature · 1 line
2.53.0