diff mbox

ARM: imx6q: work around faulty PMU irq routing

Message ID 1398371029-21176-1-git-send-email-l.stach@pengutronix.de
State New
Headers show

Commit Message

Lucas Stach April 24, 2014, 8:23 p.m. UTC
The i.MX6 PMU has a design errata where the interrupts of all cores are
wired together into a single irq line. To work around this we have to
bounce the interrupt around all cores until we find the one where the PMU
counter overflow has happened.

This causes the perf measurements to be less accurate and we can't really
handle the case where two cores fire a PMU irq at the same time. The
implemented woraround makes perf at least somewhat useable on imx6 SoCs
with more than one core.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 arch/arm/mach-imx/mach-imx6q.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

Comments

Fabio Estevam April 24, 2014, 8:32 p.m. UTC | #1
On Thu, Apr 24, 2014 at 5:23 PM, Lucas Stach <l.stach@pengutronix.de> wrote:
> The i.MX6 PMU has a design errata where the interrupts of all cores are
> wired together into a single irq line. To work around this we have to

Is there an erratum reference number for this, please?
Behme Dirk (CM/ESO2) April 25, 2014, 5:33 a.m. UTC | #2
On 24.04.2014 22:32, Fabio Estevam wrote:
> On Thu, Apr 24, 2014 at 5:23 PM, Lucas Stach <l.stach@pengutronix.de> wrote:
>> The i.MX6 PMU has a design errata where the interrupts of all cores are
>> wired together into a single irq line. To work around this we have to
>
> Is there an erratum reference number for this, please?

First, many thanks to Lucas for working on this! Up to now, it was my 
impression that the PMU on i.MX6 is completely useless for !single core 
SoCs. So maybe there is some hope, now :)

Regarding the erratum: To my knowledge there is no erratum. In 2013 I've 
had a discussion with the FSL support about this and got the answer:

-- cut --
This is the IC design issue, we have OR'ed the interrupt pin of the four 
PMU and provide one interrupt to the CPU. currently, we don't have the 
SW workaround available for it.
-- cut --

This is just what has been called as "braindead, broken system" in

http://lists.infradead.org/pipermail/linux-arm-kernel/2012-August/113802.html

Best regards

