FAILED: patch "[PATCH] pinctrl: samsung: fix SMP race condition" failed to apply to 4.4-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.4-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]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
d9ff0eb9ca4b00ce2fbf9ede1e99681f05c0bc91Mon Sep 17 00:00:00 2001
From: Youngmin Nam <[email protected]>
Date: Tue, 9 Feb 2016 00:49:28 +0900
Subject: [PATCH] pinctrl: samsung: fix SMP race condition
Previously, samsung_gpio_drection_in/output function were not covered with a spinlock.
For example, samsung_gpio_direction_output function consists of two functions.
1. samsung_gpio_set
2. samsung_gpio_set_direction
When 2 CPUs try to control the same gpio pin heavily, (situation like i2c control with gpio emulation) This situation can cause below problem.
CPU 0 | CPU1
|
samsung_gpio_direction_output |
samsung_gpio_set(pin A as 1) | samsung_gpio_direction_output
| samsung_gpio_set(pin A as 0)
samsung_gpio_set_direction |
| samsung_gpio_set_directionThe initial value of pin A will be set as 0 while we wanted to set pin A as 1.
This patch modifies samsung_gpio_direction_in/output function to be done in one spinlock to fix race condition.
Additionally, the new samsung_gpio_set_value was added to implement gpio set callback(samsung_gpio_set) with spinlock using this function.
drivers/pinctrl/samsung/pinctrl-samsung.c +35 -13
@@ -514,25 +514,35 @@ static const struct pinconf_ops samsung_pinconf_ops = { .pin_config_group_set = samsung_pinconf_group_set, }; -/* gpiolib gpio_set callback function */ -static void samsung_gpio_set (struct gpio_chip *gc,unsigned offset,int value) +/* +* The samsung_gpio_set_vlaue() should be called with "bank->slock" held +* to avoid race condition. +*/ +static void samsung_gpio_set_value (struct gpio_chip *gc, +unsigned offset,int value) {struct samsung_pin_bank *bank =gpiochip_get_data (gc);const struct samsung_pin_bank_type *type = bank->type; -unsigned long flags;void __iomem *reg;u32 data; reg = bank->drvdata->virt_base + bank->pctl_offset; -spin_lock_irqsave (&bank->slock, flags); - data =readl (reg + type->reg_offset[PINCFG_TYPE_DAT ]); data &= ~(1 << offset);if (value) data |=1 << offset;writel (data, reg + type->reg_offset[PINCFG_TYPE_DAT ]); +} + +/* gpiolib gpio_set callback function */ +static void samsung_gpio_set (struct gpio_chip *gc,unsigned offset,int value) +{ +struct samsung_pin_bank *bank =gpiochip_get_data (gc); +unsigned long flags; +spin_lock_irqsave (&bank->slock, flags); +samsung_gpio_set_value (gc, offset, value);spin_unlock_irqrestore (&bank->slock, flags); }
@@ -553,6 +563,8 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) }/* +* The samsung_gpio_set_direction() should be called with "bank->slock" held +* to avoid race condition. * The calls to gpio_direction_output() and gpio_direction_input() * leads to this function call. */
@@ -564,7 +576,6 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,struct samsung_pinctrl_drv_data *drvdata;void __iomem *reg;u32 data, mask, shift; -unsigned long flags; bank =gpiochip_get_data (gc); type = bank->type;
@@ -581,31 +592,42 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, reg +=4 ; } -spin_lock_irqsave (&bank->slock, flags); - data =readl (reg); data &= ~(mask << shift);if (!input) data |=FUNC_OUTPUT << shift;writel (data, reg); -spin_unlock_irqrestore (&bank->slock, flags); -return 0 ; }/* gpiolib gpio_direction_input callback function. */ static int samsung_gpio_direction_input (struct gpio_chip *gc,unsigned offset) { -return samsung_gpio_set_direction (gc, offset, true); +struct samsung_pin_bank *bank =gpiochip_get_data (gc); +unsigned long flags; +int ret; + +spin_lock_irqsave (&bank->slock, flags); + ret =samsung_gpio_set_direction (gc, offset, true); +spin_unlock_irqrestore (&bank->slock, flags); +return ret; }/* gpiolib gpio_direction_output callback function. */ static int samsung_gpio_direction_output (struct gpio_chip *gc,unsigned offset,int value) { -samsung_gpio_set (gc, offset, value); -return samsung_gpio_set_direction (gc, offset, false); +struct samsung_pin_bank *bank =gpiochip_get_data (gc); +unsigned long flags; +int ret; + +spin_lock_irqsave (&bank->slock, flags); +samsung_gpio_set_value (gc, offset, value); + ret =samsung_gpio_set_direction (gc, offset, false); +spin_unlock_irqrestore (&bank->slock, flags); + +return ret; }/*