[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <71a4e7da-59da-4a7c-aa4e-45ade8c5558b@codeaurora.org>
Date: Fri, 18 Dec 2020 11:05:35 +0530
From: Rajendra Nayak <rnayak@...eaurora.org>
To: Douglas Anderson <dianders@...omium.org>,
Marc Zyngier <maz@...nel.org>,
Thomas Gleixner <tglx@...utronix.de>,
Jason Cooper <jason@...edaemon.net>,
Linus Walleij <linus.walleij@...aro.org>
Cc: Bjorn Andersson <bjorn.andersson@...aro.org>,
Maulik Shah <mkshah@...eaurora.org>,
Stephen Boyd <swboyd@...omium.org>,
linux-arm-msm@...r.kernel.org,
Srinivas Ramana <sramana@...eaurora.org>,
Neeraj Upadhyay <neeraju@...eaurora.org>,
linux-gpio@...r.kernel.org, Andy Gross <agross@...nel.org>,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH v4 3/4] pinctrl: qcom: Don't clear pending interrupts when
enabling
On 12/12/2020 3:45 AM, Douglas Anderson wrote:
> In Linux, if a driver does disable_irq() and later does enable_irq()
> on its interrupt, I believe it's expecting these properties:
> * If an interrupt was pending when the driver disabled then it will
> still be pending after the driver re-enables.
> * If an edge-triggered interrupt comes in while an interrupt is
> disabled it should assert when the interrupt is re-enabled.
>
> If you think that the above sounds a lot like the disable_irq() and
> enable_irq() are supposed to be masking/unmasking the interrupt
> instead of disabling/enabling it then you've made an astute
> observation. Specifically when talking about interrupts, "mask"
> usually means to stop posting interrupts but keep tracking them and
> "disable" means to fully shut off interrupt detection. It's
> unfortunate that this is so confusing, but presumably this is all the
> way it is for historical reasons.
>
> Perhaps more confusing than the above is that, even though clients of
> IRQs themselves don't have a way to request mask/unmask
> vs. disable/enable calls, IRQ chips themselves can implement both.
> ...and yet more confusing is that if an IRQ chip implements
> disable/enable then they will be called when a client driver calls
> disable_irq() / enable_irq().
>
> It does feel like some of the above could be cleared up. However,
> without any other core interrupt changes it should be clear that when
> an IRQ chip gets a request to "disable" an IRQ that it has to treat it
> like a mask of that IRQ.
>
> In any case, after that long interlude you can see that the "unmask
> and clear" can break things. Maulik tried to fix it so that we no
> longer did "unmask and clear" in commit 71266d9d3936 ("pinctrl: qcom:
> Move clearing pending IRQ to .irq_request_resources callback"), but it
> only handled the PDC case (it also had problems, but that's the
> subject of another patch). Let's fix this for the non-PDC case.
>
> From my understanding the source of the phantom interrupt in the
> non-PDC case was the one that could have been introduced in
> msm_gpio_irq_set_type(). Let's handle that one and then get rid of
> the clear.
>
> Fixes: 4b7618fdc7e6 ("pinctrl: qcom: Add irq_enable callback for msm gpio")
> Signed-off-by: Douglas Anderson <dianders@...omium.org>
> ---
> I don't have lots of good test cases here, so hopefully someone from
> Qualcomm can confirm that this works well for them and there isn't
> some other phantom interrupt source that I'm not aware of.
I currently don;t have access to any non-PDC hardware, so could not really do
any real tests, but the changes seem sane, so
Reviewed-by: Rajendra Nayak <rnayak@...eaurora.org>
>
> Changes in v4:
> - ("pinctrl: qcom: Don't clear pending interrupts when enabling") split for v4.
>
> drivers/pinctrl/qcom/pinctrl-msm.c | 32 +++++++++++++-----------------
> 1 file changed, 14 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
> index 588df91274e2..f785646d1df7 100644
> --- a/drivers/pinctrl/qcom/pinctrl-msm.c
> +++ b/drivers/pinctrl/qcom/pinctrl-msm.c
> @@ -774,7 +774,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
> raw_spin_unlock_irqrestore(&pctrl->lock, flags);
> }
>
> -static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
> +static void msm_gpio_irq_unmask(struct irq_data *d)
> {
> struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
> @@ -792,17 +792,6 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear)
>
> raw_spin_lock_irqsave(&pctrl->lock, flags);
>
> - if (status_clear) {
> - /*
> - * clear the interrupt status bit before unmask to avoid
> - * any erroneous interrupts that would have got latched
> - * when the interrupt is not in use.
> - */
> - val = msm_readl_intr_status(pctrl, g);
> - val &= ~BIT(g->intr_status_bit);
> - msm_writel_intr_status(val, pctrl, g);
> - }
> -
> val = msm_readl_intr_cfg(pctrl, g);
> val |= BIT(g->intr_raw_status_bit);
> val |= BIT(g->intr_enable_bit);
> @@ -822,7 +811,7 @@ static void msm_gpio_irq_enable(struct irq_data *d)
> irq_chip_enable_parent(d);
>
> if (!test_bit(d->hwirq, pctrl->skip_wake_irqs))
> - msm_gpio_irq_clear_unmask(d, true);
> + msm_gpio_irq_unmask(d);
> }
>
> static void msm_gpio_irq_disable(struct irq_data *d)
> @@ -837,11 +826,6 @@ static void msm_gpio_irq_disable(struct irq_data *d)
> msm_gpio_irq_mask(d);
> }
>
> -static void msm_gpio_irq_unmask(struct irq_data *d)
> -{
> - msm_gpio_irq_clear_unmask(d, false);
> -}
> -
> /**
> * msm_gpio_update_dual_edge_parent() - Prime next edge for IRQs handled by parent.
> * @d: The irq dta.
> @@ -936,6 +920,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
> struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
> const struct msm_pingroup *g;
> unsigned long flags;
> + bool was_enabled;
> u32 val;
>
> if (msm_gpio_needs_dual_edge_parent_workaround(d, type)) {
> @@ -997,6 +982,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
> * could cause the INTR_STATUS to be set for EDGE interrupts.
> */
> val = msm_readl_intr_cfg(pctrl, g);
> + was_enabled = val & BIT(g->intr_raw_status_bit);
> val |= BIT(g->intr_raw_status_bit);
> if (g->intr_detection_width == 2) {
> val &= ~(3 << g->intr_detection_bit);
> @@ -1046,6 +1032,16 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
> }
> msm_writel_intr_cfg(val, pctrl, g);
>
> + /*
> + * The first time we set RAW_STATUS_EN it could trigger an interrupt.
> + * Clear it. This is safe because we have IRQCHIP_SET_TYPE_MASKED.
> + */
> + if (!was_enabled) {
> + val = msm_readl_intr_status(pctrl, g);
> + val &= ~BIT(g->intr_status_bit);
> + msm_writel_intr_status(val, pctrl, g);
> + }
> +
> if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
> msm_gpio_update_dual_edge_pos(pctrl, g, d);
>
>
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
Powered by blists - more mailing lists