pinctrl: samsung: fix wakeup irq for extended eint
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Thu, 9 Jun 2016 07:57:15 +0000 (16:57 +0900)
committerSeung-Woo Kim <sw0312.kim@samsung.com>
Wed, 29 Jun 2016 12:25:13 +0000 (21:25 +0900)
For extended eint bank, it should use maks1 for bit from 32 to 63
as its ext offset. So this patch fixes wakeup irq setting for
extended eit of exynos5433 with adding eint mask1 setting.

Without considering extended eint, setting wakeup on ext eint pin
causes wrong offset for eint mask, so UBSAN warning is repored
like following:

   UBSAN: Undefined behaviour in drivers/pinctrl/samsung/pinctrl-exynos.c:376:26
   shift exponent 8217 is too large for 64-bit type 'long unsigned int'
   Call trace:
   [<ffffffc00008f440>] dump_backtrace+0x0/0x218
   [<ffffffc00008f668>] show_stack+0x10/0x20
   [<ffffffc00159f3b8>] dump_stack+0x80/0xfc
   [<ffffffc00159f558>] ubsan_epilogue+0x10/0x6c
   [<ffffffc00159fe38>] __ubsan_handle_shift_out_of_bounds+0x188/0x1bc
   [<ffffffc000785514>] exynos_wkup_irq_set_wake+0x104/0x138
   [<ffffffc0001647b0>] set_irq_wake_real+0x70/0xc0
   [<ffffffc000164a70>] irq_set_irq_wake+0x158/0x1b0
   [...]

Change-Id: I6d55182609c982de702936ddb0045639df0e5ef0
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
drivers/pinctrl/samsung/pinctrl-exynos.c
drivers/pinctrl/samsung/pinctrl-exynos.h
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/samsung/pinctrl-samsung.h
drivers/soc/samsung/exynos-pmu.h
drivers/soc/samsung/exynos5433-pmu.c

index b9cd3d4d853330e2035daf0aeb067bc1204ab698..935b8d53f994d7a7a767d841690b5f361cb8d106 100644 (file)
@@ -363,17 +363,23 @@ err_domains:
        return ret;
 }
 
-static u32 exynos_eint_wake_mask = 0xffffffff;
+static u64 exynos_eint_wake_mask = 0xffffffffffffffff;
 
 u32 exynos_get_eint_wake_mask(void)
 {
-       return exynos_eint_wake_mask;
+       return (u32)exynos_eint_wake_mask;
+}
+
+u32 exynos_get_eint_wake_mask1(void)
+{
+       return (u32)(exynos_eint_wake_mask >> 32);
 }
 
 static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
 {
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
-       unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
+       u64 bit = 1ULL << ((bank->eint_ext ? bank->eint_ext_offset :
+                                   (2 * bank->eint_offset)) + irqd->hwirq);
 
        pr_info("wake %s for irq %d\n", on ? "enabled" : "disabled", irqd->irq);
 
@@ -1256,11 +1262,11 @@ static const struct samsung_pin_bank_data exynos5433_pin_banks0[] = {
        EXYNOS5433_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
        EXYNOS5433_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
        EXYNOS5433_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014),
+       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004, 0x20),
+       EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008, 0x28),
+       EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c, 0x2c),
+       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010, 0x30),
+       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014, 0x38),
 };
 
 /* pin banks of exynos5433 pin-controller - AUD */
index 988d1042c9ded7a01e9146809604a81c5f1bc2b1..8672f2912dc38d6612901e07eed4e21e98b12401 100644 (file)
                .name           = id                            \
        }
 
-#define EXYNOS5433_PIN_BANK_EINTW_EXT(pins, reg, id, offs)     \
-       {                                                       \
-               .type           = &bank_type_off_exynos5433,    \
-               .pctl_offset    = reg,                          \
-               .nr_pins        = pins,                         \
-               .eint_type      = EINT_TYPE_WKUP,               \
-               .eint_offset    = offs,                         \
-               .eint_ext       = true,                         \
-               .name           = id                            \
+#define EXYNOS5433_PIN_BANK_EINTW_EXT(pins, reg, id, offs, ext_offs)   \
+       {                                                               \
+               .type           = &bank_type_off_exynos5433,            \
+               .pctl_offset    = reg,                                  \
+               .nr_pins        = pins,                                 \
+               .eint_type      = EINT_TYPE_WKUP,                       \
+               .eint_offset    = offs,                                 \
+               .eint_ext       = true,                                 \
+               .eint_ext_offset= ext_offs,                             \
+               .name           = id                                    \
        }
 
 /**
index fc7f7b3294f3b4c0580f8e62e9918abb9a66c468..6ecb53d490ab0a97b79b3f2b9a78373f9bbfc496 100644 (file)
@@ -1015,6 +1015,7 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
                bank->eint_mask = bdata->eint_mask;
                bank->eint_offset = bdata->eint_offset;
                bank->eint_ext = bdata->eint_ext;
+               bank->eint_ext_offset = bdata->eint_ext_offset;
                bank->name = bdata->name;
 
                spin_lock_init(&bank->slock);
index 7260fb4768f820bfcdff1eb6f450804a2ca5545f..f305e46edba0386325dc2810c15ebe95175d8e1e 100644 (file)
@@ -132,6 +132,7 @@ struct samsung_pin_bank_data {
        u32             eint_mask;
        u32             eint_offset;
        bool            eint_ext;
+       u32             eint_ext_offset;
        const char      *name;
 };
 
@@ -165,6 +166,7 @@ struct samsung_pin_bank {
        u32             eint_mask;
        u32             eint_offset;
        bool            eint_ext;
+       u32             eint_ext_offset;
        const char      *name;
 
        u32             pin_base;
@@ -204,7 +206,6 @@ struct samsung_pin_ctrl {
  * @node: global list node
  * @virt_base: register base address of the controller.
  * @ext_base: external register base address of the controller.
- * @ext_base: external register base address of the controller.
  * @dev: device instance representing the controller.
  * @irq: interrpt number used by the controller to notify gpio interrupts.
  * @ctrl: pin controller instance managed by the driver.
index 78e7e18a3876733bd0a0b7a7ec5add14b189a668..6909ae670ff851c9cc5c79d9833c4551f86f8ea0 100644 (file)
@@ -49,6 +49,7 @@ static inline u32 pmu_raw_readl(u32 offset)
 }
 
 extern u32 exynos_get_eint_wake_mask(void);
+extern u32 exynos_get_eint_wake_mask1(void);
 
 /* list of all exported SoC specific data */
 extern const struct exynos_pmu_data exynos5433_pmu_data;
index c318e2c73f1f0afd6a2bb31aaf64b68b798a2a72..5cc15e921a9a68d1b9e5e8fd8d42ba1f8b3e243a 100644 (file)
@@ -276,7 +276,7 @@ static void exynos5433_set_wakeupmask(enum sys_powerdown mode)
        u32 intmask = 0;
 
        pmu_raw_writel(exynos_get_eint_wake_mask(), EXYNOS7_EINT_WAKEUP_MASK);
-       pmu_raw_writel(0xFFFFFFFF, EXYNOS7_EINT_WAKEUP_MASK_MIF1);
+       pmu_raw_writel(exynos_get_eint_wake_mask1(), EXYNOS7_EINT_WAKEUP_MASK_MIF1);
 
        /* Disable WAKEUP event monitor */
        intmask = pmu_raw_readl(EXYNOS7_WAKEUP_MASK);