Dirk
Behme Dirk (CM/ESO2) April 25, 2014, 5:37 a.m. UTC | #3
On 24.04.2014 22:23, Lucas Stach wrote:
> The i.MX6 PMU has a design errata where the interrupts of all cores are
> wired together into a single irq line. To work around this we have to
> bounce the interrupt around all cores until we find the one where the PMU
> counter overflow has happened.
>
> This causes the perf measurements to be less accurate and we can't really
> handle the case where two cores fire a PMU irq at the same time. The
> implemented woraround makes perf at least somewhat useable on imx6 SoCs
> with more than one core.
>
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> ---
>   arch/arm/mach-imx/mach-imx6q.c | 38 +++++++++++++++++++++++++++++++++++++-
>   1 file changed, 37 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> index e60456d85c9d..73976c484826 100644
> --- a/arch/arm/mach-imx/mach-imx6q.c
> +++ b/arch/arm/mach-imx/mach-imx6q.c
> @@ -16,6 +16,7 @@
>   #include <linux/delay.h>
>   #include <linux/export.h>
>   #include <linux/init.h>
> +#include "linux/interrupt.h"
>   #include <linux/io.h>
>   #include <linux/irq.h>
>   #include <linux/irqchip.h>
> @@ -33,6 +34,7 @@
>   #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
>   #include <asm/mach/arch.h>
>   #include <asm/mach/map.h>
> +#include "asm/pmu.h"
>   #include <asm/system_misc.h>
>
>   #include "common.h"
> @@ -261,6 +263,39 @@ static void __init imx6q_axi_init(void)
>   	}
>   }
>
> +/*
> + * The i.MX6 PMU has a design errata where the interrupts of all cores are
> + * wired together into a single irq line. To work around this we have to
> + * bounce the interrupt around all cores until we find the one where the PMU
> + * counter overflow has happened.
> + */
> +static irqreturn_t imx6q_pmu_handler(int irq, void *dev, irq_handler_t handler)
> +{
> +	irqreturn_t ret = handler(irq, dev);
> +	int next;
> +
> +	if (ret == IRQ_NONE) {
> +		/*
> +		 * Kick the irq over to the next cpu, regardless of it's
> +		 * online status (it might have gone offline while we were busy
> +		 * bouncing the irq).
> +		 */
> +		next = (smp_processor_id() + 1) % num_present_cpus();
> +		irq_set_affinity(irq, cpumask_of(next));
> +	}
> +
> +	return ret;
> +}
> +
> +struct arm_pmu_platdata imx6q_pmu_platdata = {
> +	.handle_irq		= imx6q_pmu_handler,
> +};
> +
> +static struct of_dev_auxdata imx6q_auxdata_lookup[] __initdata = {
> +	OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &imx6q_pmu_platdata),
> +	{}
> +};
> +
>   static void __init imx6q_init_machine(void)
>   {
>   	struct device *parent;
> @@ -276,7 +311,8 @@ static void __init imx6q_init_machine(void)
>
>   	imx6q_enet_phy_init();
>
> -	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
> +	of_platform_populate(NULL, of_default_bus_match_table,
> +			imx6q_auxdata_lookup, parent);
>
>   	imx_anatop_init();
>   	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();

Do you have anything like a test case which shows that it works (at 
least better) on a !single core with this patch? Compared to a 
non-patched system?

Many thanks

Dirk
Lucas Stach April 25, 2014, 9:13 a.m. UTC | #4
Am Freitag, den 25.04.2014, 07:37 +0200 schrieb Dirk Behme:
> On 24.04.2014 22:23, Lucas Stach wrote:
> > The i.MX6 PMU has a design errata where the interrupts of all cores are
> > wired together into a single irq line. To work around this we have to
> > bounce the interrupt around all cores until we find the one where the PMU
> > counter overflow has happened.
> >
> > This causes the perf measurements to be less accurate and we can't really
> > handle the case where two cores fire a PMU irq at the same time. The
> > implemented woraround makes perf at least somewhat useable on imx6 SoCs
> > with more than one core.
> >
> > Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> > ---
> >   arch/arm/mach-imx/mach-imx6q.c | 38 +++++++++++++++++++++++++++++++++++++-
> >   1 file changed, 37 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> > index e60456d85c9d..73976c484826 100644
> > --- a/arch/arm/mach-imx/mach-imx6q.c
> > +++ b/arch/arm/mach-imx/mach-imx6q.c
> > @@ -16,6 +16,7 @@
> >   #include <linux/delay.h>
> >   #include <linux/export.h>
> >   #include <linux/init.h>
> > +#include "linux/interrupt.h"
> >   #include <linux/io.h>
> >   #include <linux/irq.h>
> >   #include <linux/irqchip.h>
> > @@ -33,6 +34,7 @@
> >   #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
> >   #include <asm/mach/arch.h>
> >   #include <asm/mach/map.h>
> > +#include "asm/pmu.h"
> >   #include <asm/system_misc.h>
> >
> >   #include "common.h"
> > @@ -261,6 +263,39 @@ static void __init imx6q_axi_init(void)
> >   	}
> >   }
> >
> > +/*
> > + * The i.MX6 PMU has a design errata where the interrupts of all cores are
> > + * wired together into a single irq line. To work around this we have to
> > + * bounce the interrupt around all cores until we find the one where the PMU
> > + * counter overflow has happened.
> > + */
> > +static irqreturn_t imx6q_pmu_handler(int irq, void *dev, irq_handler_t handler)
> > +{
> > +	irqreturn_t ret = handler(irq, dev);
> > +	int next;
> > +
> > +	if (ret == IRQ_NONE) {
> > +		/*
> > +		 * Kick the irq over to the next cpu, regardless of it's
> > +		 * online status (it might have gone offline while we were busy
> > +		 * bouncing the irq).
> > +		 */
> > +		next = (smp_processor_id() + 1) % num_present_cpus();
> > +		irq_set_affinity(irq, cpumask_of(next));
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +struct arm_pmu_platdata imx6q_pmu_platdata = {
> > +	.handle_irq		= imx6q_pmu_handler,
> > +};
> > +
> > +static struct of_dev_auxdata imx6q_auxdata_lookup[] __initdata = {
> > +	OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &imx6q_pmu_platdata),
> > +	{}
> > +};
> > +
> >   static void __init imx6q_init_machine(void)
> >   {
> >   	struct device *parent;
> > @@ -276,7 +311,8 @@ static void __init imx6q_init_machine(void)
> >
> >   	imx6q_enet_phy_init();
> >
> > -	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
> > +	of_platform_populate(NULL, of_default_bus_match_table,
> > +			imx6q_auxdata_lookup, parent);
> >
> >   	imx_anatop_init();
> >   	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();
> 
> Do you have anything like a test case which shows that it works (at 
> least better) on a !single core with this patch? Compared to a 
> non-patched system?
> 
Without this patch, running perf top completely kills the system on
i.MX6q, most likely because of the sheer number of spurious interrupts
hitting the system from 4 cores. Even the spurious killer doesn't work
sometimes, so perf is completely busted right now.

With this patch perf has to reduce the sample frequency in order to
compensate the added irq latency, but at least we get some plausible
numbers out. Though I won't take any blame if the amount of salt you
have to apply while looking at those numbers is already a deadly
dose. ;)

I don't yet have any numbers on how accurate the measurement is, but at
least things didn't look completely off.

Regards,
Lucas
Shawn Guo April 29, 2014, 5:28 a.m. UTC | #5
On Fri, Apr 25, 2014 at 11:13:25AM +0200, Lucas Stach wrote:
> Am Freitag, den 25.04.2014, 07:37 +0200 schrieb Dirk Behme:
> > On 24.04.2014 22:23, Lucas Stach wrote:
> > > The i.MX6 PMU has a design errata where the interrupts of all cores are
> > > wired together into a single irq line. To work around this we have to
> > > bounce the interrupt around all cores until we find the one where the PMU
> > > counter overflow has happened.
> > >
> > > This causes the perf measurements to be less accurate and we can't really
> > > handle the case where two cores fire a PMU irq at the same time. The
> > > implemented woraround makes perf at least somewhat useable on imx6 SoCs
> > > with more than one core.
> > >
> > > Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> > > ---
> > >   arch/arm/mach-imx/mach-imx6q.c | 38 +++++++++++++++++++++++++++++++++++++-
> > >   1 file changed, 37 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> > > index e60456d85c9d..73976c484826 100644
> > > --- a/arch/arm/mach-imx/mach-imx6q.c
> > > +++ b/arch/arm/mach-imx/mach-imx6q.c
> > > @@ -16,6 +16,7 @@
> > >   #include <linux/delay.h>
> > >   #include <linux/export.h>
> > >   #include <linux/init.h>
> > > +#include "linux/interrupt.h"
> > >   #include <linux/io.h>
> > >   #include <linux/irq.h>
> > >   #include <linux/irqchip.h>
> > > @@ -33,6 +34,7 @@
> > >   #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
> > >   #include <asm/mach/arch.h>
> > >   #include <asm/mach/map.h>
> > > +#include "asm/pmu.h"
> > >   #include <asm/system_misc.h>
> > >
> > >   #include "common.h"
> > > @@ -261,6 +263,39 @@ static void __init imx6q_axi_init(void)
> > >   	}
> > >   }
> > >
> > > +/*
> > > + * The i.MX6 PMU has a design errata where the interrupts of all cores are
> > > + * wired together into a single irq line. To work around this we have to
> > > + * bounce the interrupt around all cores until we find the one where the PMU
> > > + * counter overflow has happened.
> > > + */
> > > +static irqreturn_t imx6q_pmu_handler(int irq, void *dev, irq_handler_t handler)
> > > +{
> > > +	irqreturn_t ret = handler(irq, dev);
> > > +	int next;
> > > +
> > > +	if (ret == IRQ_NONE) {
> > > +		/*
> > > +		 * Kick the irq over to the next cpu, regardless of it's
> > > +		 * online status (it might have gone offline while we were busy
> > > +		 * bouncing the irq).
> > > +		 */
> > > +		next = (smp_processor_id() + 1) % num_present_cpus();
> > > +		irq_set_affinity(irq, cpumask_of(next));
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +struct arm_pmu_platdata imx6q_pmu_platdata = {
> > > +	.handle_irq		= imx6q_pmu_handler,
> > > +};
> > > +
> > > +static struct of_dev_auxdata imx6q_auxdata_lookup[] __initdata = {
> > > +	OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &imx6q_pmu_platdata),
> > > +	{}
> > > +};
> > > +
> > >   static void __init imx6q_init_machine(void)
> > >   {
> > >   	struct device *parent;
> > > @@ -276,7 +311,8 @@ static void __init imx6q_init_machine(void)
> > >
> > >   	imx6q_enet_phy_init();
> > >
> > > -	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
> > > +	of_platform_populate(NULL, of_default_bus_match_table,
> > > +			imx6q_auxdata_lookup, parent);
> > >
> > >   	imx_anatop_init();
> > >   	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();
> > 
> > Do you have anything like a test case which shows that it works (at 
> > least better) on a !single core with this patch? Compared to a 
> > non-patched system?
> > 
> Without this patch, running perf top completely kills the system on
> i.MX6q, most likely because of the sheer number of spurious interrupts
> hitting the system from 4 cores. Even the spurious killer doesn't work
> sometimes, so perf is completely busted right now.
> 
> With this patch perf has to reduce the sample frequency in order to
> compensate the added irq latency, but at least we get some plausible
> numbers out. Though I won't take any blame if the amount of salt you
> have to apply while looking at those numbers is already a deadly
> dose. ;)
> 
> I don't yet have any numbers on how accurate the measurement is, but at
> least things didn't look completely off.

If it cannot provide correct/accurate data, I'd say let's not fake it
to, and just let it be completely broken there, so that people can be
aware of the brokenness, and not take inaccurate data as accurate one.

Shawn
Lucas Stach April 29, 2014, 9:55 a.m. UTC | #6
Am Dienstag, den 29.04.2014, 13:28 +0800 schrieb Shawn Guo:
> On Fri, Apr 25, 2014 at 11:13:25AM +0200, Lucas Stach wrote:
> > Am Freitag, den 25.04.2014, 07:37 +0200 schrieb Dirk Behme:
> > > On 24.04.2014 22:23, Lucas Stach wrote:
> > > > The i.MX6 PMU has a design errata where the interrupts of all cores are
> > > > wired together into a single irq line. To work around this we have to
> > > > bounce the interrupt around all cores until we find the one where the PMU
> > > > counter overflow has happened.
> > > >
> > > > This causes the perf measurements to be less accurate and we can't really
> > > > handle the case where two cores fire a PMU irq at the same time. The
> > > > implemented woraround makes perf at least somewhat useable on imx6 SoCs
> > > > with more than one core.
> > > >
[...]
> > > Do you have anything like a test case which shows that it works (at 
> > > least better) on a !single core with this patch? Compared to a 
> > > non-patched system?
> > > 
> > Without this patch, running perf top completely kills the system on
> > i.MX6q, most likely because of the sheer number of spurious interrupts
> > hitting the system from 4 cores. Even the spurious killer doesn't work
> > sometimes, so perf is completely busted right now.
> > 
> > With this patch perf has to reduce the sample frequency in order to
> > compensate the added irq latency, but at least we get some plausible
> > numbers out. Though I won't take any blame if the amount of salt you
> > have to apply while looking at those numbers is already a deadly
> > dose. ;)
> > 
> > I don't yet have any numbers on how accurate the measurement is, but at
> > least things didn't look completely off.
> 
> If it cannot provide correct/accurate data, I'd say let's not fake it
> to, and just let it be completely broken there, so that people can be
> aware of the brokenness, and not take inaccurate data as accurate one.
> 
The data isn't bogus, it just isn't as accurate as it could be with a
properly working PMU. I'll run some tests with a defined load on
Solo/Quad to see how far the measurements are off. I'm fine with holding
this patch until then.

