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 b9cd3d4..935b8d5 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 988d104..8672f29 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 fc7f7b3..6ecb53d 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 7260fb4..f305e46 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 78e7e18..6909ae6 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 c318e2c..5cc15e9 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);