lkml.org 
[lkml]   [2019]   [Jul]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 26/47] pinctrl: mediatek: Ignore interrupts that are wake only during resume
    Date
    [ Upstream commit 35594bc7cecf3a78504b590e350570e8f4d7779e ]

    Before suspending, mtk-eint would set the interrupt mask to the
    one in wake_mask. However, some of these interrupts may not have a
    corresponding interrupt handler, or the interrupt may be disabled.

    On resume, the eint irq handler would trigger nevertheless,
    and irq/pm.c:irq_pm_check_wakeup would be called, which would
    try to call irq_disable. However, if the interrupt is not enabled
    (irqd_irq_disabled(&desc->irq_data) is true), the call does nothing,
    and the interrupt is left enabled in the eint driver.

    Especially for level-sensitive interrupts, this will lead to an
    interrupt storm on resume.

    If we detect that an interrupt is only in wake_mask, but not in
    cur_mask, we can just mask it out immediately (as mtk_eint_resume
    would do anyway at a later stage in the resume sequence, when
    restoring cur_mask).

    Fixes: bf22ff45bed6 ("genirq: Avoid unnecessary low level irq function calls")
    Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
    Acked-by: Sean Wang <sean.wang@kernel.org>
    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/pinctrl/mediatek/mtk-eint.c | 16 +++++++++++++++-
    1 file changed, 15 insertions(+), 1 deletion(-)

    diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
    index a613e546717a..b9f3c02ba59d 100644
    --- a/drivers/pinctrl/mediatek/mtk-eint.c
    +++ b/drivers/pinctrl/mediatek/mtk-eint.c
    @@ -318,7 +318,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
    struct irq_chip *chip = irq_desc_get_chip(desc);
    struct mtk_eint *eint = irq_desc_get_handler_data(desc);
    unsigned int status, eint_num;
    - int offset, index, virq;
    + int offset, mask_offset, index, virq;
    void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
    int dual_edge, start_level, curr_level;

    @@ -328,10 +328,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
    status = readl(reg);
    while (status) {
    offset = __ffs(status);
    + mask_offset = eint_num >> 5;
    index = eint_num + offset;
    virq = irq_find_mapping(eint->domain, index);
    status &= ~BIT(offset);

    + /*
    + * If we get an interrupt on pin that was only required
    + * for wake (but no real interrupt requested), mask the
    + * interrupt (as would mtk_eint_resume do anyway later
    + * in the resume sequence).
    + */
    + if (eint->wake_mask[mask_offset] & BIT(offset) &&
    + !(eint->cur_mask[mask_offset] & BIT(offset))) {
    + writel_relaxed(BIT(offset), reg -
    + eint->regs->stat +
    + eint->regs->mask_set);
    + }
    +
    dual_edge = eint->dual_edge[index];
    if (dual_edge) {
    /*
    --
    2.20.1


    \
     
     \ /
      Last update: 2019-07-18 05:08    [W:3.252 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site