But the thing is this patch also fixes a serious userspace triggerable
DoS on i.MX6q. Just running perf top completely locks up the system
because of the sheer number of stray irqs. This isn't the case anymore
with this patch applied.

Maybe we can just print a warning into dmesg to make the users aware of
the imprecise measurement.

Regards,
Lucas
Behme Dirk (CM/ESO2) April 29, 2014, 11:17 a.m. UTC | #7
On 29.04.2014 11:55, Lucas Stach wrote:
> Am Dienstag, den 29.04.2014, 13:28 +0800 schrieb Shawn Guo:
>> On Fri, Apr 25, 2014 at 11:13:25AM +0200, Lucas Stach wrote:
>>> Am Freitag, den 25.04.2014, 07:37 +0200 schrieb Dirk Behme:
>>>> On 24.04.2014 22:23, Lucas Stach wrote:
>>>>> The i.MX6 PMU has a design errata where the interrupts of all cores are
>>>>> wired together into a single irq line. To work around this we have to
>>>>> bounce the interrupt around all cores until we find the one where the PMU
>>>>> counter overflow has happened.
>>>>>
>>>>> This causes the perf measurements to be less accurate and we can't really
>>>>> handle the case where two cores fire a PMU irq at the same time. The
>>>>> implemented woraround makes perf at least somewhat useable on imx6 SoCs
>>>>> with more than one core.
>>>>>
> [...]
>>>> Do you have anything like a test case which shows that it works (at
>>>> least better) on a !single core with this patch? Compared to a
>>>> non-patched system?
>>>>
>>> Without this patch, running perf top completely kills the system on
>>> i.MX6q, most likely because of the sheer number of spurious interrupts
>>> hitting the system from 4 cores. Even the spurious killer doesn't work
>>> sometimes, so perf is completely busted right now.
>>>
>>> With this patch perf has to reduce the sample frequency in order to
>>> compensate the added irq latency, but at least we get some plausible
>>> numbers out. Though I won't take any blame if the amount of salt you
>>> have to apply while looking at those numbers is already a deadly
>>> dose. ;)
>>>
>>> I don't yet have any numbers on how accurate the measurement is, but at
>>> least things didn't look completely off.
>>
>> If it cannot provide correct/accurate data, I'd say let's not fake it
>> to, and just let it be completely broken there, so that people can be
>> aware of the brokenness, and not take inaccurate data as accurate one.
>>
> The data isn't bogus, it just isn't as accurate as it could be with a
> properly working PMU. I'll run some tests with a defined load on
> Solo/Quad to see how far the measurements are off. I'm fine with holding
> this patch until then.
>
> But the thing is this patch also fixes a serious userspace triggerable
> DoS on i.MX6q. Just running perf top completely locks up the system
> because of the sheer number of stray irqs. This isn't the case anymore
> with this patch applied.
>
> Maybe we can just print a warning into dmesg to make the users aware of
> the imprecise measurement.

