diff mbox

[09/26] arm: mmp: Remove pointless fiddling with irq internals

Message ID 20140223212737.214342433@linutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Gleixner Feb. 23, 2014, 9:40 p.m. UTC
The pm-mmp2 and pm-pxa910 power management related irq_set_wake
callbacks fiddle pointlessly with the irq actions for no reason except
for lack of understanding how the wakeup mechanism works.

On supsend the core disables all interrupts lazily, i.e. it does not
mask them at the irq controller level. So any interrupt which is
firing during supsend will mark the corresponding interrupt line as
pending. Just before the core powers down it checks whether there are
interrupts pending from interrupt lines which are marked as wakeup
sources and if so it aborts the resume and resends the interrupts.

The IRQF_NO_SUSPEND flag for interrupt actions is a totally different
mechanism. That allows the device driver to prevent the core from
disabling the interrupt despite the fact that it is not marked as a
wakeup source. This has nothing to do with the case at hand. It was
introduced for special cases where lazy disable is not possible.

Remove the nonsense along with the braindamaged boundary check. The
core code does NOT call these functions out of boundary.

Add a FIXME comment to an unhandled error path which merily printks
some useless blurb instead of returning a proper error code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: arm <linux-arm-kernel@lists.infradead.org>
Cc: Eric Miao <eric.y.miao@gmail.com>
Cc: Haojian Zhuang <haojian.zhuang@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
---
 arch/arm/mach-mmp/pm-mmp2.c   |   16 +---------------
 arch/arm/mach-mmp/pm-pxa910.c |   20 ++++----------------
 2 files changed, 5 insertions(+), 31 deletions(-)

Comments

Uwe Kleine-König Feb. 23, 2014, 11:17 p.m. UTC | #1
Hi Thomas,

On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
> callbacks fiddle pointlessly with the irq actions for no reason except
> for lack of understanding how the wakeup mechanism works.
> 
> On supsend the core disables all interrupts lazily, i.e. it does not
> mask them at the irq controller level. So any interrupt which is
> firing during supsend will mark the corresponding interrupt line as
s/supsend/suspend/ twice
> pending. Just before the core powers down it checks whether there are
> interrupts pending from interrupt lines which are marked as wakeup
> sources and if so it aborts the resume and resends the interrupts.
It's the suspend that is aborted, not the resume.

Other than that your change looks fine.

Uwe
Chao Xie Feb. 24, 2014, 6:07 a.m. UTC | #2
On Mon, Feb 24, 2014 at 7:17 AM, Uwe Kleine-König
<u.kleine-koenig@pengutronix.de> wrote:
> Hi Thomas,
>
> On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
>> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
>> callbacks fiddle pointlessly with the irq actions for no reason except
>> for lack of understanding how the wakeup mechanism works.
>>
>> On supsend the core disables all interrupts lazily, i.e. it does not
>> mask them at the irq controller level. So any interrupt which is
>> firing during supsend will mark the corresponding interrupt line as
> s/supsend/suspend/ twice
>> pending. Just before the core powers down it checks whether there are
>> interrupts pending from interrupt lines which are marked as wakeup
>> sources and if so it aborts the resume and resends the interrupts.
> It's the suspend that is aborted, not the resume.
>
> Other than that your change looks fine.
>
For pxa910 and MMP2, wake up source only wake up the AP subsystem.
The AP subsystem includes the APMU(AP Power Mangament Unit) and cores.
Now the core is still powered down. APMU will check the interrupt
lines, and find
that there are interrupt pending, it will power on the cores.
So if the irq is disabled, even wake up source can wake up AP subsystem, but the
core is still powered down. It will not be powered up by APMU.


