Hi,

I am trying to get perf_event to work properly on my OMAP4 Pandabaord
running the 3.2.0 kernel. I am the developer on libpfm4 and a regular
contributor to the perf_event subsystem and perf tool. I want to use
a Pandaboard to test libpfm4 ARM support.

I have been talking with Will Deacon and he suggested I post to this list.

I know that the off-the-shelf 3.2.0 does not have working PMU interrupts.
I have integrated additional patches from both Ming Lei and Linaro. It
seems some parts of those patches were integrated into 3.2.0.

I have attached my 3.2.0 changes to this message. With that, I get perf_event
to register PMU interrupts 33 and 34. However, they don't fire when I count
therefore the counts are bogus (counters wrap around).

I suspect I am missing something in the patch I put together. But I don't know
what's missing. I am not an ARM platform expert. I am hoping someone on this
list may shed some light on this problem.

It would be really nice to have perf_event running out of the box on Pandaboard
for 3.3. It would go a long way into making performance monitoring usable on 
ARM.

Thanks.
---

diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 0bda22c..b5a5be2 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -27,13 +27,22 @@ enum arm_pmu_type {
 /*
  * struct arm_pmu_platdata - ARM PMU platform data
  *
- * @handle_irq: an optional handler which will be called from the interrupt and
- * passed the address of the low level handler, and can be used to implement
- * any platform specific handling before or after calling it.
+ * @handle_irq: an optional handler which will be called from the
+ *     interrupt and passed the address of the low level handler,
+ *     and can be used to implement any platform specific handling
+ *     before or after calling it.
+ * @enable_irq: an optional handler which will be called after
+ *     request_irq and be used to handle some platform specific
+ *     irq enablement
+ * @disable_irq: an optional handler which will be called before
+ *     free_irq and be used to handle some platform specific
+ *     irq disablement
  */
 struct arm_pmu_platdata {
        irqreturn_t (*handle_irq)(int irq, void *dev,
                                  irq_handler_t pmu_handler);
+       void (*enable_irq)(int irq);
+       void (*disable_irq)(int irq);
 };
 
 #ifdef CONFIG_CPU_HAS_PMU
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 88b0941..24e001f 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -380,6 +380,8 @@ armpmu_release_hardware(struct arm_pmu *armpmu)
 {
        int i, irq, irqs;
        struct platform_device *pmu_device = armpmu->plat_device;
+       struct arm_pmu_platdata *plat =
+               dev_get_platdata(&pmu_device->dev);
 
        irqs = min(pmu_device->num_resources, num_possible_cpus());
 
@@ -387,8 +389,11 @@ armpmu_release_hardware(struct arm_pmu *armpmu)
                if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
                        continue;
                irq = platform_get_irq(pmu_device, i);
-               if (irq >= 0)
+               if (irq >= 0) {
+                       if (plat->disable_irq)
+                               plat->disable_irq(irq);
                        free_irq(irq, armpmu);
+               }
        }
 
        release_pmu(armpmu->type);
@@ -449,6 +454,8 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
                        armpmu_release_hardware(armpmu);
                        return err;
                }
+               if (plat->enable_irq)
+                       plat->enable_irq(irq);
 
                cpumask_set_cpu(i, &armpmu->active_irqs);
        }
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index c15cfad..6caf31a 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -17,12 +17,14 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/pm_runtime.h>
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
+#include <asm/cti.h>
 
 #include <plat/tc.h>
 #include <plat/board.h>
@@ -404,14 +406,136 @@ static struct platform_device omap_pmu_device = {
        .num_resources  = 1,
 };
 