Yes, I think this sounds like a good compromise :)

Best regards

Dirk
Zhi Li April 29, 2014, 6:33 p.m. UTC | #8
On Tue, Apr 29, 2014 at 6:17 AM, Dirk Behme <dirk.behme@de.bosch.com> wrote:
> On 29.04.2014 11:55, Lucas Stach wrote:
>>
>> Am Dienstag, den 29.04.2014, 13:28 +0800 schrieb Shawn Guo:
>>>
>>> On Fri, Apr 25, 2014 at 11:13:25AM +0200, Lucas Stach wrote:
>>>>
>>>> Am Freitag, den 25.04.2014, 07:37 +0200 schrieb Dirk Behme:
>>>>>
>>>>> On 24.04.2014 22:23, Lucas Stach wrote:
>>>>>>
>>>>>> The i.MX6 PMU has a design errata where the interrupts of all cores
>>>>>> are
>>>>>> wired together into a single irq line. To work around this we have to
>>>>>> bounce the interrupt around all cores until we find the one where the
>>>>>> PMU
>>>>>> counter overflow has happened.
>>>>>>
>>>>>> This causes the perf measurements to be less accurate and we can't
>>>>>> really
>>>>>> handle the case where two cores fire a PMU irq at the same time. The
>>>>>> implemented woraround makes perf at least somewhat useable on imx6
>>>>>> SoCs
>>>>>> with more than one core.
>>>>>>
>> [...]
>>>>>
>>>>> Do you have anything like a test case which shows that it works (at
>>>>> least better) on a !single core with this patch? Compared to a
>>>>> non-patched system?
>>>>>
>>>> Without this patch, running perf top completely kills the system on
>>>> i.MX6q, most likely because of the sheer number of spurious interrupts
>>>> hitting the system from 4 cores. Even the spurious killer doesn't work
>>>> sometimes, so perf is completely busted right now.
>>>>
>>>> With this patch perf has to reduce the sample frequency in order to
>>>> compensate the added irq latency, but at least we get some plausible
>>>> numbers out. Though I won't take any blame if the amount of salt you
>>>> have to apply while looking at those numbers is already a deadly
>>>> dose. ;)
>>>>
>>>> I don't yet have any numbers on how accurate the measurement is, but at
>>>> least things didn't look completely off.
>>>
>>>
>>> If it cannot provide correct/accurate data, I'd say let's not fake it
>>> to, and just let it be completely broken there, so that people can be
>>> aware of the brokenness, and not take inaccurate data as accurate one.
>>>
>> The data isn't bogus, it just isn't as accurate as it could be with a
>> properly working PMU. I'll run some tests with a defined load on
>> Solo/Quad to see how far the measurements are off. I'm fine with holding
>> this patch until then.
>>
>> But the thing is this patch also fixes a serious userspace triggerable
>> DoS on i.MX6q. Just running perf top completely locks up the system
>> because of the sheer number of stray irqs. This isn't the case anymore
>> with this patch applied.