> Uwe
>
> --
> Pengutronix e.K.                           | Uwe Kleine-König            |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Haojian Zhuang Feb. 24, 2014, 6:43 a.m. UTC | #3
On Mon, Feb 24, 2014 at 2:07 PM, Chao Xie <xiechao.mail@gmail.com> wrote:
> On Mon, Feb 24, 2014 at 7:17 AM, Uwe Kleine-König
> <u.kleine-koenig@pengutronix.de> wrote:
>> Hi Thomas,
>>
>> On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
>>> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
>>> callbacks fiddle pointlessly with the irq actions for no reason except
>>> for lack of understanding how the wakeup mechanism works.
>>>
>>> On supsend the core disables all interrupts lazily, i.e. it does not
>>> mask them at the irq controller level. So any interrupt which is
>>> firing during supsend will mark the corresponding interrupt line as
>> s/supsend/suspend/ twice
>>> pending. Just before the core powers down it checks whether there are
>>> interrupts pending from interrupt lines which are marked as wakeup
>>> sources and if so it aborts the resume and resends the interrupts.
>> It's the suspend that is aborted, not the resume.
>>
>> Other than that your change looks fine.
>>
> For pxa910 and MMP2, wake up source only wake up the AP subsystem.
> The AP subsystem includes the APMU(AP Power Mangament Unit) and cores.
> Now the core is still powered down. APMU will check the interrupt
> lines, and find
> that there are interrupt pending, it will power on the cores.
> So if the irq is disabled, even wake up source can wake up AP subsystem, but the
> core is still powered down. It will not be powered up by APMU.
>

Yes, suspend/resume can't work if the above code is removed.

Interrupt source (logic AND with interrupt mask register) is connected
to MPMU as
wakeup source. If the interrupt is disabled, there's no wakeup source event.

And APMU is waken up by MPMU.

So please don't remove the above code. We must keep these interrupt lines active
to wake up the whole system.

Regards
Haojian
Thomas Gleixner Feb. 24, 2014, 11:27 a.m. UTC | #4
On Mon, 24 Feb 2014, Chao Xie wrote:

> On Mon, Feb 24, 2014 at 7:17 AM, Uwe Kleine-König
> <u.kleine-koenig@pengutronix.de> wrote:
> > Hi Thomas,
> >
> > On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
> >> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
> >> callbacks fiddle pointlessly with the irq actions for no reason except
> >> for lack of understanding how the wakeup mechanism works.
> >>
> >> On supsend the core disables all interrupts lazily, i.e. it does not
> >> mask them at the irq controller level. So any interrupt which is
> >> firing during supsend will mark the corresponding interrupt line as
> > s/supsend/suspend/ twice
> >> pending. Just before the core powers down it checks whether there are
> >> interrupts pending from interrupt lines which are marked as wakeup
> >> sources and if so it aborts the resume and resends the interrupts.
> > It's the suspend that is aborted, not the resume.
> >
> > Other than that your change looks fine.
> >
> For pxa910 and MMP2, wake up source only wake up the AP subsystem.
> The AP subsystem includes the APMU(AP Power Mangament Unit) and cores.
> Now the core is still powered down. APMU will check the interrupt
> lines, and find
> that there are interrupt pending, it will power on the cores.
> So if the irq is disabled, even wake up source can wake up AP subsystem, but the
> core is still powered down. It will not be powered up by APMU.

The interrupt is NOT disabled at the interrupt chip level. The core does:

