Initial PS3 perfmon2 support.
On PS3, the PS3 PMU(arch/powerpc/platform/ps3/pmu.c) is used instead of
the Cell PMU(arch/powerpc/platform/cell/pmu.c) to control the HW PMU.
This patch basically replaces cbe_***() with ps3_***() to use the PS3 PMU. 
To reduce platform dependency, 
this patch adds the pfm_cell_platform_pmu_info structure which has
PMU function pointers for each Cell platform.

And this patch also adds aquire_pmu()/release_pmu() to pfm_arch_pmu_info
structure. They are needed to create/delete the PS3 PMU at PFM PMU
acquisition/
release.

Signed-off-by: Takashi Yamamoto <TakashiA.Yamamoto at jp.sony.com>
---
 arch/powerpc/perfmon/perfmon_cell.c |  218
++++++++++++++++++++++++++++++++----
 include/asm-powerpc/perfmon.h       |   17 ++
 2 files changed, 215 insertions(+), 20 deletions(-)

--- a/arch/powerpc/perfmon/perfmon_cell.c
+++ b/arch/powerpc/perfmon/perfmon_cell.c
@@ -31,12 +31,30 @@
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/rtas.h>
+#include <asm/ps3.h>
 
 MODULE_AUTHOR("Kevin Corry <[EMAIL PROTECTED]>, "
              "Carl Love <[EMAIL PROTECTED]>");
 MODULE_DESCRIPTION("Cell PMU description table");
 MODULE_LICENSE("GPL");
 
+struct pfm_cell_platform_pmu_info {
+       u32  (*read_ctr)(u32 cpu, u32 ctr);
+       void (*write_ctr)(u32 cpu, u32 ctr, u32 val);
+       void (*write_pm07_control)(u32 cpu, u32 ctr, u32 val);
+       void (*write_pm)(u32 cpu, enum pm_reg_name reg, u32 val);
+       void (*enable_pm)(u32 cpu);
+       void (*disable_pm)(u32 cpu);
+       void (*enable_pm_interrupts)(u32 cpu, u32 thread, u32 mask);
+       u32  (*get_and_clear_pm_interrupts)(u32 cpu);
+       u32  (*get_hw_thread_id)(int cpu);
+       struct cbe_ppe_priv_regs __iomem *(*get_cpu_ppe_priv_regs)(int cpu);
+       struct cbe_pmd_regs __iomem *(*get_cpu_pmd_regs)(int cpu);
+       struct cbe_mic_tm_regs __iomem *(*get_cpu_mic_tm_regs)(int cpu);
+       int (*rtas_token)(const char *service);
+       int (*rtas_call)(int token, int param1, int param2, int *param3,
...);
+};
+
 /*
  * Mapping from Perfmon logical control registers to Cell hardware
registers.
  */
@@ -154,10 +172,13 @@ static int rtas_reset_signals(u32 cpu)
        struct cell_rtas_arg signal;
        u64 real_addr = virt_to_phys(&signal);
        int rc;
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        memset(&signal, 0, sizeof(signal));
        signal.cpu = RTAS_CPU(cpu);