I am very strange. Why PMU can work because below errata?

ERR006259 ARM: Debug/trace functions (PMU, PTM and ETB) are disabled
with absence of JTAG_TCK clock after POR

Default it should no any PMU irqs happen.

best regards
Frank Li

>>
>> Maybe we can just print a warning into dmesg to make the users aware of
>> the imprecise measurement.
>
>
> Yes, I think this sounds like a good compromise :)
>
> Best regards
>
> Dirk
>
>
>
>
>
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Lucas Stach April 30, 2014, 9:21 a.m. UTC | #9
Am Dienstag, den 29.04.2014, 13:33 -0500 schrieb Frank Li:
> On Tue, Apr 29, 2014 at 6:17 AM, Dirk Behme <dirk.behme@de.bosch.com> wrote:
> > On 29.04.2014 11:55, Lucas Stach wrote:
> >>
> >> Am Dienstag, den 29.04.2014, 13:28 +0800 schrieb Shawn Guo:
> >>>
> >>> On Fri, Apr 25, 2014 at 11:13:25AM +0200, Lucas Stach wrote:
> >>>>
> >>>> Am Freitag, den 25.04.2014, 07:37 +0200 schrieb Dirk Behme:
> >>>>>
> >>>>> On 24.04.2014 22:23, Lucas Stach wrote:
> >>>>>>
> >>>>>> The i.MX6 PMU has a design errata where the interrupts of all cores
> >>>>>> are
> >>>>>> wired together into a single irq line. To work around this we have to
> >>>>>> bounce the interrupt around all cores until we find the one where the
> >>>>>> PMU
> >>>>>> counter overflow has happened.
> >>>>>>
> >>>>>> This causes the perf measurements to be less accurate and we can't
> >>>>>> really
> >>>>>> handle the case where two cores fire a PMU irq at the same time. The
> >>>>>> implemented woraround makes perf at least somewhat useable on imx6
> >>>>>> SoCs
> >>>>>> with more than one core.
> >>>>>>
> >> [...]
> >>>>>
> >>>>> Do you have anything like a test case which shows that it works (at
> >>>>> least better) on a !single core with this patch? Compared to a
> >>>>> non-patched system?
> >>>>>
> >>>> Without this patch, running perf top completely kills the system on
> >>>> i.MX6q, most likely because of the sheer number of spurious interrupts
> >>>> hitting the system from 4 cores. Even the spurious killer doesn't work
> >>>> sometimes, so perf is completely busted right now.
> >>>>
> >>>> With this patch perf has to reduce the sample frequency in order to
> >>>> compensate the added irq latency, but at least we get some plausible
> >>>> numbers out. Though I won't take any blame if the amount of salt you
> >>>> have to apply while looking at those numbers is already a deadly
> >>>> dose. ;)
> >>>>
> >>>> I don't yet have any numbers on how accurate the measurement is, but at
> >>>> least things didn't look completely off.
> >>>
> >>>
> >>> If it cannot provide correct/accurate data, I'd say let's not fake it
> >>> to, and just let it be completely broken there, so that people can be
> >>> aware of the brokenness, and not take inaccurate data as accurate one.
> >>>
> >> The data isn't bogus, it just isn't as accurate as it could be with a
> >> properly working PMU. I'll run some tests with a defined load on
> >> Solo/Quad to see how far the measurements are off. I'm fine with holding
> >> this patch until then.
> >>
> >> But the thing is this patch also fixes a serious userspace triggerable
> >> DoS on i.MX6q. Just running perf top completely locks up the system
> >> because of the sheer number of stray irqs. This isn't the case anymore
> >> with this patch applied.
> 
> I am very strange. Why PMU can work because below errata?
> 
> ERR006259 ARM: Debug/trace functions (PMU, PTM and ETB) are disabled
> with absence of JTAG_TCK clock after POR
> 
> Default it should no any PMU irqs happen.

