diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2015-12-22 16:58:02 +0100 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2015-12-22 16:58:02 +0100 |
commit | 1ccda4237a810cc0ef5c801ed1fd512543c70785 (patch) | |
tree | 50c0e9206604a7efb0773766f0e1712f70a1609a | |
parent | 16abccd3189b44fa3a2de507d3fe03e14f9b5e43 (diff) | |
download | 4.8-rt-patches-1ccda4237a810cc0ef5c801ed1fd512543c70785.tar.gz |
[ANNOUNCE] 4.1.15-rt17
Dear RT folks!
I'm pleased to announce the v4.1.15-rt17 patch set.
Changes since v4.1.15-rt16:
Axel Lin (1):
gpio: omap: Fix missing raw locks conversion
Grygorii Strashko (15):
gpio: omap: fix omap_gpio_free to not clean up irq configuration
gpio: omap: fix error handling in omap_gpio_irq_type
gpio: omap: rework omap_x_irq_shutdown to touch only irqs specific registers
gpio: omap: rework omap_gpio_request to touch only gpio specific registers
gpio: omap: rework omap_gpio_irq_startup to handle current pin state properly
gpio: omap: add missed spin_unlock_irqrestore in omap_gpio_irq_type
gpio: omap: prevent module from being unloaded while in use
gpio: omap: remove wrong irq_domain_remove usage in probe
gpio: omap: switch to use platform_get_irq
gpio: omap: fix omap2_set_gpio_debounce
gpio: omap: protect regs access in omap_gpio_irq_handler
gpio: omap: fix clk_prepare/unprepare usage
gpio: omap: fix static checker warning
gpio: omap: move pm runtime in irq_chip.irq_bus_lock/sync_unlock
gpio: omap: convert to use generic irq handler
Russ Dill (1):
ARM: OMAP2: Drop the concept of certain power domains not being able to lose context.
Sebastian Andrzej Siewior (4):
Revert "x86: Do not disable preemption in int3 on 32bit"
Revert "gpio: omap: use raw locks for locking"
gpio: omap: use raw locks for locking
v4.1.15-rt17
Tony Lindgren (3):
gpio: omap: Allow building as a loadable module
gpio: omap: Fix gpiochip_add() handling for deferred probe
gpio: omap: Fix GPIO numbering for deferred probe
Yang Shi (1):
x86/signal: delay calling signals on 32bit
bmouring@ni.com (1):
rtmutex: Use chainwalking control enum
Known issues:
- bcache stays disabled
- CPU hotplug is not better than before
- The netlink_release() OOPS, reported by Clark, is still on the
list, but unsolved due to lack of information
- Christoph Mathys reported a stall in cgroup locking code while using
Linux containers.
The delta patch against 4.1.15-rt17 is appended below and can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.1/incr/patch-4.1.15-rt16-rt17.patch.xz
You can get this release via the git tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v4.1.15-rt17
The RT patch against 4.1.15 can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.1/patch-4.1.15-rt17.patch.xz
The split quilt queue is available at:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.1/patches-4.1.15-rt17.tar.xz
Sebastian
diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c
index 7a577145b68b..689a1af47c80 100644
--- a/arch/arm/mach-omap2/gpio.c
+++ b/arch/arm/mach-omap2/gpio.c
@@ -130,7 +130,6 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
}
pwrdm = omap_hwmod_get_pwrdm(oh);
- pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
pdev = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata));
kfree(pdata);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 78af6d8cf2e2..ef4227ffa3b6 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -1166,43 +1166,3 @@ int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
return count;
}
-/**
- * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
- * @pwrdm: struct powerdomain *
- *
- * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
- * can lose either memory or logic context or if @pwrdm is invalid, or
- * returns 0 otherwise. This function is not concerned with how the
- * powerdomain registers are programmed (i.e., to go off or not); it's
- * concerned with whether it's ever possible for this powerdomain to
- * go off while some other part of the chip is active. This function
- * assumes that every powerdomain can go to either ON or INACTIVE.
- */
-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
-{
- int i;
-
- if (!pwrdm) {
- pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
- __func__);
- return 1;
- }
-
- if (pwrdm->pwrsts & PWRSTS_OFF)
- return 1;
-
- if (pwrdm->pwrsts & PWRSTS_RET) {
- if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
- return 1;
-
- for (i = 0; i < pwrdm->banks; i++)
- if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
- return 1;
- }
-
- for (i = 0; i < pwrdm->banks; i++)
- if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
- return 1;
-
- return 0;
-}
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 28a796ce07d7..5e0c033a21db 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -244,7 +244,6 @@ int pwrdm_state_switch(struct powerdomain *pwrdm);
int pwrdm_pre_transition(struct powerdomain *pwrdm);
int pwrdm_post_transition(struct powerdomain *pwrdm);
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);
diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h
index b1b08a28c72a..0e7bfe98e1d1 100644
--- a/arch/x86/include/asm/signal.h
+++ b/arch/x86/include/asm/signal.h
@@ -32,7 +32,7 @@ typedef struct {
* TIF_NOTIFY_RESUME and set up the signal to be sent on exit of the
* trap.
*/
-#if defined(CONFIG_PREEMPT_RT_FULL) && defined(CONFIG_X86_64)
+#if defined(CONFIG_PREEMPT_RT_FULL)
#define ARCH_RT_DELAYS_SIGNAL_SEND
#endif
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index ebae118938ef..324ab5247687 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -88,21 +88,9 @@ static inline void conditional_sti(struct pt_regs *regs)
local_irq_enable();
}
-static inline void conditional_sti_ist(struct pt_regs *regs)
+static inline void preempt_conditional_sti(struct pt_regs *regs)
{
-#ifdef CONFIG_X86_64
- /*
- * X86_64 uses a per CPU stack on the IST for certain traps
- * like int3. The task can not be preempted when using one
- * of these stacks, thus preemption must be disabled, otherwise
- * the stack can be corrupted if the task is scheduled out,
- * and another task comes in and uses this stack.
- *
- * On x86_32 the task keeps its own stack and it is OK if the
- * task schedules out.
- */
preempt_count_inc();
-#endif
if (regs->flags & X86_EFLAGS_IF)
local_irq_enable();
}
@@ -113,13 +101,11 @@ static inline void conditional_cli(struct pt_regs *regs)
local_irq_disable();
}
-static inline void conditional_cli_ist(struct pt_regs *regs)
+static inline void preempt_conditional_cli(struct pt_regs *regs)
{
if (regs->flags & X86_EFLAGS_IF)
local_irq_disable();
-#ifdef CONFIG_X86_64
preempt_count_dec();
-#endif
}
enum ctx_state ist_enter(struct pt_regs *regs)
@@ -550,9 +536,9 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
* as we may switch to the interrupt stack.
*/
debug_stack_usage_inc();
- conditional_sti_ist(regs);
+ preempt_conditional_sti(regs);
do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
- conditional_cli_ist(regs);
+ preempt_conditional_cli(regs);
debug_stack_usage_dec();
exit:
ist_exit(regs, prev_state);
@@ -682,12 +668,12 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
debug_stack_usage_inc();
/* It's safe to allow irq's after DR6 has been saved */
- conditional_sti_ist(regs);
+ preempt_conditional_sti(regs);
if (v8086_mode(regs)) {
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code,
X86_TRAP_DB);
- conditional_cli_ist(regs);
+ preempt_conditional_cli(regs);
debug_stack_usage_dec();
goto exit;
}
@@ -707,7 +693,7 @@ dotraplinkage void do_debug(struct pt_regs *regs, long error_code)
si_code = get_si_code(tsk->thread.debugreg6);
if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp)
send_sigtrap(tsk, regs, error_code, si_code);
- conditional_cli_ist(regs);
+ preempt_conditional_cli(regs);
debug_stack_usage_dec();
exit:
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index caefe806db5e..ff7df95de3bf 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -308,7 +308,7 @@ config GPIO_OCTEON
family of SOCs.
config GPIO_OMAP
- bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS
+ tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST
default y if ARCH_OMAP
depends on ARM
select GENERIC_IRQ_CHIP
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index a0ace2758e2e..4916fd726dce 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -29,6 +29,7 @@
#include <linux/platform_data/gpio-omap.h>
#define OFF_MODE 1
+#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
static LIST_HEAD(omap_gpio_list);
@@ -50,7 +51,7 @@ struct gpio_regs {
struct gpio_bank {
struct list_head node;
void __iomem *base;
- u16 irq;
+ int irq;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
struct gpio_regs context;
@@ -58,6 +59,7 @@ struct gpio_bank {
u32 level_mask;
u32 toggle_mask;
raw_spinlock_t lock;
+ raw_spinlock_t wa_lock;
struct gpio_chip chip;
struct clk *dbck;
u32 mod_usage;
@@ -67,7 +69,7 @@ struct gpio_bank {
struct device *dev;
bool is_mpuio;
bool dbck_flag;
- bool loses_context;
+
bool context_valid;
int stride;
u32 width;
@@ -175,7 +177,7 @@ static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set
static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
{
if (bank->dbck_enable_mask && !bank->dbck_enabled) {
- clk_prepare_enable(bank->dbck);
+ clk_enable(bank->dbck);
bank->dbck_enabled = true;
writel_relaxed(bank->dbck_enable_mask,
@@ -193,7 +195,7 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
*/
writel_relaxed(0, bank->base + bank->regs->debounce_en);
- clk_disable_unprepare(bank->dbck);
+ clk_disable(bank->dbck);
bank->dbck_enabled = false;
}
}
@@ -204,8 +206,9 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
* @offset: the gpio number on this @bank
* @debounce: debounce time to use
*
- * OMAP's debounce time is in 31us steps so we need
- * to convert and round up to the closest unit.
+ * OMAP's debounce time is in 31us steps
+ * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31
+ * so we need to convert and round up to the closest unit.
*/
static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
unsigned debounce)
@@ -213,34 +216,33 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
void __iomem *reg;
u32 val;
u32 l;
+ bool enable = !!debounce;
if (!bank->dbck_flag)
return;
- if (debounce < 32)
- debounce = 0x01;
- else if (debounce > 7936)
- debounce = 0xff;
- else
- debounce = (debounce / 0x1f) - 1;
+ if (enable) {
+ debounce = DIV_ROUND_UP(debounce, 31) - 1;
+ debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK;
+ }
l = BIT(offset);
- clk_prepare_enable(bank->dbck);
+ clk_enable(bank->dbck);
reg = bank->base + bank->regs->debounce;
writel_relaxed(debounce, reg);
reg = bank->base + bank->regs->debounce_en;
val = readl_relaxed(reg);
- if (debounce)
+ if (enable)
val |= l;
else
val &= ~l;
bank->dbck_enable_mask = val;
writel_relaxed(val, reg);
- clk_disable_unprepare(bank->dbck);
+ clk_disable(bank->dbck);
/*
* Enable debounce clock per module.
* This call is mandatory because in omap_gpio_request() when
@@ -285,7 +287,7 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
bank->context.debounce = 0;
writel_relaxed(bank->context.debounce, bank->base +
bank->regs->debounce);
- clk_disable_unprepare(bank->dbck);
+ clk_disable(bank->dbck);
bank->dbck_enabled = false;
}
}
@@ -488,9 +490,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
unsigned long flags;
unsigned offset = d->hwirq;
- if (!BANK_USED(bank))
- pm_runtime_get_sync(bank->dev);
-
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@@ -500,10 +499,15 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
raw_spin_lock_irqsave(&bank->lock, flags);
retval = omap_set_gpio_triggering(bank, offset, type);
+ if (retval) {
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+ goto error;
+ }
omap_gpio_init_irq(bank, offset);
if (!omap_gpio_is_input(bank, offset)) {
raw_spin_unlock_irqrestore(&bank->lock, flags);
- return -EINVAL;
+ retval = -EINVAL;
+ goto error;
}
raw_spin_unlock_irqrestore(&bank->lock, flags);
@@ -512,6 +516,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
__irq_set_handler_locked(d->irq, handle_edge_irq);
+ return 0;
+
+error:
return retval;
}
@@ -638,22 +645,18 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
return 0;
}
-static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset)
-{
- omap_set_gpio_direction(bank, offset, 1);
- omap_set_gpio_irqenable(bank, offset, 0);
- omap_clear_gpio_irqstatus(bank, offset);
- omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
- omap_clear_gpio_debounce(bank, offset);
-}
-
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
unsigned offset = d->hwirq;
+ int ret;
- return omap_set_gpio_wakeup(bank, offset, enable);
+ ret = omap_set_gpio_wakeup(bank, offset, enable);
+ if (!ret)
+ ret = irq_set_irq_wake(bank->irq, enable);
+
+ return ret;
}
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -669,14 +672,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
pm_runtime_get_sync(bank->dev);
raw_spin_lock_irqsave(&bank->lock, flags);
- /* Set trigger to none. You need to enable the desired trigger with
- * request_irq() or set_irq_type(). Only do this if the IRQ line has
- * not already been requested.
- */
- if (!LINE_USED(bank->irq_usage, offset)) {
- omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
- omap_enable_gpio_module(bank, offset);
- }
+ omap_enable_gpio_module(bank, offset);
bank->mod_usage |= BIT(offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
@@ -690,8 +686,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
raw_spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset));
+ if (!LINE_USED(bank->irq_usage, offset)) {
+ omap_set_gpio_direction(bank, offset, 1);
+ omap_clear_gpio_debounce(bank, offset);
+ }
omap_disable_gpio_module(bank, offset);
- omap_reset_gpio(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -711,29 +710,27 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
* line's interrupt handler has been run, we may miss some nested
* interrupts.
*/
-static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
{
void __iomem *isr_reg = NULL;
u32 isr;
unsigned int bit;
- struct gpio_bank *bank;
- int unmasked = 0;
- struct irq_chip *irqchip = irq_desc_get_chip(desc);
- struct gpio_chip *chip = irq_get_handler_data(irq);
+ struct gpio_bank *bank = gpiobank;
+ unsigned long wa_lock_flags;
+ unsigned long lock_flags;
- chained_irq_enter(irqchip, desc);
-
- bank = container_of(chip, struct gpio_bank, chip);
isr_reg = bank->base + bank->regs->irqstatus;
- pm_runtime_get_sync(bank->dev);
-
if (WARN_ON(!isr_reg))
goto exit;
+ pm_runtime_get_sync(bank->dev);
+
while (1) {
u32 isr_saved, level_mask = 0;
u32 enabled;
+ raw_spin_lock_irqsave(&bank->lock, lock_flags);
+
enabled = omap_get_gpio_irqbank_mask(bank);
isr_saved = isr = readl_relaxed(isr_reg) & enabled;
@@ -747,12 +744,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask);
omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask);
- /* if there is only edge sensitive GPIO pin interrupts
- configured, we could unmask GPIO bank interrupt immediately */
- if (!level_mask && !unmasked) {
- unmasked = 1;
- chained_irq_exit(irqchip, desc);
- }
+ raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
if (!isr)
break;
@@ -761,6 +753,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
bit = __ffs(isr);
isr &= ~(BIT(bit));
+ raw_spin_lock_irqsave(&bank->lock, lock_flags);
/*
* Some chips can't respond to both rising and falling
* at the same time. If this irq was requested with
@@ -771,18 +764,20 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (bank->toggle_mask & (BIT(bit)))
omap_toggle_gpio_edge_triggering(bank, bit);
+ raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
+
+ raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
+
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
bit));
+
+ raw_spin_unlock_irqrestore(&bank->wa_lock,
+ wa_lock_flags);
}
}
- /* if bank has any level sensitive GPIO pin interrupt
- configured, we must unmask the bank interrupt only after
- handler(s) are executed in order to avoid spurious bank
- interrupt */
exit:
- if (!unmasked)
- chained_irq_exit(irqchip, desc);
pm_runtime_put(bank->dev);
+ return IRQ_HANDLED;
}
static unsigned int omap_gpio_irq_startup(struct irq_data *d)
@@ -791,15 +786,22 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
unsigned long flags;
unsigned offset = d->hwirq;
- if (!BANK_USED(bank))
- pm_runtime_get_sync(bank->dev);
-
raw_spin_lock_irqsave(&bank->lock, flags);
- omap_gpio_init_irq(bank, offset);
+
+ if (!LINE_USED(bank->mod_usage, offset))
+ omap_set_gpio_direction(bank, offset, 1);
+ else if (!omap_gpio_is_input(bank, offset))
+ goto err;
+ omap_enable_gpio_module(bank, offset);
+ bank->irq_usage |= BIT(offset);
+
raw_spin_unlock_irqrestore(&bank->lock, flags);
omap_gpio_unmask_irq(d);
return 0;
+err:
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+ return -EINVAL;
}
static void omap_gpio_irq_shutdown(struct irq_data *d)
@@ -810,9 +812,26 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
raw_spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset));
+ omap_set_gpio_irqenable(bank, offset, 0);
+ omap_clear_gpio_irqstatus(bank, offset);
+ omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ if (!LINE_USED(bank->mod_usage, offset))
+ omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(bank, offset);
- omap_reset_gpio(bank, offset);
raw_spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static void omap_gpio_irq_bus_lock(struct irq_data *data)
+{
+ struct gpio_bank *bank = omap_irq_data_get_bank(data);
+
+ if (!BANK_USED(bank))
+ pm_runtime_get_sync(bank->dev);
+}
+
+static void gpio_irq_bus_sync_unlock(struct irq_data *data)
+{
+ struct gpio_bank *bank = omap_irq_data_get_bank(data);
/*
* If this is the last IRQ to be freed in the bank,
@@ -1048,10 +1067,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
/* Initialize interface clk ungated, module enabled */
if (bank->regs->ctrl)
writel_relaxed(0, base + bank->regs->ctrl);
-
- bank->dbck = clk_get(bank->dev, "dbclk");
- if (IS_ERR(bank->dbck))
- dev_err(bank->dev, "Could not get gpio dbck\n");
}
static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
@@ -1080,7 +1095,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
} else {
bank->chip.label = "gpio";
bank->chip.base = gpio;
- gpio += bank->width;
}
bank->chip.ngpio = bank->width;
@@ -1090,6 +1104,9 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
return ret;
}
+ if (!bank->is_mpuio)
+ gpio += bank->width;
+
#ifdef CONFIG_ARCH_OMAP1
/*
* REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
@@ -1112,7 +1129,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
}
ret = gpiochip_irqchip_add(&bank->chip, irqc,
- irq_base, omap_gpio_irq_handler,
+ irq_base, handle_bad_irq,
IRQ_TYPE_NONE);
if (ret) {
@@ -1121,10 +1138,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
return -ENODEV;
}
- gpiochip_set_chained_irqchip(&bank->chip, irqc,
- bank->irq, omap_gpio_irq_handler);
+ gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL);
- return 0;
+ ret = devm_request_irq(bank->dev, bank->irq, omap_gpio_irq_handler,
+ 0, dev_name(bank->dev), bank);
+ if (ret)
+ gpiochip_remove(&bank->chip);
+
+ return ret;
}
static const struct of_device_id omap_gpio_match[];
@@ -1163,17 +1184,23 @@ static int omap_gpio_probe(struct platform_device *pdev)
irqc->irq_unmask = omap_gpio_unmask_irq,
irqc->irq_set_type = omap_gpio_irq_type,
irqc->irq_set_wake = omap_gpio_wake_enable,
+ irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
+ irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
irqc->name = dev_name(&pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (unlikely(!res)) {
- dev_err(dev, "Invalid IRQ resource\n");
- return -ENODEV;
+ bank->irq = platform_get_irq(pdev, 0);
+ if (bank->irq <= 0) {
+ if (!bank->irq)
+ bank->irq = -ENXIO;
+ if (bank->irq != -EPROBE_DEFER)
+ dev_err(dev,
+ "can't get irq resource ret=%d\n", bank->irq);
+ return bank->irq;
}
- bank->irq = res->start;
bank->dev = dev;
bank->chip.dev = dev;
+ bank->chip.owner = THIS_MODULE;
bank->dbck_flag = pdata->dbck_flag;
bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width;
@@ -1183,15 +1210,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node);
#endif
- if (node) {
- if (!of_property_read_bool(node, "ti,gpio-always-on"))
- bank->loses_context = true;
- } else {
- bank->loses_context = pdata->loses_context;
-
- if (bank->loses_context)
- bank->get_context_loss_count =
- pdata->get_context_loss_count;
+ if (!node) {
+ bank->get_context_loss_count =
+ pdata->get_context_loss_count;
}
if (bank->regs->set_dataout && bank->regs->clr_dataout)
@@ -1200,15 +1221,26 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->set_dataout = omap_set_gpio_dataout_mask;
raw_spin_lock_init(&bank->lock);
+ raw_spin_lock_init(&bank->wa_lock);
/* Static mapping, never released */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bank->base = devm_ioremap_resource(dev, res);
if (IS_ERR(bank->base)) {
- irq_domain_remove(bank->chip.irqdomain);
return PTR_ERR(bank->base);
}
+ if (bank->dbck_flag) {
+ bank->dbck = devm_clk_get(bank->dev, "dbclk");
+ if (IS_ERR(bank->dbck)) {
+ dev_err(bank->dev,
+ "Could not get gpio dbck. Disable debounce\n");
+ bank->dbck_flag = false;
+ } else {
+ clk_prepare(bank->dbck);
+ }
+ }
+
platform_set_drvdata(pdev, bank);
pm_runtime_enable(bank->dev);
@@ -1221,8 +1253,11 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_gpio_mod_init(bank);
ret = omap_gpio_chip_init(bank, irqc);
- if (ret)
+ if (ret) {
+ pm_runtime_put_sync(bank->dev);
+ pm_runtime_disable(bank->dev);
return ret;
+ }
omap_gpio_show_rev(bank);
@@ -1233,6 +1268,19 @@ static int omap_gpio_probe(struct platform_device *pdev)
return 0;
}
+static int omap_gpio_remove(struct platform_device *pdev)
+{
+ struct gpio_bank *bank = platform_get_drvdata(pdev);
+
+ list_del(&bank->node);
+ gpiochip_remove(&bank->chip);
+ pm_runtime_disable(bank->dev);
+ if (bank->dbck_flag)
+ clk_unprepare(bank->dbck);
+
+ return 0;
+}
+
#ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM)
@@ -1321,7 +1369,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
* been initialised and so initialise it now. Also initialise
* the context loss count.
*/
- if (bank->loses_context && !bank->context_valid) {
+ if (!bank->context_valid) {
omap_gpio_init_context(bank);
if (bank->get_context_loss_count)
@@ -1342,17 +1390,15 @@ static int omap_gpio_runtime_resume(struct device *dev)
writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
- if (bank->loses_context) {
- if (!bank->get_context_loss_count) {
+ if (!bank->get_context_loss_count) {
+ omap_gpio_restore_context(bank);
+ } else {
+ c = bank->get_context_loss_count(bank->dev);
+ if (c != bank->context_loss_count) {
omap_gpio_restore_context(bank);
} else {
- c = bank->get_context_loss_count(bank->dev);
- if (c != bank->context_loss_count) {
- omap_gpio_restore_context(bank);
- } else {
- raw_spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
- }
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+ return 0;
}
}
@@ -1418,12 +1464,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
}
#endif /* CONFIG_PM */
+#if IS_BUILTIN(CONFIG_GPIO_OMAP)
void omap2_gpio_prepare_for_idle(int pwr_mode)
{
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!BANK_USED(bank) || !bank->loses_context)
+ if (!BANK_USED(bank))
continue;
bank->power_mode = pwr_mode;
@@ -1437,12 +1484,13 @@ void omap2_gpio_resume_after_idle(void)
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!BANK_USED(bank) || !bank->loses_context)
+ if (!BANK_USED(bank))
continue;
pm_runtime_get_sync(bank->dev);
}
}
+#endif
#if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p)
@@ -1598,6 +1646,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match);
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
+ .remove = omap_gpio_remove,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,
@@ -1615,3 +1664,13 @@ static int __init omap_gpio_drv_reg(void)
return platform_driver_register(&omap_gpio_driver);
}
postcore_initcall(omap_gpio_drv_reg);
+
+static void __exit omap_gpio_exit(void)
+{
+ platform_driver_unregister(&omap_gpio_driver);
+}
+module_exit(omap_gpio_exit);
+
+MODULE_DESCRIPTION("omap gpio driver");
+MODULE_ALIAS("platform:gpio-omap");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/gpio-omap.h b/include/linux/platform_data/gpio-omap.h
index 5d50b25a73d7..ff43e01b8ca9 100644
--- a/include/linux/platform_data/gpio-omap.h
+++ b/include/linux/platform_data/gpio-omap.h
@@ -198,7 +198,6 @@ struct omap_gpio_platform_data {
int bank_width; /* GPIO bank width */
int bank_stride; /* Only needed for omap1 MPUIO */
bool dbck_flag; /* dbck required or not - True for OMAP3&4 */
- bool loses_context; /* whether the bank would ever lose context */
bool is_mpuio; /* whether the bank is of type MPUIO */
u32 non_wakeup_gpios;
@@ -208,9 +207,17 @@ struct omap_gpio_platform_data {
int (*get_context_loss_count)(struct device *dev);
};
+#if IS_BUILTIN(CONFIG_GPIO_OMAP)
extern void omap2_gpio_prepare_for_idle(int off_mode);
extern void omap2_gpio_resume_after_idle(void);
-extern void omap_set_gpio_debounce(int gpio, int enable);
-extern void omap_set_gpio_debounce_time(int gpio, int enable);
+#else
+static inline void omap2_gpio_prepare_for_idle(int off_mode)
+{
+}
+
+static inline void omap2_gpio_resume_after_idle(void)
+{
+}
+#endif
#endif
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 20267595df07..e0b0d9b419b5 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -1008,7 +1008,7 @@ static void noinline __sched rt_spin_lock_slowlock(struct rt_mutex *lock)
__set_current_state_no_track(TASK_UNINTERRUPTIBLE);
pi_unlock(&self->pi_lock);
- ret = task_blocks_on_rt_mutex(lock, &waiter, self, 0);
+ ret = task_blocks_on_rt_mutex(lock, &waiter, self, RT_MUTEX_MIN_CHAINWALK);
BUG_ON(ret);
for (;;) {
diff --git a/localversion-rt b/localversion-rt
index 1199ebade17b..1e584b47c987 100644
--- a/localversion-rt
+++ b/localversion-rt
@@ -1 +1 @@
--rt16
+-rt17
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
29 files changed, 1739 insertions, 68 deletions
diff --git a/patches/0001-gpio-omap-Allow-building-as-a-loadable-module.patch b/patches/0001-gpio-omap-Allow-building-as-a-loadable-module.patch new file mode 100644 index 00000000000000..63fae94bf1c2ad --- /dev/null +++ b/patches/0001-gpio-omap-Allow-building-as-a-loadable-module.patch @@ -0,0 +1,130 @@ +From ed28ad9cd730334b1df1de8268c2fef20766cb59 Mon Sep 17 00:00:00 2001 +From: Tony Lindgren <tony@atomide.com> +Date: Mon, 13 Jul 2015 17:04:15 +0300 +Subject: [PATCH 01/21] gpio: omap: Allow building as a loadable module + +commit cac089f9026e9ddb3481daf08f0fc4e5949fa1af upstream + +We currently get all kinds of errors building the omap gpio driver +as a module starting with: + +undefined reference to `omap2_gpio_resume_after_idle' +undefined reference to `omap2_gpio_prepare_for_idle' +... + +Let's fix the issue by adding inline functions to the header. +Note that we can now also remove the two unused functions for +omap_set_gpio_debounce and omap_set_gpio_debounce_time. + +Then doing rmmod on the module produces further warnings +because of missing exit related functions. Let's add those. + +And finally, we can make the Kconfig entry just a tristate +option that's selected for omaps. + +Cc: Javier Martinez Canillas <javier@dowhile0.org> +Cc: Kevin Hilman <khilman@deeprootsystems.com> +Cc: Nishanth Menon <nm@ti.com> +Signed-off-by: Tony Lindgren <tony@atomide.com> +Reviewed-by: Grygorii Strashko <grygorii.strashko@linaro.org> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Reviewed-by: Felipe Balbi <balbi@ti.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/Kconfig | 2 +- + drivers/gpio/gpio-omap.c | 24 ++++++++++++++++++++++++ + include/linux/platform_data/gpio-omap.h | 12 ++++++++++-- + 3 files changed, 35 insertions(+), 3 deletions(-) + +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -308,7 +308,7 @@ config GPIO_OCTEON + family of SOCs. + + config GPIO_OMAP +- bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS ++ tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST + default y if ARCH_OMAP + depends on ARM + select GENERIC_IRQ_CHIP +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -1233,6 +1233,17 @@ static int omap_gpio_probe(struct platfo + return 0; + } + ++static int omap_gpio_remove(struct platform_device *pdev) ++{ ++ struct gpio_bank *bank = platform_get_drvdata(pdev); ++ ++ list_del(&bank->node); ++ gpiochip_remove(&bank->chip); ++ pm_runtime_disable(bank->dev); ++ ++ return 0; ++} ++ + #ifdef CONFIG_ARCH_OMAP2PLUS + + #if defined(CONFIG_PM) +@@ -1418,6 +1429,7 @@ static int omap_gpio_runtime_resume(stru + } + #endif /* CONFIG_PM */ + ++#if IS_BUILTIN(CONFIG_GPIO_OMAP) + void omap2_gpio_prepare_for_idle(int pwr_mode) + { + struct gpio_bank *bank; +@@ -1443,6 +1455,7 @@ void omap2_gpio_resume_after_idle(void) + pm_runtime_get_sync(bank->dev); + } + } ++#endif + + #if defined(CONFIG_PM) + static void omap_gpio_init_context(struct gpio_bank *p) +@@ -1598,6 +1611,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match) + + static struct platform_driver omap_gpio_driver = { + .probe = omap_gpio_probe, ++ .remove = omap_gpio_remove, + .driver = { + .name = "omap_gpio", + .pm = &gpio_pm_ops, +@@ -1615,3 +1629,13 @@ static int __init omap_gpio_drv_reg(void + return platform_driver_register(&omap_gpio_driver); + } + postcore_initcall(omap_gpio_drv_reg); ++ ++static void __exit omap_gpio_exit(void) ++{ ++ platform_driver_unregister(&omap_gpio_driver); ++} ++module_exit(omap_gpio_exit); ++ ++MODULE_DESCRIPTION("omap gpio driver"); ++MODULE_ALIAS("platform:gpio-omap"); ++MODULE_LICENSE("GPL v2"); +--- a/include/linux/platform_data/gpio-omap.h ++++ b/include/linux/platform_data/gpio-omap.h +@@ -208,9 +208,17 @@ struct omap_gpio_platform_data { + int (*get_context_loss_count)(struct device *dev); + }; + ++#if IS_BUILTIN(CONFIG_GPIO_OMAP) + extern void omap2_gpio_prepare_for_idle(int off_mode); + extern void omap2_gpio_resume_after_idle(void); +-extern void omap_set_gpio_debounce(int gpio, int enable); +-extern void omap_set_gpio_debounce_time(int gpio, int enable); ++#else ++static inline void omap2_gpio_prepare_for_idle(int off_mode) ++{ ++} ++ ++static inline void omap2_gpio_resume_after_idle(void) ++{ ++} ++#endif + + #endif diff --git a/patches/0002-gpio-omap-fix-omap_gpio_free-to-not-clean-up-irq-con.patch b/patches/0002-gpio-omap-fix-omap_gpio_free-to-not-clean-up-irq-con.patch new file mode 100644 index 00000000000000..ba63133bd910f0 --- /dev/null +++ b/patches/0002-gpio-omap-fix-omap_gpio_free-to-not-clean-up-irq-con.patch @@ -0,0 +1,45 @@ +From 463bb14e6fc957a7d5ec9434afed29430debbbfb Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@linaro.org> +Date: Mon, 13 Jul 2015 17:08:08 +0300 +Subject: [PATCH 02/21] gpio: omap: fix omap_gpio_free to not clean up irq + configuration + +commit 5f982c70a7c3382d3532ac6d13fdea48ab38b934 upstream + +This patch fixes following issue: +- GPIOn is used as IRQ by some dev, for example PCF8575.INT -> gpio6.11 +- PCFx driver knows nothing about type of IRQ line (GPIO or not) + so it doesn't request gpio and just do request_irq() +- If gpio6.11 will be exported through the sysfs and then un-xeported +then IRQs from PCFx will not be received any more, because +IRQ configuration for gpio6.11 will be cleaned up unconditionally +in omap_gpio_free. + +Fix this by removing all GPIO IRQ specific code from omap_gpio_free() +and also do GPIO clean up (change direction to 'in' and disable debounce) +only if corresponding GPIO is not used as IRQ too. +GPIO IRQ will be properly cleaned up by GPIO irqchip code. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@linaro.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -690,8 +690,11 @@ static void omap_gpio_free(struct gpio_c + + spin_lock_irqsave(&bank->lock, flags); + bank->mod_usage &= ~(BIT(offset)); ++ if (!LINE_USED(bank->irq_usage, offset)) { ++ omap_set_gpio_direction(bank, offset, 1); ++ omap_clear_gpio_debounce(bank, offset); ++ } + omap_disable_gpio_module(bank, offset); +- omap_reset_gpio(bank, offset); + spin_unlock_irqrestore(&bank->lock, flags); + + /* diff --git a/patches/0003-gpio-omap-fix-error-handling-in-omap_gpio_irq_type.patch b/patches/0003-gpio-omap-fix-error-handling-in-omap_gpio_irq_type.patch new file mode 100644 index 00000000000000..b10843843d7747 --- /dev/null +++ b/patches/0003-gpio-omap-fix-error-handling-in-omap_gpio_irq_type.patch @@ -0,0 +1,66 @@ +From 290b539f02c79ede61502447d77579f15f6a4984 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@linaro.org> +Date: Mon, 13 Jul 2015 17:08:09 +0300 +Subject: [PATCH 03/21] gpio: omap: fix error handling in omap_gpio_irq_type + +commit 1562e4618ded89b07d145d6985f469fe8be04830 upstream + +The GPIO bank will be kept powered in case if input parameters +are invalid or error occurred in omap_gpio_irq_type. + +Hence, fix it by ensuring that GPIO bank will be unpowered +in case of errors and add additional check of value returned +from omap_set_gpio_triggering(). + +Signed-off-by: Grygorii Strashko <grygorii.strashko@linaro.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq + unsigned long flags; + unsigned offset = d->hwirq; + +- if (!BANK_USED(bank)) +- pm_runtime_get_sync(bank->dev); +- + if (type & ~IRQ_TYPE_SENSE_MASK) + return -EINVAL; + +@@ -498,12 +495,18 @@ static int omap_gpio_irq_type(struct irq + (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) + return -EINVAL; + ++ if (!BANK_USED(bank)) ++ pm_runtime_get_sync(bank->dev); ++ + spin_lock_irqsave(&bank->lock, flags); + retval = omap_set_gpio_triggering(bank, offset, type); ++ if (retval) ++ goto error; + omap_gpio_init_irq(bank, offset); + if (!omap_gpio_is_input(bank, offset)) { + spin_unlock_irqrestore(&bank->lock, flags); +- return -EINVAL; ++ retval = -EINVAL; ++ goto error; + } + spin_unlock_irqrestore(&bank->lock, flags); + +@@ -512,6 +515,11 @@ static int omap_gpio_irq_type(struct irq + else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + __irq_set_handler_locked(d->irq, handle_edge_irq); + ++ return 0; ++ ++error: ++ if (!BANK_USED(bank)) ++ pm_runtime_put(bank->dev); + return retval; + } + diff --git a/patches/0004-gpio-omap-rework-omap_x_irq_shutdown-to-touch-only-i.patch b/patches/0004-gpio-omap-rework-omap_x_irq_shutdown-to-touch-only-i.patch new file mode 100644 index 00000000000000..d148a40423ea3d --- /dev/null +++ b/patches/0004-gpio-omap-rework-omap_x_irq_shutdown-to-touch-only-i.patch @@ -0,0 +1,62 @@ +From 05c248c1091e714b6c2b4c8885ebfc3000352303 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@linaro.org> +Date: Mon, 13 Jul 2015 17:08:10 +0300 +Subject: [PATCH 04/21] gpio: omap: rework omap_x_irq_shutdown to touch only + irqs specific registers + +commit 6e96c1b5e54889cd11ce29723a5c38ba284c1d91 upstream + +The GPIO Chip and GPIO IRQ Chip functionality are essentially orthogonal, +so GPIO IRQ Chip implementation shouldn't touch GPIO specific +registers and vise versa. + +Hence, rework omap_gpio_irq_shutdown and try to touch only irqs specific +registers: +- don't configure GPIO as input (it, actually, should be already configured + as input). +- don't clear debounce configuration if GPIO is still used as GPIO. + We need to take in to account here commit c9c55d921115 + ("gpio/omap: fix off-mode bug: clear debounce settings on free/reset"). + +Also remove omap_reset_gpio() function as it is not used any more. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@linaro.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -646,15 +646,6 @@ static int omap_set_gpio_wakeup(struct g + return 0; + } + +-static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset) +-{ +- omap_set_gpio_direction(bank, offset, 1); +- omap_set_gpio_irqenable(bank, offset, 0); +- omap_clear_gpio_irqstatus(bank, offset); +- omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); +- omap_clear_gpio_debounce(bank, offset); +-} +- + /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ + static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) + { +@@ -821,8 +812,12 @@ static void omap_gpio_irq_shutdown(struc + + spin_lock_irqsave(&bank->lock, flags); + bank->irq_usage &= ~(BIT(offset)); ++ omap_set_gpio_irqenable(bank, offset, 0); ++ omap_clear_gpio_irqstatus(bank, offset); ++ omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); ++ if (!LINE_USED(bank->mod_usage, offset)) ++ omap_clear_gpio_debounce(bank, offset); + omap_disable_gpio_module(bank, offset); +- omap_reset_gpio(bank, offset); + spin_unlock_irqrestore(&bank->lock, flags); + + /* diff --git a/patches/0005-gpio-omap-rework-omap_gpio_request-to-touch-only-gpi.patch b/patches/0005-gpio-omap-rework-omap_gpio_request-to-touch-only-gpi.patch new file mode 100644 index 00000000000000..263e701928bdb3 --- /dev/null +++ b/patches/0005-gpio-omap-rework-omap_gpio_request-to-touch-only-gpi.patch @@ -0,0 +1,44 @@ +From 17782f9dede8027dc6a26270b2cfec389fe39374 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@linaro.org> +Date: Mon, 13 Jul 2015 17:08:11 +0300 +Subject: [PATCH 05/21] gpio: omap: rework omap_gpio_request to touch only gpio + specific registers + +commit c3518172129a60a1f3071e61a8a4ffc50c7b2a68 upstream + +The GPIO Chip and GPIO IRQ Chip functionality are essentially orthogonal, +so GPIO Chip implementation shouldn't touch GPIO IRQ specific registers +and vise versa. + +Hence, rework omap_gpio_request: +- don't reset GPIO IRQ triggering type to IRQ_TYPE_NONE, because + GPIO irqchip should be responsible for that; +- call directly omap_enable_gpio_module as all needed checks are already + present inside it. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@linaro.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -668,14 +668,7 @@ static int omap_gpio_request(struct gpio + pm_runtime_get_sync(bank->dev); + + spin_lock_irqsave(&bank->lock, flags); +- /* Set trigger to none. You need to enable the desired trigger with +- * request_irq() or set_irq_type(). Only do this if the IRQ line has +- * not already been requested. +- */ +- if (!LINE_USED(bank->irq_usage, offset)) { +- omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); +- omap_enable_gpio_module(bank, offset); +- } ++ omap_enable_gpio_module(bank, offset); + bank->mod_usage |= BIT(offset); + spin_unlock_irqrestore(&bank->lock, flags); + diff --git a/patches/0006-gpio-omap-rework-omap_gpio_irq_startup-to-handle-cur.patch b/patches/0006-gpio-omap-rework-omap_gpio_irq_startup-to-handle-cur.patch new file mode 100644 index 00000000000000..5180d8781157d4 --- /dev/null +++ b/patches/0006-gpio-omap-rework-omap_gpio_irq_startup-to-handle-cur.patch @@ -0,0 +1,52 @@ +From 37652e77696d14c5f8b0130441651418e263822d Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@linaro.org> +Date: Mon, 13 Jul 2015 17:08:12 +0300 +Subject: [PATCH 06/21] gpio: omap: rework omap_gpio_irq_startup to handle + current pin state properly + +commit 121dcb760426ca67ee90a8b2db6a75eee010f8e3 upstream + +The omap_gpio_irq_startup() can be called at time when: +- corresponding GPIO has been requested already and in this case +it has to be configured as input already. If not - return with -EINVAL +and do not try to re-configure it as it could be unsafe. +- corresponding GPIO is free: reconfigure GPIO as input. + +In addition, call omap_enable_gpio_module directly as all needed +checks are already present inside it. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@linaro.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -790,11 +790,23 @@ static unsigned int omap_gpio_irq_startu + pm_runtime_get_sync(bank->dev); + + spin_lock_irqsave(&bank->lock, flags); +- omap_gpio_init_irq(bank, offset); ++ ++ if (!LINE_USED(bank->mod_usage, offset)) ++ omap_set_gpio_direction(bank, offset, 1); ++ else if (!omap_gpio_is_input(bank, offset)) ++ goto err; ++ omap_enable_gpio_module(bank, offset); ++ bank->irq_usage |= BIT(offset); ++ + spin_unlock_irqrestore(&bank->lock, flags); + omap_gpio_unmask_irq(d); + + return 0; ++err: ++ spin_unlock_irqrestore(&bank->lock, flags); ++ if (!BANK_USED(bank)) ++ pm_runtime_put(bank->dev); ++ return -EINVAL; + } + + static void omap_gpio_irq_shutdown(struct irq_data *d) diff --git a/patches/0007-gpio-omap-add-missed-spin_unlock_irqrestore-in-omap_.patch b/patches/0007-gpio-omap-add-missed-spin_unlock_irqrestore-in-omap_.patch new file mode 100644 index 00000000000000..e014a2f9185783 --- /dev/null +++ b/patches/0007-gpio-omap-add-missed-spin_unlock_irqrestore-in-omap_.patch @@ -0,0 +1,37 @@ +From e63638dc9dbb27e4d18dd1101cbe2c153253e343 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@linaro.org> +Date: Mon, 13 Jul 2015 17:08:13 +0300 +Subject: [PATCH 07/21] gpio: omap: add missed spin_unlock_irqrestore in + omap_gpio_irq_type + +Add missed spin_unlock_irqrestore in omap_gpio_irq_type when +omap_set_gpio_triggering() is failed. + +It fixes static checker warning: + + drivers/gpio/gpio-omap.c:523 omap_gpio_irq_type() + warn: inconsistent returns 'spin_lock:&bank->lock'. + +This fixes commit: +1562e4618ded ('gpio: omap: fix error handling in omap_gpio_irq_type') + +Reported-by: Javier Martinez Canillas <javier@dowhile0.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@linaro.org> +--- + drivers/gpio/gpio-omap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -500,8 +500,10 @@ static int omap_gpio_irq_type(struct irq + + spin_lock_irqsave(&bank->lock, flags); + retval = omap_set_gpio_triggering(bank, offset, type); +- if (retval) ++ if (retval) { ++ spin_unlock_irqrestore(&bank->lock, flags); + goto error; ++ } + omap_gpio_init_irq(bank, offset); + if (!omap_gpio_is_input(bank, offset)) { + spin_unlock_irqrestore(&bank->lock, flags); diff --git a/patches/0008-gpio-omap-prevent-module-from-being-unloaded-while-i.patch b/patches/0008-gpio-omap-prevent-module-from-being-unloaded-while-i.patch new file mode 100644 index 00000000000000..e20698e51eb1ee --- /dev/null +++ b/patches/0008-gpio-omap-prevent-module-from-being-unloaded-while-i.patch @@ -0,0 +1,32 @@ +From 1e7405ae2fa7c7fefb2bc8dbb8365f99755c74ad Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 13 Jul 2015 17:08:14 +0300 +Subject: [PATCH 08/21] gpio: omap: prevent module from being unloaded while in + use + +OMAP GPIO driver allowed to be built as loadable module, but it +doesn't set owner field in GPIO chip structure. As result, +module_get/put() API is not working and it's possible to unload +OMAP driver while in use: + + omap_gpio 48051000.gpio: REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED + +Hence, add missing configuration. + +Cc: Tony Lindgren <tony@atomide.com> +Fixes: cac089f9026e ('gpio: omap: Allow building as a loadable module') +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -1187,6 +1187,7 @@ static int omap_gpio_probe(struct platfo + bank->irq = res->start; + bank->dev = dev; + bank->chip.dev = dev; ++ bank->chip.owner = THIS_MODULE; + bank->dbck_flag = pdata->dbck_flag; + bank->stride = pdata->bank_stride; + bank->width = pdata->bank_width; diff --git a/patches/0009-ARM-OMAP2-Drop-the-concept-of-certain-power-domains-.patch b/patches/0009-ARM-OMAP2-Drop-the-concept-of-certain-power-domains-.patch new file mode 100644 index 00000000000000..77e1ccb57a472a --- /dev/null +++ b/patches/0009-ARM-OMAP2-Drop-the-concept-of-certain-power-domains-.patch @@ -0,0 +1,177 @@ +From 70f4293bd36740fd730ab25abe39281d1b312365 Mon Sep 17 00:00:00 2001 +From: Russ Dill <Russ.Dill@ti.com> +Date: Wed, 5 Aug 2015 15:30:44 +0530 +Subject: [PATCH 09/21] ARM: OMAP2: Drop the concept of certain power domains + not being able to lose context. + +It isn't much of a win, and with hibernation, everything loses context. + +Signed-off-by: Russ Dill <Russ.Dill@ti.com> +[j-keerthy@ti.com] ported to 4.1 +Signed-off-by: Keerthy <j-keerthy@ti.com> +--- + arch/arm/mach-omap2/gpio.c | 1 + arch/arm/mach-omap2/powerdomain.c | 40 -------------------------------- + arch/arm/mach-omap2/powerdomain.h | 1 + drivers/gpio/gpio-omap.c | 36 +++++++++++----------------- + include/linux/platform_data/gpio-omap.h | 1 + 5 files changed, 14 insertions(+), 65 deletions(-) + +--- a/arch/arm/mach-omap2/gpio.c ++++ b/arch/arm/mach-omap2/gpio.c +@@ -130,7 +130,6 @@ static int __init omap2_gpio_dev_init(st + } + + pwrdm = omap_hwmod_get_pwrdm(oh); +- pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm); + + pdev = omap_device_build(name, id - 1, oh, pdata, sizeof(*pdata)); + kfree(pdata); +--- a/arch/arm/mach-omap2/powerdomain.c ++++ b/arch/arm/mach-omap2/powerdomain.c +@@ -1166,43 +1166,3 @@ int pwrdm_get_context_loss_count(struct + return count; + } + +-/** +- * pwrdm_can_ever_lose_context - can this powerdomain ever lose context? +- * @pwrdm: struct powerdomain * +- * +- * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain +- * can lose either memory or logic context or if @pwrdm is invalid, or +- * returns 0 otherwise. This function is not concerned with how the +- * powerdomain registers are programmed (i.e., to go off or not); it's +- * concerned with whether it's ever possible for this powerdomain to +- * go off while some other part of the chip is active. This function +- * assumes that every powerdomain can go to either ON or INACTIVE. +- */ +-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm) +-{ +- int i; +- +- if (!pwrdm) { +- pr_debug("powerdomain: %s: invalid powerdomain pointer\n", +- __func__); +- return 1; +- } +- +- if (pwrdm->pwrsts & PWRSTS_OFF) +- return 1; +- +- if (pwrdm->pwrsts & PWRSTS_RET) { +- if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF) +- return 1; +- +- for (i = 0; i < pwrdm->banks; i++) +- if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF) +- return 1; +- } +- +- for (i = 0; i < pwrdm->banks; i++) +- if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF) +- return 1; +- +- return 0; +-} +--- a/arch/arm/mach-omap2/powerdomain.h ++++ b/arch/arm/mach-omap2/powerdomain.h +@@ -244,7 +244,6 @@ int pwrdm_state_switch(struct powerdomai + int pwrdm_pre_transition(struct powerdomain *pwrdm); + int pwrdm_post_transition(struct powerdomain *pwrdm); + int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); +-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); + + extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state); + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -67,7 +67,7 @@ struct gpio_bank { + struct device *dev; + bool is_mpuio; + bool dbck_flag; +- bool loses_context; ++ + bool context_valid; + int stride; + u32 width; +@@ -1197,15 +1197,9 @@ static int omap_gpio_probe(struct platfo + #ifdef CONFIG_OF_GPIO + bank->chip.of_node = of_node_get(node); + #endif +- if (node) { +- if (!of_property_read_bool(node, "ti,gpio-always-on")) +- bank->loses_context = true; +- } else { +- bank->loses_context = pdata->loses_context; +- +- if (bank->loses_context) +- bank->get_context_loss_count = +- pdata->get_context_loss_count; ++ if (!node) { ++ bank->get_context_loss_count = ++ pdata->get_context_loss_count; + } + + if (bank->regs->set_dataout && bank->regs->clr_dataout) +@@ -1346,7 +1340,7 @@ static int omap_gpio_runtime_resume(stru + * been initialised and so initialise it now. Also initialise + * the context loss count. + */ +- if (bank->loses_context && !bank->context_valid) { ++ if (!bank->context_valid) { + omap_gpio_init_context(bank); + + if (bank->get_context_loss_count) +@@ -1367,17 +1361,15 @@ static int omap_gpio_runtime_resume(stru + writel_relaxed(bank->context.risingdetect, + bank->base + bank->regs->risingdetect); + +- if (bank->loses_context) { +- if (!bank->get_context_loss_count) { ++ if (!bank->get_context_loss_count) { ++ omap_gpio_restore_context(bank); ++ } else { ++ c = bank->get_context_loss_count(bank->dev); ++ if (c != bank->context_loss_count) { + omap_gpio_restore_context(bank); + } else { +- c = bank->get_context_loss_count(bank->dev); +- if (c != bank->context_loss_count) { +- omap_gpio_restore_context(bank); +- } else { +- spin_unlock_irqrestore(&bank->lock, flags); +- return 0; +- } ++ spin_unlock_irqrestore(&bank->lock, flags); ++ return 0; + } + } + +@@ -1449,7 +1441,7 @@ void omap2_gpio_prepare_for_idle(int pwr + struct gpio_bank *bank; + + list_for_each_entry(bank, &omap_gpio_list, node) { +- if (!BANK_USED(bank) || !bank->loses_context) ++ if (!BANK_USED(bank)) + continue; + + bank->power_mode = pwr_mode; +@@ -1463,7 +1455,7 @@ void omap2_gpio_resume_after_idle(void) + struct gpio_bank *bank; + + list_for_each_entry(bank, &omap_gpio_list, node) { +- if (!BANK_USED(bank) || !bank->loses_context) ++ if (!BANK_USED(bank)) + continue; + + pm_runtime_get_sync(bank->dev); +--- a/include/linux/platform_data/gpio-omap.h ++++ b/include/linux/platform_data/gpio-omap.h +@@ -198,7 +198,6 @@ struct omap_gpio_platform_data { + int bank_width; /* GPIO bank width */ + int bank_stride; /* Only needed for omap1 MPUIO */ + bool dbck_flag; /* dbck required or not - True for OMAP3&4 */ +- bool loses_context; /* whether the bank would ever lose context */ + bool is_mpuio; /* whether the bank is of type MPUIO */ + u32 non_wakeup_gpios; + diff --git a/patches/gpio-omap-use-raw-locks-for-locking.patch b/patches/0010-gpio-omap-use-raw-locks-for-locking.patch index 48947fe69c8317..85a082b1de33a1 100644 --- a/patches/gpio-omap-use-raw-locks-for-locking.patch +++ b/patches/0010-gpio-omap-use-raw-locks-for-locking.patch @@ -1,6 +1,7 @@ +From 8b568939eb4098e3cf10ec0b49f3b082a332667d Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> -Date: Thu, 12 Feb 2015 16:01:13 +0100 -Subject: gpio: omap: use raw locks for locking +Date: Mon, 31 Aug 2015 18:52:19 +0300 +Subject: [PATCH 10/21] gpio: omap: use raw locks for locking This patch converts gpio_bank.lock from a spin_lock into a raw_spin_lock. The call path is to access this lock is always under a @@ -27,10 +28,13 @@ is not and this is not limited to -RT: The number of users of gpiod_set_debounce() / gpio_set_debounce() looks low but still this is not good. +Acked-by: Javier Martinez Canillas <javier@dowhile0.org> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- - drivers/gpio/gpio-omap.c | 78 +++++++++++++++++++++++------------------------ - 1 file changed, 39 insertions(+), 39 deletions(-) + drivers/gpio/gpio-omap.c | 80 +++++++++++++++++++++++------------------------ + 1 file changed, 40 insertions(+), 40 deletions(-) --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -43,25 +47,30 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> struct gpio_chip chip; struct clk *dbck; u32 mod_usage; -@@ -498,14 +498,14 @@ static int omap_gpio_irq_type(struct irq - (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) - return -EINVAL; +@@ -498,7 +498,7 @@ static int omap_gpio_irq_type(struct irq + if (!BANK_USED(bank)) + pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); retval = omap_set_gpio_triggering(bank, offset, type); + if (retval) { + spin_unlock_irqrestore(&bank->lock, flags); +@@ -506,11 +506,11 @@ static int omap_gpio_irq_type(struct irq + } omap_gpio_init_irq(bank, offset); if (!omap_gpio_is_input(bank, offset)) { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); - return -EINVAL; + retval = -EINVAL; + goto error; } - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) __irq_set_handler_locked(d->irq, handle_level_irq); -@@ -626,14 +626,14 @@ static int omap_set_gpio_wakeup(struct g +@@ -636,14 +636,14 @@ static int omap_set_gpio_wakeup(struct g return -EINVAL; } @@ -78,65 +87,79 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -668,7 +668,7 @@ static int omap_gpio_request(struct gpio +@@ -669,10 +669,10 @@ static int omap_gpio_request(struct gpio if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); - /* Set trigger to none. You need to enable the desired trigger with - * request_irq() or set_irq_type(). Only do this if the IRQ line has - * not already been requested. -@@ -678,7 +678,7 @@ static int omap_gpio_request(struct gpio - omap_enable_gpio_module(bank, offset); - } + omap_enable_gpio_module(bank, offset); bank->mod_usage |= BIT(offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } -@@ -688,11 +688,11 @@ static void omap_gpio_free(struct gpio_c +@@ -682,14 +682,14 @@ static void omap_gpio_free(struct gpio_c struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); + if (!LINE_USED(bank->irq_usage, offset)) { + omap_set_gpio_direction(bank, offset, 1); + omap_clear_gpio_debounce(bank, offset); + } omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); /* * If this is the last gpio to be freed in the bank, -@@ -794,9 +794,9 @@ static unsigned int omap_gpio_irq_startu +@@ -791,7 +791,7 @@ static unsigned int omap_gpio_irq_startu if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); - omap_gpio_init_irq(bank, offset); + + if (!LINE_USED(bank->mod_usage, offset)) + omap_set_gpio_direction(bank, offset, 1); +@@ -800,12 +800,12 @@ static unsigned int omap_gpio_irq_startu + omap_enable_gpio_module(bank, offset); + bank->irq_usage |= BIT(offset); + - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); omap_gpio_unmask_irq(d); return 0; -@@ -808,11 +808,11 @@ static void omap_gpio_irq_shutdown(struc + err: +- spin_unlock_irqrestore(&bank->lock, flags); ++ raw_spin_unlock_irqrestore(&bank->lock, flags); + if (!BANK_USED(bank)) + pm_runtime_put(bank->dev); + return -EINVAL; +@@ -817,7 +817,7 @@ static void omap_gpio_irq_shutdown(struc unsigned long flags; unsigned offset = d->hwirq; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); + omap_set_gpio_irqenable(bank, offset, 0); + omap_clear_gpio_irqstatus(bank, offset); +@@ -825,7 +825,7 @@ static void omap_gpio_irq_shutdown(struc + if (!LINE_USED(bank->mod_usage, offset)) + omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); - omap_reset_gpio(bank, offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); /* * If this is the last IRQ to be freed in the bank, -@@ -836,10 +836,10 @@ static void omap_gpio_mask_irq(struct ir +@@ -849,10 +849,10 @@ static void omap_gpio_mask_irq(struct ir unsigned offset = d->hwirq; unsigned long flags; @@ -149,7 +172,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } static void omap_gpio_unmask_irq(struct irq_data *d) -@@ -849,7 +849,7 @@ static void omap_gpio_unmask_irq(struct +@@ -862,7 +862,7 @@ static void omap_gpio_unmask_irq(struct u32 trigger = irqd_get_trigger_type(d); unsigned long flags; @@ -158,7 +181,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> if (trigger) omap_set_gpio_triggering(bank, offset, trigger); -@@ -861,7 +861,7 @@ static void omap_gpio_unmask_irq(struct +@@ -874,7 +874,7 @@ static void omap_gpio_unmask_irq(struct } omap_set_gpio_irqenable(bank, offset, 1); @@ -167,7 +190,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } /*---------------------------------------------------------------------*/ -@@ -874,9 +874,9 @@ static int omap_mpuio_suspend_noirq(stru +@@ -887,9 +887,9 @@ static int omap_mpuio_suspend_noirq(stru OMAP_MPUIO_GPIO_MASKIT / bank->stride; unsigned long flags; @@ -179,7 +202,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -889,9 +889,9 @@ static int omap_mpuio_resume_noirq(struc +@@ -902,9 +902,9 @@ static int omap_mpuio_resume_noirq(struc OMAP_MPUIO_GPIO_MASKIT / bank->stride; unsigned long flags; @@ -191,7 +214,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -937,9 +937,9 @@ static int omap_gpio_get_direction(struc +@@ -950,9 +950,9 @@ static int omap_gpio_get_direction(struc bank = container_of(chip, struct gpio_bank, chip); reg = bank->base + bank->regs->direction; @@ -203,7 +226,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return dir; } -@@ -949,9 +949,9 @@ static int omap_gpio_input(struct gpio_c +@@ -962,9 +962,9 @@ static int omap_gpio_input(struct gpio_c unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); @@ -215,7 +238,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -973,10 +973,10 @@ static int omap_gpio_output(struct gpio_ +@@ -986,10 +986,10 @@ static int omap_gpio_output(struct gpio_ unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); @@ -228,7 +251,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -988,9 +988,9 @@ static int omap_gpio_debounce(struct gpi +@@ -1001,9 +1001,9 @@ static int omap_gpio_debounce(struct gpi bank = container_of(chip, struct gpio_bank, chip); @@ -240,7 +263,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -1001,9 +1001,9 @@ static void omap_gpio_set(struct gpio_ch +@@ -1014,9 +1014,9 @@ static void omap_gpio_set(struct gpio_ch unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); @@ -252,7 +275,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } /*---------------------------------------------------------------------*/ -@@ -1199,7 +1199,7 @@ static int omap_gpio_probe(struct platfo +@@ -1207,7 +1207,7 @@ static int omap_gpio_probe(struct platfo else bank->set_dataout = omap_set_gpio_dataout_mask; @@ -261,7 +284,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -@@ -1246,7 +1246,7 @@ static int omap_gpio_runtime_suspend(str +@@ -1265,7 +1265,7 @@ static int omap_gpio_runtime_suspend(str unsigned long flags; u32 wake_low, wake_hi; @@ -270,7 +293,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * Only edges can generate a wakeup event to the PRCM. -@@ -1299,7 +1299,7 @@ static int omap_gpio_runtime_suspend(str +@@ -1318,7 +1318,7 @@ static int omap_gpio_runtime_suspend(str bank->get_context_loss_count(bank->dev); omap_gpio_dbck_disable(bank); @@ -279,7 +302,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -1314,7 +1314,7 @@ static int omap_gpio_runtime_resume(stru +@@ -1333,7 +1333,7 @@ static int omap_gpio_runtime_resume(stru unsigned long flags; int c; @@ -288,14 +311,13 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * On the first resume during the probe, the context has not -@@ -1350,14 +1350,14 @@ static int omap_gpio_runtime_resume(stru - if (c != bank->context_loss_count) { - omap_gpio_restore_context(bank); - } else { -- spin_unlock_irqrestore(&bank->lock, flags); -+ raw_spin_unlock_irqrestore(&bank->lock, flags); - return 0; - } +@@ -1368,13 +1368,13 @@ static int omap_gpio_runtime_resume(stru + if (c != bank->context_loss_count) { + omap_gpio_restore_context(bank); + } else { +- spin_unlock_irqrestore(&bank->lock, flags); ++ raw_spin_unlock_irqrestore(&bank->lock, flags); + return 0; } } @@ -305,7 +327,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> return 0; } -@@ -1412,7 +1412,7 @@ static int omap_gpio_runtime_resume(stru +@@ -1429,7 +1429,7 @@ static int omap_gpio_runtime_resume(stru } bank->workaround_enabled = false; diff --git a/patches/0011-gpio-omap-Fix-missing-raw-locks-conversion.patch b/patches/0011-gpio-omap-Fix-missing-raw-locks-conversion.patch new file mode 100644 index 00000000000000..738ab126a6977a --- /dev/null +++ b/patches/0011-gpio-omap-Fix-missing-raw-locks-conversion.patch @@ -0,0 +1,29 @@ +From 27934f278560ff4a800439cd01a102a65e622801 Mon Sep 17 00:00:00 2001 +From: Axel Lin <axel.lin@ingics.com> +Date: Mon, 31 Aug 2015 18:52:20 +0300 +Subject: [PATCH 11/21] gpio: omap: Fix missing raw locks conversion + +Fix below build warning: + CC drivers/gpio/gpio-omap.o +drivers/gpio/gpio-omap.c: In function 'omap_gpio_irq_type': +drivers/gpio/gpio-omap.c:504:3: warning: passing argument 1 of 'spin_unlock_irqrestore' from incompatible pointer type [enabled by default] +include/linux/spinlock.h:360:29: note: expected 'struct spinlock_t *' but argument is of type 'struct raw_spinlock_t *' + +Fixes: commit 4dbada2be460 ("gpio: omap: use raw locks for locking") +Signed-off-by: Axel Lin <axel.lin@ingics.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-omap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -501,7 +501,7 @@ static int omap_gpio_irq_type(struct irq + raw_spin_lock_irqsave(&bank->lock, flags); + retval = omap_set_gpio_triggering(bank, offset, type); + if (retval) { +- spin_unlock_irqrestore(&bank->lock, flags); ++ raw_spin_unlock_irqrestore(&bank->lock, flags); + goto error; + } + omap_gpio_init_irq(bank, offset); diff --git a/patches/0012-gpio-omap-remove-wrong-irq_domain_remove-usage-in-pr.patch b/patches/0012-gpio-omap-remove-wrong-irq_domain_remove-usage-in-pr.patch new file mode 100644 index 00000000000000..0635c1fdd81887 --- /dev/null +++ b/patches/0012-gpio-omap-remove-wrong-irq_domain_remove-usage-in-pr.patch @@ -0,0 +1,27 @@ +From b461fa3a9d07736eb2f8405899e8b85ee962b9c8 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 31 Aug 2015 18:52:21 +0300 +Subject: [PATCH 12/21] gpio: omap: remove wrong irq_domain_remove usage in + probe + +The bank->chip.irqdomain is uninitialized at the moment when +irq_domain_remove() is called, so remove this call. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-omap.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -1213,7 +1213,6 @@ static int omap_gpio_probe(struct platfo + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + bank->base = devm_ioremap_resource(dev, res); + if (IS_ERR(bank->base)) { +- irq_domain_remove(bank->chip.irqdomain); + return PTR_ERR(bank->base); + } + diff --git a/patches/0013-gpio-omap-switch-to-use-platform_get_irq.patch b/patches/0013-gpio-omap-switch-to-use-platform_get_irq.patch new file mode 100644 index 00000000000000..81d9cf32dd05ec --- /dev/null +++ b/patches/0013-gpio-omap-switch-to-use-platform_get_irq.patch @@ -0,0 +1,42 @@ +From 65677de608ceb2c9d0f72d4fc0375d18c68b021a Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 31 Aug 2015 18:52:22 +0300 +Subject: [PATCH 13/21] gpio: omap: switch to use platform_get_irq + +Switch OMAP GPIO driver to use platform_get_irq(), because +it is not recommened to use platform_get_resource(pdev, IORESOURCE_IRQ, ..) +for requesting IRQ resources any more, as they can be not ready yet +in case of DT-boot. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-omap.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -1178,13 +1178,16 @@ static int omap_gpio_probe(struct platfo + irqc->irq_set_wake = omap_gpio_wake_enable, + irqc->name = dev_name(&pdev->dev); + +- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +- if (unlikely(!res)) { +- dev_err(dev, "Invalid IRQ resource\n"); +- return -ENODEV; ++ bank->irq = platform_get_irq(pdev, 0); ++ if (bank->irq <= 0) { ++ if (!bank->irq) ++ bank->irq = -ENXIO; ++ if (bank->irq != -EPROBE_DEFER) ++ dev_err(dev, ++ "can't get irq resource ret=%d\n", bank->irq); ++ return bank->irq; + } + +- bank->irq = res->start; + bank->dev = dev; + bank->chip.dev = dev; + bank->chip.owner = THIS_MODULE; diff --git a/patches/0014-gpio-omap-fix-omap2_set_gpio_debounce.patch b/patches/0014-gpio-omap-fix-omap2_set_gpio_debounce.patch new file mode 100644 index 00000000000000..c21c73f5463b0a --- /dev/null +++ b/patches/0014-gpio-omap-fix-omap2_set_gpio_debounce.patch @@ -0,0 +1,95 @@ +From e02e1a208b803111ba52cc321a419378e9ed63bd Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 31 Aug 2015 18:52:23 +0300 +Subject: [PATCH 14/21] gpio: omap: fix omap2_set_gpio_debounce +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to TRMs: + +Required input line stable = + (the value of the GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) × 31, +where the value of the GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME bit field +is from 0 to 255. + +But now omap2_set_gpio_debounce() will calculate debounce time and +behave incorrectly in the following cases: +1) requested debounce time is !0 and <32 + calculated DEBOUNCETIME = 0x1 == 62 us; + expected value of DEBOUNCETIME = 0x0 == 31us +2) requested debounce time is 0 + calculated DEBOUNCETIME = 0x1 == 62 us; + expected: disable debounce and DEBOUNCETIME = 0x0 +3) requested debounce time is >32 and <63 + calculated DEBOUNCETIME = 0x0 and debounce will be disabled; + expected: enable debounce and DEBOUNCETIME = 0x1 == 62 us + +Hence, rework omap2_set_gpio_debounce() to fix above cases: +1) introduce local variable "enable" and use it to identify +when debounce need to be enabled or disabled. Disable debounce +if requested debounce time is 0. +2) use below formula for debounce time calculation: + debounce = (DIV_ROUND_UP(debounce, 31) - 1) & 0xFF; + +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-omap.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -29,6 +29,7 @@ + #include <linux/platform_data/gpio-omap.h> + + #define OFF_MODE 1 ++#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF + + static LIST_HEAD(omap_gpio_list); + +@@ -204,8 +205,9 @@ static inline void omap_gpio_dbck_disabl + * @offset: the gpio number on this @bank + * @debounce: debounce time to use + * +- * OMAP's debounce time is in 31us steps so we need +- * to convert and round up to the closest unit. ++ * OMAP's debounce time is in 31us steps ++ * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 ++ * so we need to convert and round up to the closest unit. + */ + static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, + unsigned debounce) +@@ -213,16 +215,15 @@ static void omap2_set_gpio_debounce(stru + void __iomem *reg; + u32 val; + u32 l; ++ bool enable = !!debounce; + + if (!bank->dbck_flag) + return; + +- if (debounce < 32) +- debounce = 0x01; +- else if (debounce > 7936) +- debounce = 0xff; +- else +- debounce = (debounce / 0x1f) - 1; ++ if (enable) { ++ debounce = DIV_ROUND_UP(debounce, 31) - 1; ++ debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; ++ } + + l = BIT(offset); + +@@ -233,7 +234,7 @@ static void omap2_set_gpio_debounce(stru + reg = bank->base + bank->regs->debounce_en; + val = readl_relaxed(reg); + +- if (debounce) ++ if (enable) + val |= l; + else + val &= ~l; diff --git a/patches/0015-gpio-omap-protect-regs-access-in-omap_gpio_irq_handl.patch b/patches/0015-gpio-omap-protect-regs-access-in-omap_gpio_irq_handl.patch new file mode 100644 index 00000000000000..010e99a7530656 --- /dev/null +++ b/patches/0015-gpio-omap-protect-regs-access-in-omap_gpio_irq_handl.patch @@ -0,0 +1,63 @@ +From ec29016aefaf6649096224bc9031a303cb21df47 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 31 Aug 2015 18:52:24 +0300 +Subject: [PATCH 15/21] gpio: omap: protect regs access in + omap_gpio_irq_handler + +The access to HW registers has to be be protected in +omap_gpio_irq_handler(), as it may race with code executed on +another CPUs. + +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-omap.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -718,6 +718,7 @@ static void omap_gpio_irq_handler(unsign + int unmasked = 0; + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_get_handler_data(irq); ++ unsigned long lock_flags; + + chained_irq_enter(irqchip, desc); + +@@ -732,6 +733,8 @@ static void omap_gpio_irq_handler(unsign + u32 isr_saved, level_mask = 0; + u32 enabled; + ++ raw_spin_lock_irqsave(&bank->lock, lock_flags); ++ + enabled = omap_get_gpio_irqbank_mask(bank); + isr_saved = isr = readl_relaxed(isr_reg) & enabled; + +@@ -745,6 +748,8 @@ static void omap_gpio_irq_handler(unsign + omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask); + omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask); + ++ raw_spin_unlock_irqrestore(&bank->lock, lock_flags); ++ + /* if there is only edge sensitive GPIO pin interrupts + configured, we could unmask GPIO bank interrupt immediately */ + if (!level_mask && !unmasked) { +@@ -759,6 +764,7 @@ static void omap_gpio_irq_handler(unsign + bit = __ffs(isr); + isr &= ~(BIT(bit)); + ++ raw_spin_lock_irqsave(&bank->lock, lock_flags); + /* + * Some chips can't respond to both rising and falling + * at the same time. If this irq was requested with +@@ -769,6 +775,8 @@ static void omap_gpio_irq_handler(unsign + if (bank->toggle_mask & (BIT(bit))) + omap_toggle_gpio_edge_triggering(bank, bit); + ++ raw_spin_unlock_irqrestore(&bank->lock, lock_flags); ++ + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, + bit)); + } diff --git a/patches/0016-gpio-omap-fix-clk_prepare-unprepare-usage.patch b/patches/0016-gpio-omap-fix-clk_prepare-unprepare-usage.patch new file mode 100644 index 00000000000000..b7f81f2bb53279 --- /dev/null +++ b/patches/0016-gpio-omap-fix-clk_prepare-unprepare-usage.patch @@ -0,0 +1,120 @@ +From 72f110f4546f9fff10bdeeb13f075c6263abe8ff Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 31 Aug 2015 18:52:25 +0300 +Subject: [PATCH 16/21] gpio: omap: fix clk_prepare/unprepare usage + +As per CCF documentation (clk.txt) the clk_prepare/unprepare APIs +are not allowed in atomic context. But now OMAP GPIO driver +uses them while applying debounce settings and as part +of PM runtime irqsafe operations: + +- omap_gpio_debounce() is holding the lock with IRQs off. + + omap2_set_gpio_debounce() + + clk_prepare_enable() + + clk_prepare() this one might sleep. + +- pm_runtime_get_sync() is holding the lock with IRQs off + + omap_gpio_runtime_suspend() + + raw_spin_lock_irqsave() + + omap_gpio_dbck_disable() + + clk_disable_unprepare() + +Hence, fix it by moeving dbclk prepare/unprepare in OMAP GPIO +omap_gpio_probe/omap_gpio_remove. Also, while here, ensure that +debounce functionality is disabled if clk_get() failed, +because otherwise kernel will carsh in omap2_set_gpio_debounce(). + +Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +--- + drivers/gpio/gpio-omap.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -176,7 +176,7 @@ static inline void omap_gpio_rmw(void __ + static inline void omap_gpio_dbck_enable(struct gpio_bank *bank) + { + if (bank->dbck_enable_mask && !bank->dbck_enabled) { +- clk_prepare_enable(bank->dbck); ++ clk_enable(bank->dbck); + bank->dbck_enabled = true; + + writel_relaxed(bank->dbck_enable_mask, +@@ -194,7 +194,7 @@ static inline void omap_gpio_dbck_disabl + */ + writel_relaxed(0, bank->base + bank->regs->debounce_en); + +- clk_disable_unprepare(bank->dbck); ++ clk_disable(bank->dbck); + bank->dbck_enabled = false; + } + } +@@ -227,7 +227,7 @@ static void omap2_set_gpio_debounce(stru + + l = BIT(offset); + +- clk_prepare_enable(bank->dbck); ++ clk_enable(bank->dbck); + reg = bank->base + bank->regs->debounce; + writel_relaxed(debounce, reg); + +@@ -241,7 +241,7 @@ static void omap2_set_gpio_debounce(stru + bank->dbck_enable_mask = val; + + writel_relaxed(val, reg); +- clk_disable_unprepare(bank->dbck); ++ clk_disable(bank->dbck); + /* + * Enable debounce clock per module. + * This call is mandatory because in omap_gpio_request() when +@@ -286,7 +286,7 @@ static void omap_clear_gpio_debounce(str + bank->context.debounce = 0; + writel_relaxed(bank->context.debounce, bank->base + + bank->regs->debounce); +- clk_disable_unprepare(bank->dbck); ++ clk_disable(bank->dbck); + bank->dbck_enabled = false; + } + } +@@ -1070,10 +1070,6 @@ static void omap_gpio_mod_init(struct gp + /* Initialize interface clk ungated, module enabled */ + if (bank->regs->ctrl) + writel_relaxed(0, base + bank->regs->ctrl); +- +- bank->dbck = clk_get(bank->dev, "dbclk"); +- if (IS_ERR(bank->dbck)) +- dev_err(bank->dev, "Could not get gpio dbck\n"); + } + + static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) +@@ -1228,6 +1224,17 @@ static int omap_gpio_probe(struct platfo + return PTR_ERR(bank->base); + } + ++ if (bank->dbck_flag) { ++ bank->dbck = devm_clk_get(bank->dev, "dbclk"); ++ if (IS_ERR(bank->dbck)) { ++ dev_err(bank->dev, ++ "Could not get gpio dbck. Disable debounce\n"); ++ bank->dbck_flag = false; ++ } else { ++ clk_prepare(bank->dbck); ++ } ++ } ++ + platform_set_drvdata(pdev, bank); + + pm_runtime_enable(bank->dev); +@@ -1259,6 +1266,8 @@ static int omap_gpio_remove(struct platf + list_del(&bank->node); + gpiochip_remove(&bank->chip); + pm_runtime_disable(bank->dev); ++ if (bank->dbck_flag) ++ clk_unprepare(bank->dbck); + + return 0; + } diff --git a/patches/0017-gpio-omap-Fix-gpiochip_add-handling-for-deferred-pro.patch b/patches/0017-gpio-omap-Fix-gpiochip_add-handling-for-deferred-pro.patch new file mode 100644 index 00000000000000..b83f8ce541eaba --- /dev/null +++ b/patches/0017-gpio-omap-Fix-gpiochip_add-handling-for-deferred-pro.patch @@ -0,0 +1,44 @@ +From f8ed3ff1efe8be27483c48d06974f8026dd673dd Mon Sep 17 00:00:00 2001 +From: Tony Lindgren <tony@atomide.com> +Date: Mon, 28 Sep 2015 18:36:12 -0500 +Subject: [PATCH 17/21] gpio: omap: Fix gpiochip_add() handling for deferred + probe + +commit 5e606abef57a89b3ca25f5d97a953c6cdad7cbac upstream. + +Currently we gpio-omap breaks if gpiochip_add() returns -EPROBE_DEFER: + +[ 0.570000] gpiochip_add: GPIOs 0..31 (gpio) failed to register +[ 0.570000] omap_gpio 48310000.gpio: Could not register gpio chip -517 +... +[ 3.670000] omap_gpio 48310000.gpio: Unbalanced pm_runtime_enable! + +Let's fix the issue by adding the missing pm_runtime_put() on error. + +Cc: Grygorii Strashko <grygorii.strashko@ti.com> +Cc: Javier Martinez Canillas <javier@dowhile0.org> +Cc: Kevin Hilman <khilman@deeprootsystems.com> +Cc: Santosh Shilimkar <ssantosh@kernel.org> +Acked-by: Santosh Shilimkar <ssantosh@kernel.org> +Signed-off-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -1247,8 +1247,11 @@ static int omap_gpio_probe(struct platfo + omap_gpio_mod_init(bank); + + ret = omap_gpio_chip_init(bank, irqc); +- if (ret) ++ if (ret) { ++ pm_runtime_put_sync(bank->dev); ++ pm_runtime_disable(bank->dev); + return ret; ++ } + + omap_gpio_show_rev(bank); + diff --git a/patches/0018-gpio-omap-Fix-GPIO-numbering-for-deferred-probe.patch b/patches/0018-gpio-omap-Fix-GPIO-numbering-for-deferred-probe.patch new file mode 100644 index 00000000000000..ec56c6279c8512 --- /dev/null +++ b/patches/0018-gpio-omap-Fix-GPIO-numbering-for-deferred-probe.patch @@ -0,0 +1,43 @@ +From 1cda618ade93f4439e17e8159182b035e9c189c9 Mon Sep 17 00:00:00 2001 +From: Tony Lindgren <tony@atomide.com> +Date: Mon, 28 Sep 2015 18:36:13 -0500 +Subject: [PATCH 18/21] gpio: omap: Fix GPIO numbering for deferred probe + +commit 46d4f7c25e1bb59b1663878b843a7ec06eaf5806 upstream. + +If gpio-omap probe fails with -EPROBE_DEFER, the GPIO numbering +keeps increasing. Only increase the gpio count if gpiochip_add() +was successful as otherwise the numbers will increase for each +probe attempt. + +Cc: Javier Martinez Canillas <javier@dowhile0.org> +Cc: Kevin Hilman <khilman@deeprootsystems.com> +Cc: Santosh Shilimkar <ssantosh@kernel.org> +Reviewed-by: Grygorii Strashko <grygorii.strashko@ti.com> +Signed-off-by: Tony Lindgren <tony@atomide.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -1098,7 +1098,6 @@ static int omap_gpio_chip_init(struct gp + } else { + bank->chip.label = "gpio"; + bank->chip.base = gpio; +- gpio += bank->width; + } + bank->chip.ngpio = bank->width; + +@@ -1108,6 +1107,9 @@ static int omap_gpio_chip_init(struct gp + return ret; + } + ++ if (!bank->is_mpuio) ++ gpio += bank->width; ++ + #ifdef CONFIG_ARCH_OMAP1 + /* + * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop diff --git a/patches/0019-gpio-omap-fix-static-checker-warning.patch b/patches/0019-gpio-omap-fix-static-checker-warning.patch new file mode 100644 index 00000000000000..9d6993921f809c --- /dev/null +++ b/patches/0019-gpio-omap-fix-static-checker-warning.patch @@ -0,0 +1,47 @@ +From 58ac52221b71c6a7e067ebe2f13e595cb99e17b6 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 28 Sep 2015 18:36:14 -0500 +Subject: [PATCH 19/21] gpio: omap: fix static checker warning + +This patch fixes below static checker warning by changing +type of irq field in struct gpio_bank from u16 to int. + +drivers/gpio/gpio-omap.c:1191 omap_gpio_probe() + warn: assigning (-6) to unsigned variable 'bank->irq' + +drivers/gpio/gpio-omap.c + 1188 bank->irq = platform_get_irq(pdev, 0); + 1189 if (bank->irq <= 0) { + +bank->irq is u16. + + 1190 if (!bank->irq) + 1191 bank->irq = -ENXIO; + +Does not work. + + 1192 if (bank->irq != -EPROBE_DEFER) + +Does not work. + + 1193 dev_err(dev, + 1194 "can't get irq resource ret=%d\n", bank->irq); + 1195 return bank->irq; + 1196 } + +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -51,7 +51,7 @@ struct gpio_regs { + struct gpio_bank { + struct list_head node; + void __iomem *base; +- u16 irq; ++ int irq; + u32 non_wakeup_gpios; + u32 enabled_non_wakeup_gpios; + struct gpio_regs context; diff --git a/patches/0020-gpio-omap-move-pm-runtime-in-irq_chip.irq_bus_lock-s.patch b/patches/0020-gpio-omap-move-pm-runtime-in-irq_chip.irq_bus_lock-s.patch new file mode 100644 index 00000000000000..b11be591c1f0e1 --- /dev/null +++ b/patches/0020-gpio-omap-move-pm-runtime-in-irq_chip.irq_bus_lock-s.patch @@ -0,0 +1,133 @@ +From c82f51eada9730a1b1c07c75a036a1a893964e49 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 28 Sep 2015 18:36:15 -0500 +Subject: [PATCH 20/21] gpio: omap: move pm runtime in + irq_chip.irq_bus_lock/sync_unlock + +The PM runtime API can't be used in atomic contex on -RT even if +it's configured as irqsafe. As result, below error report can +be seen when PM runtime API called from IRQ chip's callbacks +irq_startup/irq_shutdown/irq_set_type, because they are +protected by RAW spinlock: + +BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:917 +in_atomic(): 1, irqs_disabled(): 128, pid: 96, name: insmod +3 locks held by insmod/96: + #0: (&dev->mutex){......}, at: [<c04752c8>] __driver_attach+0x54/0xa0 + #1: (&dev->mutex){......}, at: [<c04752d4>] __driver_attach+0x60/0xa0 + #2: (class){......}, at: [<c00a408c>] __irq_get_desc_lock+0x60/0xa4 +irq event stamp: 1834 +hardirqs last enabled at (1833): [<c06ab2a4>] _raw_spin_unlock_irqrestore+0x88/0x90 +hardirqs last disabled at (1834): [<c06ab068>] _raw_spin_lock_irqsave+0x2c/0x64 +softirqs last enabled at (0): [<c003d220>] copy_process.part.52+0x410/0x19d8 +softirqs last disabled at (0): [< (null)>] (null) +Preemption disabled at:[< (null)>] (null) + +CPU: 1 PID: 96 Comm: insmod Tainted: G W O 4.1.3-rt3-00618-g57e2387-dirty #184 +Hardware name: Generic DRA74X (Flattened Device Tree) +[<c00190f4>] (unwind_backtrace) from [<c0014734>] (show_stack+0x20/0x24) +[<c0014734>] (show_stack) from [<c06a62ec>] (dump_stack+0x88/0xdc) +[<c06a62ec>] (dump_stack) from [<c006ca44>] (___might_sleep+0x198/0x2a8) +[<c006ca44>] (___might_sleep) from [<c06ab6d4>] (rt_spin_lock+0x30/0x70) +[<c06ab6d4>] (rt_spin_lock) from [<c04815ac>] (__pm_runtime_resume+0x68/0xa4) +[<c04815ac>] (__pm_runtime_resume) from [<c04123f4>] (omap_gpio_irq_type+0x188/0x1d8) +[<c04123f4>] (omap_gpio_irq_type) from [<c00a64e4>] (__irq_set_trigger+0x68/0x130) +[<c00a64e4>] (__irq_set_trigger) from [<c00a7bc4>] (irq_set_irq_type+0x44/0x6c) +[<c00a7bc4>] (irq_set_irq_type) from [<c00abbf8>] (irq_create_of_mapping+0x120/0x174) +[<c00abbf8>] (irq_create_of_mapping) from [<c0577b74>] (of_irq_get+0x48/0x58) +[<c0577b74>] (of_irq_get) from [<c0540a14>] (i2c_device_probe+0x54/0x15c) +[<c0540a14>] (i2c_device_probe) from [<c04750dc>] (driver_probe_device+0x184/0x2c8) +[<c04750dc>] (driver_probe_device) from [<c0475310>] (__driver_attach+0x9c/0xa0) +[<c0475310>] (__driver_attach) from [<c0473238>] (bus_for_each_dev+0x7c/0xb0) +[<c0473238>] (bus_for_each_dev) from [<c0474af4>] (driver_attach+0x28/0x30) +[<c0474af4>] (driver_attach) from [<c0474760>] (bus_add_driver+0x154/0x200) +[<c0474760>] (bus_add_driver) from [<c0476348>] (driver_register+0x88/0x108) +[<c0476348>] (driver_register) from [<c0541600>] (i2c_register_driver+0x3c/0x90) +[<c0541600>] (i2c_register_driver) from [<bf003018>] (pcf857x_init+0x18/0x24 [gpio_pcf857x]) +[<bf003018>] (pcf857x_init [gpio_pcf857x]) from [<c000998c>] (do_one_initcall+0x128/0x1e8) +[<c000998c>] (do_one_initcall) from [<c06a4220>] (do_init_module+0x6c/0x1bc) +[<c06a4220>] (do_init_module) from [<c00dd0c8>] (load_module+0x18e8/0x21c4) +[<c00dd0c8>] (load_module) from [<c00ddaa0>] (SyS_init_module+0xfc/0x158) +[<c00ddaa0>] (SyS_init_module) from [<c000ff40>] (ret_fast_syscall+0x0/0x54) + +The IRQ chip interface defines only two callbacks which are executed in +non-atomic contex - irq_bus_lock/irq_bus_sync_unlock, so lets move +PM runtime calls there. + +Cc: <linux-rt-users@vger.kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Tested-by: Austin Schuh <austin@peloton-tech.com> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -496,9 +496,6 @@ static int omap_gpio_irq_type(struct irq + (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) + return -EINVAL; + +- if (!BANK_USED(bank)) +- pm_runtime_get_sync(bank->dev); +- + raw_spin_lock_irqsave(&bank->lock, flags); + retval = omap_set_gpio_triggering(bank, offset, type); + if (retval) { +@@ -521,8 +518,6 @@ static int omap_gpio_irq_type(struct irq + return 0; + + error: +- if (!BANK_USED(bank)) +- pm_runtime_put(bank->dev); + return retval; + } + +@@ -797,9 +792,6 @@ static unsigned int omap_gpio_irq_startu + unsigned long flags; + unsigned offset = d->hwirq; + +- if (!BANK_USED(bank)) +- pm_runtime_get_sync(bank->dev); +- + raw_spin_lock_irqsave(&bank->lock, flags); + + if (!LINE_USED(bank->mod_usage, offset)) +@@ -815,8 +807,6 @@ static unsigned int omap_gpio_irq_startu + return 0; + err: + raw_spin_unlock_irqrestore(&bank->lock, flags); +- if (!BANK_USED(bank)) +- pm_runtime_put(bank->dev); + return -EINVAL; + } + +@@ -835,6 +825,19 @@ static void omap_gpio_irq_shutdown(struc + omap_clear_gpio_debounce(bank, offset); + omap_disable_gpio_module(bank, offset); + raw_spin_unlock_irqrestore(&bank->lock, flags); ++} ++ ++static void omap_gpio_irq_bus_lock(struct irq_data *data) ++{ ++ struct gpio_bank *bank = omap_irq_data_get_bank(data); ++ ++ if (!BANK_USED(bank)) ++ pm_runtime_get_sync(bank->dev); ++} ++ ++static void gpio_irq_bus_sync_unlock(struct irq_data *data) ++{ ++ struct gpio_bank *bank = omap_irq_data_get_bank(data); + + /* + * If this is the last IRQ to be freed in the bank, +@@ -1183,6 +1186,8 @@ static int omap_gpio_probe(struct platfo + irqc->irq_unmask = omap_gpio_unmask_irq, + irqc->irq_set_type = omap_gpio_irq_type, + irqc->irq_set_wake = omap_gpio_wake_enable, ++ irqc->irq_bus_lock = omap_gpio_irq_bus_lock, ++ irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock, + irqc->name = dev_name(&pdev->dev); + + bank->irq = platform_get_irq(pdev, 0); diff --git a/patches/0021-gpio-omap-convert-to-use-generic-irq-handler.patch b/patches/0021-gpio-omap-convert-to-use-generic-irq-handler.patch new file mode 100644 index 00000000000000..c30e6fbc6440e2 --- /dev/null +++ b/patches/0021-gpio-omap-convert-to-use-generic-irq-handler.patch @@ -0,0 +1,184 @@ +From a53b71a3646765698f8280c1889412575ea1d7f5 Mon Sep 17 00:00:00 2001 +From: Grygorii Strashko <grygorii.strashko@ti.com> +Date: Mon, 28 Sep 2015 18:36:16 -0500 +Subject: [PATCH 21/21] gpio: omap: convert to use generic irq handler + +This patch converts TI OMAP GPIO driver to use generic irq handler +instead of chained IRQ handler. This way OMAP GPIO driver will be +compatible with RT kernel where it will be forced thread IRQ handler +while in non-RT kernel it still will be executed in HW IRQ context. +As part of this change the IRQ wakeup configuration is applied to +GPIO Bank IRQ as it now will be under control of IRQ PM Core during +suspend. + +There are also additional benefits: + - on-RT kernel there will be no complains any more about PM runtime usage + in atomic context "BUG: sleeping function called from invalid context"; + - GPIO bank IRQs will appear in /proc/interrupts and its usage statistic + will be visible; + - GPIO bank IRQs could be configured through IRQ proc_fs interface and, + as result, could be a part of IRQ balancing process if needed; + - GPIO bank IRQs will be under control of IRQ PM Core during + suspend to RAM. + +Disadvantage: + - additional runtime overhed as call chain till + omap_gpio_irq_handler() will be longer now + - necessity to use wa_lock in omap_gpio_irq_handler() to W/A warning + in handle_irq_event_percpu() + WARNING: CPU: 1 PID: 35 at kernel/irq/handle.c:149 handle_irq_event_percpu+0x51c/0x638() + +This patch doesn't fully follows recommendations provided by Sebastian +Andrzej Siewior [1], because It's required to go through and check all +GPIO IRQ pin states as fast as possible and pass control to handle_level_irq +or handle_edge_irq. handle_level_irq or handle_edge_irq will perform actions +specific for IRQ triggering type and wakeup corresponding registered +threaded IRQ handler (at least it's expected to be threaded). +IRQs can be lost if handle_nested_irq() will be used, because excecution +time of some pin specific GPIO IRQ handler can be very significant and +require accessing ext. devices (I2C). + +Idea of such kind reworking was also discussed in [2]. + +[1] http://www.spinics.net/lists/linux-omap/msg120665.html +[2] http://www.spinics.net/lists/linux-omap/msg119516.html + +Cc: <linux-rt-users@vger.kernel.org> +Tested-by: Tony Lindgren <tony@atomide.com> +Tested-by: Austin Schuh <austin@peloton-tech.com> +Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> +--- + drivers/gpio/gpio-omap.c | 55 +++++++++++++++++++++++------------------------ + 1 file changed, 27 insertions(+), 28 deletions(-) + +--- a/drivers/gpio/gpio-omap.c ++++ b/drivers/gpio/gpio-omap.c +@@ -59,6 +59,7 @@ struct gpio_bank { + u32 level_mask; + u32 toggle_mask; + raw_spinlock_t lock; ++ raw_spinlock_t wa_lock; + struct gpio_chip chip; + struct clk *dbck; + u32 mod_usage; +@@ -649,8 +650,13 @@ static int omap_gpio_wake_enable(struct + { + struct gpio_bank *bank = omap_irq_data_get_bank(d); + unsigned offset = d->hwirq; ++ int ret; ++ ++ ret = omap_set_gpio_wakeup(bank, offset, enable); ++ if (!ret) ++ ret = irq_set_irq_wake(bank->irq, enable); + +- return omap_set_gpio_wakeup(bank, offset, enable); ++ return ret; + } + + static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) +@@ -704,26 +710,21 @@ static void omap_gpio_free(struct gpio_c + * line's interrupt handler has been run, we may miss some nested + * interrupts. + */ +-static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank) + { + void __iomem *isr_reg = NULL; + u32 isr; + unsigned int bit; +- struct gpio_bank *bank; +- int unmasked = 0; +- struct irq_chip *irqchip = irq_desc_get_chip(desc); +- struct gpio_chip *chip = irq_get_handler_data(irq); ++ struct gpio_bank *bank = gpiobank; ++ unsigned long wa_lock_flags; + unsigned long lock_flags; + +- chained_irq_enter(irqchip, desc); +- +- bank = container_of(chip, struct gpio_bank, chip); + isr_reg = bank->base + bank->regs->irqstatus; +- pm_runtime_get_sync(bank->dev); +- + if (WARN_ON(!isr_reg)) + goto exit; + ++ pm_runtime_get_sync(bank->dev); ++ + while (1) { + u32 isr_saved, level_mask = 0; + u32 enabled; +@@ -745,13 +746,6 @@ static void omap_gpio_irq_handler(unsign + + raw_spin_unlock_irqrestore(&bank->lock, lock_flags); + +- /* if there is only edge sensitive GPIO pin interrupts +- configured, we could unmask GPIO bank interrupt immediately */ +- if (!level_mask && !unmasked) { +- unmasked = 1; +- chained_irq_exit(irqchip, desc); +- } +- + if (!isr) + break; + +@@ -772,18 +766,18 @@ static void omap_gpio_irq_handler(unsign + + raw_spin_unlock_irqrestore(&bank->lock, lock_flags); + ++ raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags); ++ + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, + bit)); ++ ++ raw_spin_unlock_irqrestore(&bank->wa_lock, ++ wa_lock_flags); + } + } +- /* if bank has any level sensitive GPIO pin interrupt +- configured, we must unmask the bank interrupt only after +- handler(s) are executed in order to avoid spurious bank +- interrupt */ + exit: +- if (!unmasked) +- chained_irq_exit(irqchip, desc); + pm_runtime_put(bank->dev); ++ return IRQ_HANDLED; + } + + static unsigned int omap_gpio_irq_startup(struct irq_data *d) +@@ -1135,7 +1129,7 @@ static int omap_gpio_chip_init(struct gp + } + + ret = gpiochip_irqchip_add(&bank->chip, irqc, +- irq_base, omap_gpio_irq_handler, ++ irq_base, handle_bad_irq, + IRQ_TYPE_NONE); + + if (ret) { +@@ -1144,10 +1138,14 @@ static int omap_gpio_chip_init(struct gp + return -ENODEV; + } + +- gpiochip_set_chained_irqchip(&bank->chip, irqc, +- bank->irq, omap_gpio_irq_handler); ++ gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL); + +- return 0; ++ ret = devm_request_irq(bank->dev, bank->irq, omap_gpio_irq_handler, ++ 0, dev_name(bank->dev), bank); ++ if (ret) ++ gpiochip_remove(&bank->chip); ++ ++ return ret; + } + + static const struct of_device_id omap_gpio_match[]; +@@ -1223,6 +1221,7 @@ static int omap_gpio_probe(struct platfo + bank->set_dataout = omap_set_gpio_dataout_mask; + + raw_spin_lock_init(&bank->lock); ++ raw_spin_lock_init(&bank->wa_lock); + + /* Static mapping, never released */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/patches/KVM-lapic-mark-LAPIC-timer-handler-as-irqsafe.patch b/patches/KVM-lapic-mark-LAPIC-timer-handler-as-irqsafe.patch index 875dc538bc9a0a..7440ee2bf35472 100644 --- a/patches/KVM-lapic-mark-LAPIC-timer-handler-as-irqsafe.patch +++ b/patches/KVM-lapic-mark-LAPIC-timer-handler-as-irqsafe.patch @@ -18,7 +18,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c -@@ -1167,8 +1167,36 @@ void wait_lapic_expire(struct kvm_vcpu * +@@ -1169,8 +1169,36 @@ void wait_lapic_expire(struct kvm_vcpu * __delay(tsc_deadline - guest_tsc); } @@ -55,7 +55,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> ktime_t now; atomic_set(&apic->lapic_timer.pending, 0); -@@ -1199,9 +1227,11 @@ static void start_apic_timer(struct kvm_ +@@ -1201,9 +1229,11 @@ static void start_apic_timer(struct kvm_ } } @@ -68,7 +68,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" PRIx64 ", " -@@ -1233,8 +1263,10 @@ static void start_apic_timer(struct kvm_ +@@ -1235,8 +1265,10 @@ static void start_apic_timer(struct kvm_ do_div(ns, this_tsc_khz); expire = ktime_add_ns(now, ns); expire = ktime_sub_ns(expire, lapic_timer_advance_ns); @@ -80,7 +80,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } else apic_timer_expired(apic); -@@ -1707,6 +1739,7 @@ int kvm_create_lapic(struct kvm_vcpu *vc +@@ -1709,6 +1741,7 @@ int kvm_create_lapic(struct kvm_vcpu *vc hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); apic->lapic_timer.timer.function = apic_timer_fn; @@ -88,7 +88,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> /* * APIC is created enabled. This will prevent kvm_lapic_set_base from -@@ -1834,7 +1867,8 @@ void __kvm_migrate_apic_timer(struct kvm +@@ -1836,7 +1869,8 @@ void __kvm_migrate_apic_timer(struct kvm timer = &vcpu->arch.apic->lapic_timer.timer; if (hrtimer_cancel(timer)) diff --git a/patches/KVM-use-simple-waitqueue-for-vcpu-wq.patch b/patches/KVM-use-simple-waitqueue-for-vcpu-wq.patch index 9ec1315628bcef..16160641401fa5 100644 --- a/patches/KVM-use-simple-waitqueue-for-vcpu-wq.patch +++ b/patches/KVM-use-simple-waitqueue-for-vcpu-wq.patch @@ -224,7 +224,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> } --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c -@@ -1104,7 +1104,7 @@ static void apic_update_lvtt(struct kvm_ +@@ -1106,7 +1106,7 @@ static void apic_update_lvtt(struct kvm_ static void apic_timer_expired(struct kvm_lapic *apic) { struct kvm_vcpu *vcpu = apic->vcpu; @@ -233,7 +233,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> struct kvm_timer *ktimer = &apic->lapic_timer; if (atomic_read(&apic->lapic_timer.pending)) -@@ -1113,8 +1113,8 @@ static void apic_timer_expired(struct kv +@@ -1115,8 +1115,8 @@ static void apic_timer_expired(struct kv atomic_inc(&apic->lapic_timer.pending); kvm_set_pending_timer(vcpu); @@ -255,7 +255,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> struct pid *pid; int sigset_active; sigset_t sigset; -@@ -690,7 +690,7 @@ static inline bool kvm_arch_has_noncoher +@@ -701,7 +701,7 @@ static inline bool kvm_arch_has_noncoher } #endif diff --git a/patches/Revert-x86-Do-not-disable-preemption-in-int3-on-32bi.patch b/patches/Revert-x86-Do-not-disable-preemption-in-int3-on-32bi.patch new file mode 100644 index 00000000000000..a6cbd45a0c0eed --- /dev/null +++ b/patches/Revert-x86-Do-not-disable-preemption-in-int3-on-32bi.patch @@ -0,0 +1,90 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Tue, 22 Dec 2015 12:17:39 +0100 +Subject: Revert "x86: Do not disable preemption in int3 on 32bit" + +Since commit 959274753857 ("x86, traps: Track entry into and exit from +IST context") we always disable preemption. Which means the original +patch is no longer usefull. +The patch mentioned is part of v4.0-rc1+ + +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/x86/kernel/traps.c | 28 +++++++--------------------- + 1 file changed, 7 insertions(+), 21 deletions(-) + +--- a/arch/x86/kernel/traps.c ++++ b/arch/x86/kernel/traps.c +@@ -88,21 +88,9 @@ static inline void conditional_sti(struc + local_irq_enable(); + } + +-static inline void conditional_sti_ist(struct pt_regs *regs) ++static inline void preempt_conditional_sti(struct pt_regs *regs) + { +-#ifdef CONFIG_X86_64 +- /* +- * X86_64 uses a per CPU stack on the IST for certain traps +- * like int3. The task can not be preempted when using one +- * of these stacks, thus preemption must be disabled, otherwise +- * the stack can be corrupted if the task is scheduled out, +- * and another task comes in and uses this stack. +- * +- * On x86_32 the task keeps its own stack and it is OK if the +- * task schedules out. +- */ + preempt_count_inc(); +-#endif + if (regs->flags & X86_EFLAGS_IF) + local_irq_enable(); + } +@@ -113,13 +101,11 @@ static inline void conditional_cli(struc + local_irq_disable(); + } + +-static inline void conditional_cli_ist(struct pt_regs *regs) ++static inline void preempt_conditional_cli(struct pt_regs *regs) + { + if (regs->flags & X86_EFLAGS_IF) + local_irq_disable(); +-#ifdef CONFIG_X86_64 + preempt_count_dec(); +-#endif + } + + enum ctx_state ist_enter(struct pt_regs *regs) +@@ -550,9 +536,9 @@ dotraplinkage void notrace do_int3(struc + * as we may switch to the interrupt stack. + */ + debug_stack_usage_inc(); +- conditional_sti_ist(regs); ++ preempt_conditional_sti(regs); + do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); +- conditional_cli_ist(regs); ++ preempt_conditional_cli(regs); + debug_stack_usage_dec(); + exit: + ist_exit(regs, prev_state); +@@ -682,12 +668,12 @@ dotraplinkage void do_debug(struct pt_re + debug_stack_usage_inc(); + + /* It's safe to allow irq's after DR6 has been saved */ +- conditional_sti_ist(regs); ++ preempt_conditional_sti(regs); + + if (v8086_mode(regs)) { + handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, + X86_TRAP_DB); +- conditional_cli_ist(regs); ++ preempt_conditional_cli(regs); + debug_stack_usage_dec(); + goto exit; + } +@@ -707,7 +693,7 @@ dotraplinkage void do_debug(struct pt_re + si_code = get_si_code(tsk->thread.debugreg6); + if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp) + send_sigtrap(tsk, regs, error_code, si_code); +- conditional_cli_ist(regs); ++ preempt_conditional_cli(regs); + debug_stack_usage_dec(); + + exit: diff --git a/patches/irqwork-Move-irq-safe-work-to-irq-context.patch b/patches/irqwork-Move-irq-safe-work-to-irq-context.patch index 99c5a41041c6a9..57a542ac3562de 100644 --- a/patches/irqwork-Move-irq-safe-work-to-irq-context.patch +++ b/patches/irqwork-Move-irq-safe-work-to-irq-context.patch @@ -20,10 +20,8 @@ Cc: stable-rt@vger.kernel.org kernel/time/timer.c | 6 ++---- 3 files changed, 17 insertions(+), 4 deletions(-) -Index: linux-rt-devel/include/linux/irq_work.h -=================================================================== ---- linux-rt-devel.orig/include/linux/irq_work.h -+++ linux-rt-devel/include/linux/irq_work.h +--- a/include/linux/irq_work.h ++++ b/include/linux/irq_work.h @@ -52,4 +52,10 @@ static inline bool irq_work_needs_cpu(vo static inline void irq_work_run(void) { } #endif @@ -35,10 +33,8 @@ Index: linux-rt-devel/include/linux/irq_work.h +#endif + #endif /* _LINUX_IRQ_WORK_H */ -Index: linux-rt-devel/kernel/irq_work.c -=================================================================== ---- linux-rt-devel.orig/kernel/irq_work.c -+++ linux-rt-devel/kernel/irq_work.c +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c @@ -200,8 +200,17 @@ void irq_work_tick(void) if (!llist_empty(raised) && !arch_irq_work_has_interrupt()) @@ -57,10 +53,8 @@ Index: linux-rt-devel/kernel/irq_work.c /* * Synchronize against the irq_work @entry, ensures the entry is not -Index: linux-rt-devel/kernel/time/timer.c -=================================================================== ---- linux-rt-devel.orig/kernel/time/timer.c -+++ linux-rt-devel/kernel/time/timer.c +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c @@ -1455,7 +1455,7 @@ void update_process_times(int user_tick) scheduler_tick(); run_local_timers(); diff --git a/patches/localversion.patch b/patches/localversion.patch index dee63a20fa3bba..a3b81e783166e2 100644 --- a/patches/localversion.patch +++ b/patches/localversion.patch @@ -1,4 +1,4 @@ -Subject: v4.1.15-rt16 +Subject: v4.1.15-rt17 From: Thomas Gleixner <tglx@linutronix.de> Date: Fri, 08 Jul 2011 20:25:16 +0200 @@ -10,4 +10,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- /dev/null +++ b/localversion-rt @@ -0,0 +1 @@ -+-rt16 ++-rt17 diff --git a/patches/rtmutex-Use-chainwalking-control-enum.patch b/patches/rtmutex-Use-chainwalking-control-enum.patch new file mode 100644 index 00000000000000..2ecfc54b064aba --- /dev/null +++ b/patches/rtmutex-Use-chainwalking-control-enum.patch @@ -0,0 +1,28 @@ +From 13f032043086194982ac91c68124adae545f5627 Mon Sep 17 00:00:00 2001 +From: "bmouring@ni.com" <bmouring@ni.com> +Date: Tue, 15 Dec 2015 17:07:30 -0600 +Subject: [PATCH] rtmutex: Use chainwalking control enum + +In 8930ed80 (rtmutex: Cleanup deadlock detector debug logic), +chainwalking control enums were introduced to limit the deadlock +detection logic. One of the calls to task_blocks_on_rt_mutex was +missed when converting to use the enums. + +Cc: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Brad Mouring <brad.mouring@ni.com> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + kernel/locking/rtmutex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/locking/rtmutex.c ++++ b/kernel/locking/rtmutex.c +@@ -1007,7 +1007,7 @@ static void noinline __sched rt_spin_lo + __set_current_state_no_track(TASK_UNINTERRUPTIBLE); + pi_unlock(&self->pi_lock); + +- ret = task_blocks_on_rt_mutex(lock, &waiter, self, 0); ++ ret = task_blocks_on_rt_mutex(lock, &waiter, self, RT_MUTEX_MIN_CHAINWALK); + BUG_ON(ret); + + for (;;) { diff --git a/patches/series b/patches/series index c9cf63a135c1a4..f90b2efe106988 100644 --- a/patches/series +++ b/patches/series @@ -89,7 +89,27 @@ kernel-SRCU-provide-a-static-initializer.patch ############################################################ # Stuff which should go upstream ASAP ############################################################ -gpio-omap-use-raw-locks-for-locking.patch +0001-gpio-omap-Allow-building-as-a-loadable-module.patch +0002-gpio-omap-fix-omap_gpio_free-to-not-clean-up-irq-con.patch +0003-gpio-omap-fix-error-handling-in-omap_gpio_irq_type.patch +0004-gpio-omap-rework-omap_x_irq_shutdown-to-touch-only-i.patch +0005-gpio-omap-rework-omap_gpio_request-to-touch-only-gpi.patch +0006-gpio-omap-rework-omap_gpio_irq_startup-to-handle-cur.patch +0007-gpio-omap-add-missed-spin_unlock_irqrestore-in-omap_.patch +0008-gpio-omap-prevent-module-from-being-unloaded-while-i.patch +0009-ARM-OMAP2-Drop-the-concept-of-certain-power-domains-.patch +0010-gpio-omap-use-raw-locks-for-locking.patch +0011-gpio-omap-Fix-missing-raw-locks-conversion.patch +0012-gpio-omap-remove-wrong-irq_domain_remove-usage-in-pr.patch +0013-gpio-omap-switch-to-use-platform_get_irq.patch +0014-gpio-omap-fix-omap2_set_gpio_debounce.patch +0015-gpio-omap-protect-regs-access-in-omap_gpio_irq_handl.patch +0016-gpio-omap-fix-clk_prepare-unprepare-usage.patch +0017-gpio-omap-Fix-gpiochip_add-handling-for-deferred-pro.patch +0018-gpio-omap-Fix-GPIO-numbering-for-deferred-probe.patch +0019-gpio-omap-fix-static-checker-warning.patch +0020-gpio-omap-move-pm-runtime-in-irq_chip.irq_bus_lock-s.patch +0021-gpio-omap-convert-to-use-generic-irq-handler.patch # SCHED BLOCK/WQ block-shorten-interrupt-disabled-regions.patch @@ -141,6 +161,7 @@ net-sched-dev_deactivate_many-use-msleep-1-instead-o.patch # X86 x86-io-apic-migra-no-unmask.patch fix-rt-int3-x86_32-3.2-rt.patch +Revert-x86-Do-not-disable-preemption-in-int3-on-32bi.patch # RCU @@ -210,6 +231,7 @@ mm-workingset-do-not-protect-workingset_shadow_nodes.patch # Sigh signal-fix-up-rcu-wreckage.patch oleg-signal-rt-fix.patch +x86-signal-delay-calling-signals-on-32bit.patch # ANNOTATE BUG/WARNON net-wireless-warn-nort.patch @@ -337,6 +359,7 @@ rtmutex-lock-killable.patch spinlock-types-separate-raw.patch rtmutex-avoid-include-hell.patch rt-add-rt-locks.patch +rtmutex-Use-chainwalking-control-enum.patch rtmutex-add-a-first-shot-of-ww_mutex.patch ptrace-fix-ptrace-vs-tasklist_lock-race.patch diff --git a/patches/x86-signal-delay-calling-signals-on-32bit.patch b/patches/x86-signal-delay-calling-signals-on-32bit.patch new file mode 100644 index 00000000000000..bd37c47fc92b90 --- /dev/null +++ b/patches/x86-signal-delay-calling-signals-on-32bit.patch @@ -0,0 +1,42 @@ +From: Yang Shi <yang.shi@linaro.org> +Date: Thu, 10 Dec 2015 10:58:51 -0800 +Subject: x86/signal: delay calling signals on 32bit + +When running some ptrace single step tests on x86-32 machine, the below problem +is triggered: + +BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:917 +in_atomic(): 1, irqs_disabled(): 0, pid: 1041, name: dummy2 +Preemption disabled at:[<c100326f>] do_debug+0x1f/0x1a0 + +CPU: 10 PID: 1041 Comm: dummy2 Tainted: G W 4.1.13-rt13 #1 +Call Trace: + [<c1aa8306>] dump_stack+0x46/0x5c + [<c1080517>] ___might_sleep+0x137/0x220 + [<c1ab0eff>] rt_spin_lock+0x1f/0x80 + [<c1064b5a>] do_force_sig_info+0x2a/0xc0 + [<c106567d>] force_sig_info+0xd/0x10 + [<c1010cff>] send_sigtrap+0x6f/0x80 + [<c10033b1>] do_debug+0x161/0x1a0 + [<c1ab2921>] debug_stack_correct+0x2e/0x35 + +This happens since 959274753857 ("x86, traps: Track entry into and exit +from IST context") which was merged in v4.1-rc1. + +Signed-off-by: Yang Shi <yang.shi@linaro.org> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + arch/x86/include/asm/signal.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/include/asm/signal.h ++++ b/arch/x86/include/asm/signal.h +@@ -32,7 +32,7 @@ typedef struct { + * TIF_NOTIFY_RESUME and set up the signal to be sent on exit of the + * trap. + */ +-#if defined(CONFIG_PREEMPT_RT_FULL) && defined(CONFIG_X86_64) ++#if defined(CONFIG_PREEMPT_RT_FULL) + #define ARCH_RT_DELAYS_SIGNAL_SEND + #endif + |