suspend_device_irqs() {
  __disable_irq() {
    if (!desc->depth++)
      irq_disable(desc) {
        irq_state_set_disabled(desc);
        if (desc->irq_data.chip->irq_disable) {
          desc->irq_data.chip->irq_disable(&desc->irq_data);
          irq_state_set_masked(desc);
        }

Your chip does not have a chip->irq_disable() callback installed, so
the interrupt is not masked at the controller level. So APMU sees the
interrupt enabled.

APMU does not care about the irq_desc->depth counter and the irq_data
IRQD_DISABLED state bit.

So this hackery is completely pointless.

Thanks,

	tglx
Thomas Gleixner Feb. 24, 2014, 11:31 a.m. UTC | #5
On Mon, 24 Feb 2014, Haojian Zhuang wrote:

> On Mon, Feb 24, 2014 at 2:07 PM, Chao Xie <xiechao.mail@gmail.com> wrote:
> > On Mon, Feb 24, 2014 at 7:17 AM, Uwe Kleine-König
> > <u.kleine-koenig@pengutronix.de> wrote:
> >> Hi Thomas,
> >>
> >> On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
> >>> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
> >>> callbacks fiddle pointlessly with the irq actions for no reason except
> >>> for lack of understanding how the wakeup mechanism works.
> >>>
> >>> On supsend the core disables all interrupts lazily, i.e. it does not
> >>> mask them at the irq controller level. So any interrupt which is
> >>> firing during supsend will mark the corresponding interrupt line as
> >> s/supsend/suspend/ twice
> >>> pending. Just before the core powers down it checks whether there are
> >>> interrupts pending from interrupt lines which are marked as wakeup
> >>> sources and if so it aborts the resume and resends the interrupts.
> >> It's the suspend that is aborted, not the resume.
> >>
> >> Other than that your change looks fine.
> >>
> > For pxa910 and MMP2, wake up source only wake up the AP subsystem.
> > The AP subsystem includes the APMU(AP Power Mangament Unit) and cores.
> > Now the core is still powered down. APMU will check the interrupt
> > lines, and find
> > that there are interrupt pending, it will power on the cores.
> > So if the irq is disabled, even wake up source can wake up AP subsystem, but the
> > core is still powered down. It will not be powered up by APMU.
> >
> 
> Yes, suspend/resume can't work if the above code is removed.
> 
> Interrupt source (logic AND with interrupt mask register) is connected
> to MPMU as
> wakeup source. If the interrupt is disabled, there's no wakeup source event.
> 
> And APMU is waken up by MPMU.
> 
> So please don't remove the above code. We must keep these interrupt lines active
> to wake up the whole system.

They are kept active at the interrupt controller level. You just
refuse to understand how the internals of the interrupt subsystem
work.

And even if you would need this flag, then fiddling with the irq desc
internals is a big NONO. There is a proper way to hand that in.

Thanks,

	tglx
Chao Xie Feb. 27, 2014, 1:37 a.m. UTC | #6
On Mon, Feb 24, 2014 at 7:31 PM, Thomas Gleixner <tglx@linutronix.de> wrote:
> On Mon, 24 Feb 2014, Haojian Zhuang wrote:
>
>> On Mon, Feb 24, 2014 at 2:07 PM, Chao Xie <xiechao.mail@gmail.com> wrote:
>> > On Mon, Feb 24, 2014 at 7:17 AM, Uwe Kleine-König
>> > <u.kleine-koenig@pengutronix.de> wrote:
>> >> Hi Thomas,
>> >>
>> >> On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
>> >>> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
>> >>> callbacks fiddle pointlessly with the irq actions for no reason except
>> >>> for lack of understanding how the wakeup mechanism works.
>> >>>
>> >>> On supsend the core disables all interrupts lazily, i.e. it does not
>> >>> mask them at the irq controller level. So any interrupt which is
>> >>> firing during supsend will mark the corresponding interrupt line as
>> >> s/supsend/suspend/ twice
>> >>> pending. Just before the core powers down it checks whether there are
>> >>> interrupts pending from interrupt lines which are marked as wakeup
>> >>> sources and if so it aborts the resume and resends the interrupts.
>> >> It's the suspend that is aborted, not the resume.
>> >>
>> >> Other than that your change looks fine.
>> >>
>> > For pxa910 and MMP2, wake up source only wake up the AP subsystem.
>> > The AP subsystem includes the APMU(AP Power Mangament Unit) and cores.
>> > Now the core is still powered down. APMU will check the interrupt
>> > lines, and find
>> > that there are interrupt pending, it will power on the cores.
>> > So if the irq is disabled, even wake up source can wake up AP subsystem, but the
>> > core is still powered down. It will not be powered up by APMU.
>> >
>>
>> Yes, suspend/resume can't work if the above code is removed.
>>
>> Interrupt source (logic AND with interrupt mask register) is connected
>> to MPMU as
>> wakeup source. If the interrupt is disabled, there's no wakeup source event.
>>
>> And APMU is waken up by MPMU.
>>
>> So please don't remove the above code. We must keep these interrupt lines active
>> to wake up the whole system.
>
> They are kept active at the interrupt controller level. You just
> refuse to understand how the internals of the interrupt subsystem
> work.
>
If no irq_disable callback is hooked, when do irq_disable, it will not
actually disable
the interrupt, it will depend on next time when the irq happens, the
handler will first mask
the interrupt as this interrupt never happens.
So after system suspended, the interrupt happens, but the device
driver will not recieve this interrupt
because it is masked.
It results in that the device driver miss a important interrupt which
related to something need to be
handled. If user application for example android has power managment
daemon. It will find that nothing
to handle, it will make the system enter suspend again.

> And even if you would need this flag, then fiddling with the irq desc
> internals is a big NONO. There is a proper way to hand that in.
>

So can you suggest the proper way to handle it? Thanks.

> Thanks,
>
>         tglx
>
Haojian Zhuang Feb. 27, 2014, 2:19 a.m. UTC | #7
On Thu, Feb 27, 2014 at 9:37 AM, Chao Xie <xiechao.mail@gmail.com> wrote:
> On Mon, Feb 24, 2014 at 7:31 PM, Thomas Gleixner <tglx@linutronix.de> wrote:
>> On Mon, 24 Feb 2014, Haojian Zhuang wrote:
>>
>>> On Mon, Feb 24, 2014 at 2:07 PM, Chao Xie <xiechao.mail@gmail.com> wrote:
>>> > On Mon, Feb 24, 2014 at 7:17 AM, Uwe Kleine-König
>>> > <u.kleine-koenig@pengutronix.de> wrote:
>>> >> Hi Thomas,
>>> >>
>>> >> On Sun, Feb 23, 2014 at 09:40:13PM -0000, Thomas Gleixner wrote:
>>> >>> The pm-mmp2 and pm-pxa910 power management related irq_set_wake
>>> >>> callbacks fiddle pointlessly with the irq actions for no reason except
>>> >>> for lack of understanding how the wakeup mechanism works.
>>> >>>
>>> >>> On supsend the core disables all interrupts lazily, i.e. it does not
>>> >>> mask them at the irq controller level. So any interrupt which is
>>> >>> firing during supsend will mark the corresponding interrupt line as
>>> >> s/supsend/suspend/ twice
>>> >>> pending. Just before the core powers down it checks whether there are
>>> >>> interrupts pending from interrupt lines which are marked as wakeup
>>> >>> sources and if so it aborts the resume and resends the interrupts.
>>> >> It's the suspend that is aborted, not the resume.
>>> >>
>>> >> Other than that your change looks fine.
>>> >>
>>> > For pxa910 and MMP2, wake up source only wake up the AP subsystem.
>>> > The AP subsystem includes the APMU(AP Power Mangament Unit) and cores.
>>> > Now the core is still powered down. APMU will check the interrupt
>>> > lines, and find
>>> > that there are interrupt pending, it will power on the cores.
>>> > So if the irq is disabled, even wake up source can wake up AP subsystem, but the
>>> > core is still powered down. It will not be powered up by APMU.
>>> >
>>>
>>> Yes, suspend/resume can't work if the above code is removed.
>>>
>>> Interrupt source (logic AND with interrupt mask register) is connected
>>> to MPMU as
>>> wakeup source. If the interrupt is disabled, there's no wakeup source event.
>>>
>>> And APMU is waken up by MPMU.
>>>
>>> So please don't remove the above code. We must keep these interrupt lines active
>>> to wake up the whole system.
>>
>> They are kept active at the interrupt controller level. You just
>> refuse to understand how the internals of the interrupt subsystem
>> work.
>>
> If no irq_disable callback is hooked, when do irq_disable, it will not
> actually disable
> the interrupt, it will depend on next time when the irq happens, the
> handler will first mask
> the interrupt as this interrupt never happens.
> So after system suspended, the interrupt happens, but the device
> driver will not recieve this interrupt
> because it is masked.
> It results in that the device driver miss a important interrupt which
> related to something need to be
> handled. If user application for example android has power managment
> daemon. It will find that nothing
> to handle, it will make the system enter suspend again.
>
Let me list the logic to make it easier to understand.

suspend_enter()
  --> dpm_suspend_end()
           --> dpm_suspend_noirq()
                    --> suspend_device_irqs()
                             --> __disable_irq()
                                     --> set IRQS_SUSPENDED && call
irq_disable() if necessary
  --> syscore_suspend()
          --> check_wakeup_irqs()
               If there's no pending irq in suspend process &&
IRQS_SUSPENDED is set,
               then mask the irq.

Yes, we didn't implement disable_irq(). But we must implement mask_irq().

So system suspends. Then system will never be waken up by this irq any
more since
it's masked.


>> And even if you would need this flag, then fiddling with the irq desc
>> internals is a big NONO. There is a proper way to hand that in.
>>
>
> So can you suggest the proper way to handle it? Thanks.
>
>> Thanks,
>>
>>         tglx
>>
Thomas Gleixner Feb. 27, 2014, 11:28 a.m. UTC | #8
On Thu, 27 Feb 2014, Haojian Zhuang wrote:
> Let me list the logic to make it easier to understand.
> 
> suspend_enter()
>   --> dpm_suspend_end()
>            --> dpm_suspend_noirq()
>                     --> suspend_device_irqs()
>                              --> __disable_irq()
>                                      --> set IRQS_SUSPENDED && call
> irq_disable() if necessary
>   --> syscore_suspend()
>           --> check_wakeup_irqs()
>                If there's no pending irq in suspend process &&
> IRQS_SUSPENDED is set,
>                then mask the irq.
> 
> Yes, we didn't implement disable_irq(). But we must implement mask_irq().
> 
> So system suspends. Then system will never be waken up by this irq any
> more since
> it's masked.

This is so wrong, it's not even funny anymore.

check_wakeup_irqs()
{
	for_each_irq_desc(irq, desc) {
                if (irqd_is_wakeup_set(&desc->irq_data)) {
                        if (desc->depth == 1 && desc->istate & IRQS_PENDING)
                                return -EBUSY;
                        continue;
                }

So all interrupt lines which have been marked as wakeup sources are
not masked. And we only mask the other lines if the irq chip has the
IRQCHIP_MASK_ON_SUSPEND flag set.

                if (desc->istate & IRQS_SUSPENDED &&
                    irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
                        mask_irq(desc);

}

The interrupts which can wake up your system fall into the
irqd_is_wakeup_set() clause. So nothing masks the interrupts at these
interrupt controller level. Your chip does not have the
IRQCHIP_MASK_ON_SUSPEND flag set either, so not a single interrupt
line gets masked.

The only thing you do with your hackery is to avoid that the interrupt
is marked disabled. And that means that you violate the rules of the
suspend logic.

We lazy disable the interrupts when we go into suspend in order to
abort the suspend when a wakeup interrupt happens between the
suspend_device_irqs() and check_wakeup_irqs(). Your hackery allows the
system to handle the interrupt, so we have no indication that the
suspend should be aborted.

You insist, that the interrupt line is masked at the irq chip level on
suspend, but you completely fail to explain how this should
happen. All you came up with so far is handwaving and a proper proof
of incompetence.

I'm really start to get grumpy about this utter waste of time.

Thanks,

	tglx
diff mbox

Patch

Index: tip/arch/arm/mach-mmp/pm-mmp2.c
===================================================================
--- tip.orig/arch/arm/mach-mmp/pm-mmp2.c
+++ tip/arch/arm/mach-mmp/pm-mmp2.c
@@ -27,22 +27,8 @@ 
 
 int mmp2_set_wake(struct irq_data *d, unsigned int on)
 {
-	int irq = d->irq;
-	struct irq_desc *desc = irq_to_desc(irq);
 	unsigned long data = 0;
-
-	if (unlikely(irq >= nr_irqs)) {
-		pr_err("IRQ nubmers are out of boundary!\n");
-		return -EINVAL;
-	}
-
-	if (on) {
-		if (desc->action)
-			desc->action->flags |= IRQF_NO_SUSPEND;
-	} else {
-		if (desc->action)
-			desc->action->flags &= ~IRQF_NO_SUSPEND;
-	}
+	int irq = d->irq;
 
 	/* enable wakeup sources */
 	switch (irq) {
Index: tip/arch/arm/mach-mmp/pm-pxa910.c
===================================================================
--- tip.orig/arch/arm/mach-mmp/pm-pxa910.c
+++ tip/arch/arm/mach-mmp/pm-pxa910.c
@@ -27,22 +27,8 @@ 
 
 int pxa910_set_wake(struct irq_data *data, unsigned int on)
 {
-	int irq = data->irq;
-	struct irq_desc *desc = irq_to_desc(data->irq);
 	uint32_t awucrm = 0, apcr = 0;
-
-	if (unlikely(irq >= nr_irqs)) {
-		pr_err("IRQ nubmers are out of boundary!\n");
-		return -EINVAL;
-	}
-
-	if (on) {
-		if (desc->action)
-			desc->action->flags |= IRQF_NO_SUSPEND;
-	} else {
-		if (desc->action)
-			desc->action->flags &= ~IRQF_NO_SUSPEND;
-	}
+	int irq = data->irq;
 
 	/* setting wakeup sources */
 	switch (irq) {
@@ -115,9 +101,11 @@  int pxa910_set_wake(struct irq_data *dat
 		if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
 			awucrm = MPMU_AWUCRM_WAKEUP(2);
 			apcr |= MPMU_APCR_SLPWP2;
-		} else
+		} else {
+			/* FIXME: This should return a proper error code ! */
 			printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
 				irq);
+		}
 	}
 
 	if (on) {