Hm, I wasn't aware of this errata and I have to say it confuses me a
bit, as contrary to what the errata claims the PMU is working just fine
on imx6 without a JTAG_TCK connected. I've just tested this on 3
different boards (2 of them imx6q, 1 imx6dl) and you can clearly see the
interrupt hitting.

Regards,
Lucas
diff mbox

Patch

diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index e60456d85c9d..73976c484826 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -16,6 +16,7 @@ 
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/init.h>
+#include "linux/interrupt.h"
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
@@ -33,6 +34,7 @@ 
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include "asm/pmu.h"
 #include <asm/system_misc.h>
 
 #include "common.h"
@@ -261,6 +263,39 @@  static void __init imx6q_axi_init(void)
 	}
 }
 
+/*
+ * The i.MX6 PMU has a design errata where the interrupts of all cores are
+ * wired together into a single irq line. To work around this we have to
+ * bounce the interrupt around all cores until we find the one where the PMU
+ * counter overflow has happened.
+ */
+static irqreturn_t imx6q_pmu_handler(int irq, void *dev, irq_handler_t handler)
+{
+	irqreturn_t ret = handler(irq, dev);
+	int next;
+
+	if (ret == IRQ_NONE) {
+		/*
+		 * Kick the irq over to the next cpu, regardless of it's
+		 * online status (it might have gone offline while we were busy
+		 * bouncing the irq).
+		 */
+		next = (smp_processor_id() + 1) % num_present_cpus();
+		irq_set_affinity(irq, cpumask_of(next));
+	}
+
+	return ret;
+}
+
+struct arm_pmu_platdata imx6q_pmu_platdata = {
+	.handle_irq		= imx6q_pmu_handler,
+};
+
+static struct of_dev_auxdata imx6q_auxdata_lookup[] __initdata = {
+	OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &imx6q_pmu_platdata),
+	{}
+};
+
 static void __init imx6q_init_machine(void)
 {
 	struct device *parent;
@@ -276,7 +311,8 @@  static void __init imx6q_init_machine(void)
 
 	imx6q_enet_phy_init();
 
-	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
+	of_platform_populate(NULL, of_default_bus_match_table,
+			imx6q_auxdata_lookup, parent);
 
 	imx_anatop_init();
 	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();