-       rc = rtas_call(rtas_token("ibm,cbe-perftools"),
+       rc = info->rtas_call(info->rtas_token("ibm,cbe-perftools"),
                       5, 1, NULL,
                       subfunc_RESET,
                       passthru_DISABLE,
@@ -179,8 +200,11 @@ static int rtas_activate_signals(struct 
 {
        u64 real_addr = virt_to_phys(signals);
        int rc;
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
-       rc = rtas_call(rtas_token("ibm,cbe-perftools"),
+       rc = info->rtas_call(info->rtas_token("ibm,cbe-perftools"),
                       5, 1, NULL,
                       subfunc_ACTIVATE,
                       passthru_ENABLE,
@@ -267,10 +291,13 @@ static int passthru(u32 cpu, u64 enable)
        struct cbe_ppe_priv_regs __iomem *ppe_priv_regs;
        struct cbe_pmd_regs __iomem *pmd_regs;
        struct cbe_mic_tm_regs __iomem *mic_tm_regs;
-
-       ppe_priv_regs = cbe_get_cpu_ppe_priv_regs(cpu);
-       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-       mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
+
+       ppe_priv_regs = info->get_cpu_ppe_priv_regs(cpu);
+       pmd_regs = info->get_cpu_pmd_regs(cpu);
+       mic_tm_regs = info->get_cpu_mic_tm_regs(cpu);
 
        if (!ppe_priv_regs || !pmd_regs || !mic_tm_regs) {
                PFM_ERR("Error getting Cell PPE, PMD, and MIC "
@@ -402,6 +429,39 @@ static int celleb_activate_signals(struc
 }
 
 /**
+ * ps3_reset_signals
+ *
+ * ps3 version of resetting the debug-bus signals.
+ **/
+static int ps3_reset_signals(u32 cpu)
+{
+#ifdef CONFIG_PPC_PS3
+       return ps3_set_signal(0, 0, 0, 0);
+#else
+       return 0;
+#endif
+}
+
+/**
+ * ps3_activate_signals
+ *
+ * ps3 version of activating the debug-bus signals.
+ **/
+static int ps3_activate_signals(struct cell_rtas_arg *signals,
+                               int num_signals)
+{
+#ifdef CONFIG_PPC_PS3
+       int i;
+
+       for (i = 0; i < num_signals; i++)
+               ps3_set_signal(signals[i].signal_group, signals[i].bit,
+                              signals[i].sub_unit, signals[i].bus_word);
+#endif
+       return 0;
+}
+
+
+/**
  * reset_signals
  *
  * Call to the firmware (if available) to reset the debug-bus signals.
@@ -413,6 +473,8 @@ int reset_signals(u32 cpu)
 
        if (machine_is(celleb))
                rc = celleb_reset_signals(cpu);
+       else if (machine_is(ps3))
+               rc = ps3_reset_signals(cpu);
        else
                rc = rtas_reset_signals(cpu);
 
@@ -431,6 +493,8 @@ int activate_signals(struct cell_rtas_ar
 
        if (machine_is(celleb))
                rc = celleb_activate_signals(signals, num_signals);
+       else if (machine_is(ps3))
+               rc = ps3_activate_signals(signals, num_signals);
        else
                rc = rtas_activate_signals(signals, num_signals);
 
@@ -539,9 +603,12 @@ static int pfm_cell_probe_pmu(void)
 static void pfm_cell_write_pmc(unsigned int cnum, u64 value)
 {
        int cpu = smp_processor_id();
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        if (cnum < NR_CTRS) {
-               cbe_write_pm07_control(cpu, cnum, value);
+               info->write_pm07_control(cpu, cnum, value);
 
        } else if (cnum < NR_CTRS * 2) {
                write_pm07_event(cpu, cnum - NR_CTRS, value);
@@ -552,10 +619,11 @@ static void pfm_cell_write_pmc(unsigned 
                 * the interrupts are routed to the correct CPU, as well
                 * as writing the desired value to the pm_status register.
                 */
-               cbe_enable_pm_interrupts(cpu, cbe_get_hw_thread_id(cpu),
value);
+               info->enable_pm_interrupts(cpu, info->get_hw_thread_id(cpu),
+                                          value);
 
        } else if (cnum < PFM_PM_NUM_PMCS) {
-               cbe_write_pm(cpu, cnum - (NR_CTRS * 2), value);
+               info->write_pm(cpu, cnum - (NR_CTRS * 2), value);
        }
 }
 
@@ -565,9 +633,12 @@ static void pfm_cell_write_pmc(unsigned 
 static void pfm_cell_write_pmd(unsigned int cnum, u64 value)
 {
        int cpu = smp_processor_id();
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        if (cnum < NR_CTRS) {
-               cbe_write_ctr(cpu, cnum, value);
+               info->write_ctr(cpu, cnum, value);
        }
 }
 
@@ -577,9 +648,12 @@ static void pfm_cell_write_pmd(unsigned 
 static u64 pfm_cell_read_pmd(unsigned int cnum)
 {
        int cpu = smp_processor_id();
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        if (cnum < NR_CTRS) {
-               return cbe_read_ctr(cpu, cnum);
+               return info->read_ctr(cpu, cnum);
        }
 
        return -EINVAL;
@@ -593,7 +667,11 @@ static u64 pfm_cell_read_pmd(unsigned in
 static void pfm_cell_enable_counters(struct pfm_context *ctx,
                                     struct pfm_event_set *set)
 {
-       cbe_enable_pm(smp_processor_id());
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
+
+       info->enable_pm(smp_processor_id());
 }
 
 /**
@@ -604,7 +682,13 @@ static void pfm_cell_enable_counters(str
 static void pfm_cell_disable_counters(struct pfm_context *ctx,
                                      struct pfm_event_set *set)
 {
-       cbe_disable_pm(smp_processor_id());
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
+
+       info->disable_pm(smp_processor_id());
+       if (machine_is(ps3))
+               reset_signals(smp_processor_id());
 }
 
 /**
@@ -622,6 +706,9 @@ void pfm_cell_restore_pmcs(struct pfm_ev
        u64 value, *used_pmcs = set->used_pmcs;
        int i, rc, num_used = 0, cpu = smp_processor_id();
        s32 signal_number;
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        memset(signals, 0, sizeof(signals));
 
@@ -630,7 +717,7 @@ void pfm_cell_restore_pmcs(struct pfm_ev
                 * in use, then it will simply clear the register, which
will
                 * disable the associated counter.
                 */
-               cbe_write_pm07_control(cpu, i, set->pmcs[i]);
+               info->write_pm07_control(cpu, i, set->pmcs[i]);
 
                /* Set up the next RTAS array entry for this counter. Only
                 * include pm07_event registers that are in use by this set
@@ -720,6 +807,9 @@ static void pfm_cell_get_ovfl_pmds(struc
        u32 pm_status, ovfl_ctrs;
        u64 povfl_pmds = 0;
        int i;
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        if (!ctx_arch->last_read_updated)
                /* This routine was not called via the interrupt handler.
@@ -727,7 +817,7 @@ static void pfm_cell_get_ovfl_pmds(struc
                 * last_read_pm_status.
                 */
                ctx_arch->last_read_pm_status =
-                       cbe_get_and_clear_pm_interrupts(smp_processor_id());
+
info->get_and_clear_pm_interrupts(smp_processor_id());
 
        /* Reset the flag that the interrupt handler last read pm_status. */
        ctx_arch->last_read_updated = 0;
@@ -753,6 +843,45 @@ static void pfm_cell_get_ovfl_pmds(struc
 }
 
 /**
+ * pfm_cell_acquire_pmu
+ *
+ * acquire PMU resource.
+ * This acquisition is done when the first context is created.
+ **/
+int pfm_cell_acquire_pmu(void)
+{
+#ifdef CONFIG_PPC_PS3
+       int ret;
+
+       if (machine_is(ps3)) {
+               PFM_DBG("");
+               ret = ps3_create_lpm(1, 0, 0, 1);
+               if (ret) {
+                       PFM_ERR("Can't create PS3 lpm. error:%d", ret);
+                       return -EFAULT;
+               }
+       }
+#endif
+       return 0;
+}
+
+/**
+ * pfm_cell_release_pmu
+ *
+ * release PMU resource.
+ * actual release happens when last context is destroyed
+ **/
+void pfm_cell_release_pmu(void)
+{
+#ifdef CONFIG_PPC_PS3
+       if (machine_is(ps3)) {
+               if (ps3_delete_lpm())
+                       PFM_ERR("Can't delete PS3 lpm.");
+       }
+#endif
+}
+
+/**
  * handle_trace_buffer_interrupts
  *
  * This routine is for processing just the interval timer and trace buffer
@@ -780,12 +909,15 @@ static void pfm_cell_irq_handler(struct 
        struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx);
        u32 last_read_pm_status;
        int cpu = smp_processor_id();
+       struct pfm_cell_platform_pmu_info *info =
+               ((struct pfm_arch_pmu_info *)
+                (pfm_pmu_conf->arch_info))->platform_info;
 
        /* Need to disable and reenable the performance counters to get the
         * desired behavior from the hardware. This is specific to the Cell
         * PMU hardware.
         */
-       cbe_disable_pm(cpu);
+       info->disable_pm(cpu);
 
        /* Read the pm_status register to get the interrupt bits. If a
         * perfmormance counter overflow interrupt occurred, call the core
@@ -807,7 +939,7 @@ static void pfm_cell_irq_handler(struct 
         * - The pmd0 bit is the MSB of the 32 bit register.
         */
        ctx_arch->last_read_pm_status = last_read_pm_status =
-
cbe_get_and_clear_pm_interrupts(cpu);
+               info->get_and_clear_pm_interrupts(cpu);
 
        /* Set flag for pfm_cell_get_ovfl_pmds() routine so it knows
         * last_read_pm_status was updated by the interrupt handler.
@@ -829,8 +961,8 @@ static void pfm_cell_irq_handler(struct 
         * register. It is saved in the context when the register is
         * written.
         */
-       cbe_enable_pm_interrupts(cpu, cbe_get_hw_thread_id(cpu),
-                                ctx->active_set->pmcs[CELL_PMC_PM_STATUS]);
+       info->enable_pm_interrupts(cpu, info->get_hw_thread_id(cpu),
+
ctx->active_set->pmcs[CELL_PMC_PM_STATUS]);
 
        /* The writes to the various performance counters only writes to a
         * latch. The new values (interrupt setting bits, reset counter
value
@@ -839,11 +971,52 @@ static void pfm_cell_irq_handler(struct 
         * permormance monitor needs to be disabled while writting to the
         * latches. This is a HW design issue.
         */
-       cbe_enable_pm(cpu);
+       info->enable_pm(cpu);
 }
 
+
+static struct pfm_cell_platform_pmu_info ps3_platform_pmu_info = {
+#ifdef CONFIG_PPC_PS3
+       .read_ctr                    = ps3_read_ctr,
+       .write_ctr                   = ps3_write_ctr,
+       .write_pm07_control          = ps3_write_pm07_control,
+       .write_pm                    = ps3_write_pm,
+       .enable_pm                   = ps3_enable_pm,
+       .disable_pm                  = ps3_disable_pm,
+       .enable_pm_interrupts        = ps3_enable_pm_interrupts,
+       .get_and_clear_pm_interrupts = ps3_get_and_clear_pm_interrupts,
+       .get_hw_thread_id            = ps3_get_hw_thread_id,
+       .get_cpu_ppe_priv_regs       = NULL,
+       .get_cpu_pmd_regs            = NULL,
+       .get_cpu_mic_tm_regs         = NULL,
+       .rtas_token                  = NULL,
+       .rtas_call                   = NULL,
+#endif
+};
+
+static struct pfm_cell_platform_pmu_info native_platform_pmu_info = {
+#ifdef CONFIG_PPC_CELL_NATIVE
+       .read_ctr                    = cbe_read_ctr,
+       .write_ctr                   = cbe_write_ctr,
+       .write_pm07_control          = cbe_write_pm07_control,
+       .write_pm                    = cbe_write_pm,
+       .enable_pm                   = cbe_enable_pm,
+       .disable_pm                  = cbe_disable_pm,
+       .enable_pm_interrupts        = cbe_enable_pm_interrupts,
+       .get_and_clear_pm_interrupts = cbe_get_and_clear_pm_interrupts,
+       .get_hw_thread_id            = cbe_get_hw_thread_id,
+       .get_cpu_ppe_priv_regs       = cbe_get_cpu_ppe_priv_regs,
+       .get_cpu_pmd_regs            = cbe_get_cpu_pmd_regs,
+       .get_cpu_mic_tm_regs         = cbe_get_cpu_mic_tm_regs,
+       .rtas_token                  = rtas_token,
+       .rtas_call                   = rtas_call,
+#endif
+};
+
 static struct pfm_arch_pmu_info pfm_cell_pmu_info = {
        .pmu_style        = PFM_POWERPC_PMU_CELL,
+       .acquire_pmu      = pfm_cell_acquire_pmu,
+       .release_pmu      = pfm_cell_release_pmu,
        .write_pmc        = pfm_cell_write_pmc,
        .write_pmd        = pfm_cell_write_pmd,
        .read_pmd         = pfm_cell_read_pmd,
@@ -884,6 +1057,11 @@ static void pfm_cell_platform_probe(void
                for (cnum = NR_CTRS; cnum < (NR_CTRS * 2); cnum++)
                        pfm_cell_pmc_desc[cnum].type |= PFM_REG_WC;
        }
+
+       if (machine_is(ps3))
+               pfm_cell_pmu_info.platform_info = &ps3_platform_pmu_info;
+       else
+               pfm_cell_pmu_info.platform_info = &native_platform_pmu_info;
 }
 
 static int __init pfm_cell_pmu_init_module(void)
--- a/include/asm-powerpc/perfmon.h
+++ b/include/asm-powerpc/perfmon.h
@@ -74,6 +74,9 @@ struct pfm_arch_pmu_info {
                             struct task_struct *task);
        int  (*unload_context)(struct pfm_context *ctx,
                               struct task_struct *task);
+       int  (*acquire_pmu)(void);
+       void (*release_pmu)(void);
+       void *platform_info;
 };
 
 #ifdef CONFIG_PPC32
@@ -340,11 +343,25 @@ static inline ssize_t pfm_arch_compat_re
 
 static inline int pfm_arch_pmu_acquire(void)
 {
+       struct pfm_arch_pmu_info *arch_info = pfm_pmu_conf->arch_info;
+       int rc = 0;
+
+       if (arch_info->acquire_pmu) {
+               rc = arch_info->acquire_pmu();
+               if (rc)
+                       return rc;
+       }
+
        return reserve_pmc_hardware(powerpc_irq_handler);
 }
 
 static inline void pfm_arch_pmu_release(void)
 {
+       struct pfm_arch_pmu_info *arch_info = pfm_pmu_conf->arch_info;
+
+       if (arch_info->release_pmu)
+               arch_info->release_pmu();
+
        release_pmc_hardware();
 }


_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/

Reply via email to