From: Seung-Woo Kim Date: Thu, 9 Jun 2016 07:57:15 +0000 (+0900) Subject: pinctrl: samsung: fix wakeup irq for extended eint X-Git-Tag: submit/tizen/20160810.050017~134 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=367c75d2942b5fadf6faf92d06d096deb72de945;p=platform%2Fkernel%2Flinux-exynos.git pinctrl: samsung: fix wakeup irq for extended eint 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: [] dump_backtrace+0x0/0x218 [] show_stack+0x10/0x20 [] dump_stack+0x80/0xfc [] ubsan_epilogue+0x10/0x6c [] __ubsan_handle_shift_out_of_bounds+0x188/0x1bc [] exynos_wkup_irq_set_wake+0x104/0x138 [] set_irq_wake_real+0x70/0xc0 [] irq_set_irq_wake+0x158/0x1b0 [...] Change-Id: I6d55182609c982de702936ddb0045639df0e5ef0 Signed-off-by: Seung-Woo Kim --- diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index b9cd3d4d8533..935b8d53f994 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -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 */ diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 988d1042c9de..8672f2912dc3 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -110,15 +110,16 @@ .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 \ } /** diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index fc7f7b3294f3..6ecb53d490ab 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -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); diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index 7260fb4768f8..f305e46edba0 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -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. diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h index 78e7e18a3876..6909ae670ff8 100644 --- a/drivers/soc/samsung/exynos-pmu.h +++ b/drivers/soc/samsung/exynos-pmu.h @@ -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; diff --git a/drivers/soc/samsung/exynos5433-pmu.c b/drivers/soc/samsung/exynos5433-pmu.c index c318e2c73f1f..5cc15e921a9a 100644 --- a/drivers/soc/samsung/exynos5433-pmu.c +++ b/drivers/soc/samsung/exynos5433-pmu.c @@ -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);