-static void omap_init_pmu(void)
+static struct arm_pmu_platdata omap4_pmu_data;
+static struct cti omap4_cti[2];
+static struct platform_device *pmu_dev;
+
+static void omap4_enable_cti(int irq)
 {
-       if (cpu_is_omap24xx())
+       pm_runtime_get_sync(&pmu_dev->dev);
+
+       if (irq == OMAP44XX_IRQ_CTI0)
+               cti_enable(&omap4_cti[0]);
+       else if (irq == OMAP44XX_IRQ_CTI1)
+               cti_enable(&omap4_cti[1]);
+}
+
+static void omap4_disable_cti(int irq)
+{
+       if (irq == OMAP44XX_IRQ_CTI0)
+               cti_disable(&omap4_cti[0]);
+       else if (irq == OMAP44XX_IRQ_CTI1)
+               cti_disable(&omap4_cti[1]);
+       pm_runtime_put(&pmu_dev->dev);
+}
+
+static irqreturn_t omap4_pmu_handler(int irq, void *dev, irq_handler_t handler)
+{
+       if (irq == OMAP44XX_IRQ_CTI0)
+               cti_irq_ack(&omap4_cti[0]);
+       else if (irq == OMAP44XX_IRQ_CTI1)
+               cti_irq_ack(&omap4_cti[1]);
+
+       return handler(irq, dev);
+}
+
+static void omap4_configure_pmu_irq(void)
+{
+       void __iomem *base0;
+       void __iomem *base1;
+
+       base0 = ioremap(OMAP44XX_CTI0_BASE, SZ_4K);
+       base1 = ioremap(OMAP44XX_CTI1_BASE, SZ_4K);
+       if (!base0 && !base1) {
+               pr_err("ioremap for OMAP4 CTI failed\n");
+               return;
+       }
+
+       /*configure CTI0 for pmu irq routing*/
+       cti_init(&omap4_cti[0], base0, OMAP44XX_IRQ_CTI0, 6);
+       cti_unlock(&omap4_cti[0]);
+       cti_map_trigger(&omap4_cti[0], 1, 6, 2);
+
+       /*configure CTI1 for pmu irq routing*/
+       cti_init(&omap4_cti[1], base1, OMAP44XX_IRQ_CTI1, 6);
+       cti_unlock(&omap4_cti[1]);
+       cti_map_trigger(&omap4_cti[1], 1, 6, 2);
+
+       omap4_pmu_data.handle_irq = omap4_pmu_handler;
+       omap4_pmu_data.enable_irq = omap4_enable_cti;
+       omap4_pmu_data.disable_irq = omap4_disable_cti;
+}
+
+static struct arm_pmu_platdata omap4_pmu_data;
+static struct omap_device_pm_latency omap_pmu_latency[] = {
+       [0] = {
+               .deactivate_func = omap_device_idle_hwmods,
+               .activate_func   = omap_device_enable_hwmods,
+               .flags           = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+};
+
+static struct platform_device* __init omap4_init_pmu(void)
+{
+       int id = -1;
+       const char *hw;
+       struct platform_device *pd;
+       struct omap_hwmod* oh[3];
+       char *dev_name = "arm-pmu";
+
+       hw = "l3_main_3";
+       oh[0] = omap_hwmod_lookup(hw);
+       if (!oh[0]) {
+               pr_err("Could not look up %s hwmod\n", hw);
+               return NULL;
+       }
+       hw = "l3_instr";
+       oh[1] = omap_hwmod_lookup(hw);
+       if (!oh[1]) {
+               pr_err("Could not look up %s hwmod\n", hw);
+               return NULL;
+       }
+       hw = "emu";
+       oh[2] = omap_hwmod_lookup(hw);
+       if (!oh[2]) {
+               pr_err("Could not look up %s hwmod\n", hw);
+               return NULL;
+       }
+
+       pd = omap_device_build_ss(dev_name, id, oh, 3, &omap4_pmu_data,
+                       sizeof(omap4_pmu_data),
+                       omap_pmu_latency,
+                       ARRAY_SIZE(omap_pmu_latency), 0);
+       WARN(IS_ERR(pd), "Can't build omap_device for %s.\n",
+                       dev_name);
+       return pd;
+}
+
+static void __init omap_init_pmu(void)
+{
+       if (cpu_is_omap24xx()) {
                omap_pmu_device.resource = &omap2_pmu_resource;
-       else if (cpu_is_omap34xx())
+       } else if (cpu_is_omap34xx()) {
                omap_pmu_device.resource = &omap3_pmu_resource;
-       else
+       } else if (cpu_is_omap44xx()) {
+               struct platform_device *pd;
+
+               pd = omap4_init_pmu();
+               if (!pd)
+                       return;
+{ int i;
+  for (i = 0 ; i < 2; i++)
+               printk("RES:%d IRQ:%d\n", i, platform_get_irq(pd, i));
+}
+               pmu_dev = pd;
+               pm_runtime_enable(&pd->dev);
+               pm_runtime_get_sync(&pd->dev);
+               omap4_configure_pmu_irq();
+               pm_runtime_put(&pd->dev);
+               return;
+       } else {
                return;
+       }
 
        platform_device_register(&omap_pmu_device);
 }
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c 
b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index daaf165..dd4e1c2 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -5276,6 +5276,30 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
        .slaves_cnt     = ARRAY_SIZE(omap44xx_wd_timer3_slaves),
 };
 
+static struct omap_hwmod_class omap44xx_emu_hwmod_class = {
+       .name   = "emu",
+};
+
+static struct omap_hwmod_irq_info omap44xx_emu_irqs[] = {
+       { .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START },
+       { .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START },
+       { .irq = -1 }
+};
+
+/*emu hwmod*/
+static struct omap_hwmod omap44xx_emu_hwmod = {
+       .name           = "emu",
+       .class          = &omap44xx_emu_hwmod_class,
+       .clkdm_name     = "emu_sys_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP4_CM_EMU_CLKSTCTRL_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .mpu_irqs       = omap44xx_emu_irqs,
+};
+
 static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
 
        /* dmm class */
@@ -5422,6 +5446,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
        &omap44xx_wd_timer2_hwmod,
        &omap44xx_wd_timer3_hwmod,
 
+       /*emu class*/
+       &omap44xx_emu_hwmod,
+
        NULL,
 };
 
diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h 
b/arch/arm/plat-omap/include/plat/omap44xx.h
index ea2b8a6..b127a16 100644
--- a/arch/arm/plat-omap/include/plat/omap44xx.h
+++ b/arch/arm/plat-omap/include/plat/omap44xx.h
@@ -57,5 +57,7 @@
 #define OMAP44XX_HSUSB_OHCI_BASE       (L4_44XX_BASE + 0x64800)
 #define OMAP44XX_HSUSB_EHCI_BASE       (L4_44XX_BASE + 0x64C00)
 
+#define OMAP44XX_CTI0_BASE             0x54148000
+#define OMAP44XX_CTI1_BASE             0x54149000
 #endif /* __ASM_ARCH_OMAP44XX_H */
 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to