Kevin,

Patch was applied.

Thanks for your contributions.

On Wed, Sep 05, 2007 at 09:15:32AM -0500, Kevin Corry wrote:
> Add in-kernel debug-bus signal routing for Cell systems that do not include
> firmware with the "ibm,cbe-perftools" RTAS call. This code only handles two
> signal-groups: PPU Instruction Unit (Group 1) and PPU Execution Unit.
> 
> This is a modification of the patches posted by Takaki Azuma
> ([EMAIL PROTECTED]) and Takayuki Uchikawa
> ([EMAIL PROTECTED]). The code from perfmon_cell_signals.c
> and perfmon_cell_signals.h has been merged into perfmon_cell.c. Having the
> multiple files causes headaches with the kernel build when perfmon_cell is
> configured as a module. The additional code is only about 300 lines, so I
> think it's reasonable to include it in the same file as the existing code.
> Other minor changes and bug-fixes were also made.
> 
> Signed-off-by: Kevin Corry <[EMAIL PROTECTED]>
> ---
> 
>  arch/powerpc/perfmon/perfmon_cell.c |  341 
> ++++++++++++++++++++++++++++++++++-
>  1 files changed, 330 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/powerpc/perfmon/perfmon_cell.c 
> b/arch/powerpc/perfmon/perfmon_cell.c
> index 91c6f75..6f6eb8f 100644
> --- a/arch/powerpc/perfmon/perfmon_cell.c
> +++ b/arch/powerpc/perfmon/perfmon_cell.c
> @@ -3,6 +3,7 @@
>   * and pmc checker used by perfmon.c.
>   *
>   * Copyright IBM Corporation 2007
> + * (C) Copyright 2007 TOSHIBA CORPORATION
>   *
>   * Based on other Perfmon2 PMU modules.
>   * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
> @@ -27,6 +28,7 @@
>  #include <linux/perfmon.h>
>  #include <asm/cell-pmu.h>
>  #include <asm/io.h>
> +#include <asm/machdep.h>
>  #include <asm/rtas.h>
>  #include "../platforms/cell/cbe_regs.h"
>  #include <asm/perfmon_cell_hw_smpl.h>
> @@ -92,6 +94,14 @@ static struct pfm_regmap_desc pfm_cell_pmd_desc[] = {
>  };
>  #define PFM_PM_NUM_PMDS      ARRAY_SIZE(pfm_cell_pmd_desc)
>  
> +/*
> + * Debug-bus signal handling.
> + *
> + * Some Cell systems have firmware that can handle the debug-bus signal
> + * routing. For systems without this firmware, we have a minimal in-kernel
> + * implementation as well.
> + */
> +
>  /* The firmware only sees physical CPUs, so divide by 2 if SMT is on. */
>  #ifdef CONFIG_SCHED_SMT
>  #define RTAS_CPU(cpu) ((cpu) / 2)
> @@ -101,6 +111,7 @@ static struct pfm_regmap_desc pfm_cell_pmd_desc[] = {
>  #define RTAS_BUS_WORD(x)      (u16)(((x) >> 48) & 0x0000ffff)
>  #define RTAS_SUB_UNIT(x)      (u16)(((x) >> 32) & 0x0000ffff)
>  #define RTAS_SIGNAL_NUMBER(x) (s32)( (x)        & 0xffffffff)
> +#define RTAS_SIGNAL_GROUP(x)  (RTAS_SIGNAL_NUMBER(x) / 100)
>  
>  #define subfunc_RESET                1
>  #define subfunc_ACTIVATE     2
> @@ -135,8 +146,8 @@ struct cell_rtas_arg {
>  /**
>   * rtas_reset_signals
>   *
> - * Set up the RTAS arguments for a RESET command. The buffer will be only
> - * the first entry in the rtas_args[cpu].signal[] array.
> + * Use the firmware RTAS call to disable signal pass-thru and to reset the
> + * debug-bus signals.
>   **/
>  static int rtas_reset_signals(u32 cpu)
>  {
> @@ -160,9 +171,8 @@ static int rtas_reset_signals(u32 cpu)
>  /**
>   * rtas_activate_signals
>   *
> - * Set up the RTAS arguments for an ACTIVATE command. The buffer will be the
> - * number of entries in the rtas_args[cpu].signal[] array that were filled
> - * in by attach_signal_to_counter().
> + * Use the firmware RTAS call to enable signal pass-thru and to activate the
> + * desired signal groups on the debug-bus.
>   **/
>  static int rtas_activate_signals(struct cell_rtas_arg *signals,
>                                int num_signals)
> @@ -181,6 +191,298 @@ static int rtas_activate_signals(struct cell_rtas_arg 
> *signals,
>       return rc;
>  }
>  
> +#define HID1_RESET_MASK                      (~0x00000001ffffffffUL)
> +#define PPU_IU1_WORD0_HID1_EN_MASK   (~0x00000001f0c0802cUL)
> +#define PPU_IU1_WORD0_HID1_EN_WORD   ( 0x00000001f0400000UL)
> +#define PPU_IU1_WORD1_HID1_EN_MASK   (~0x000000010fc08023UL)
> +#define PPU_IU1_WORD1_HID1_EN_WORD   ( 0x000000010f400001UL)
> +#define PPU_XU_WORD0_HID1_EN_MASK    (~0x00000001f038402cUL)
> +#define PPU_XU_WORD0_HID1_EN_WORD    ( 0x00000001f0080008UL)
> +#define PPU_XU_WORD1_HID1_EN_MASK    (~0x000000010f074023UL)
> +#define PPU_XU_WORD1_HID1_EN_WORD    ( 0x000000010f030002UL)
> +
> +/* The bus_word field in the cell_rtas_arg structure is a bit-mask
> + * indicating which debug-bus word(s) to use.
> + */
> +enum {
> +     BUS_WORD_0 = 1,
> +     BUS_WORD_1 = 2,
> +     BUS_WORD_2 = 4,
> +     BUS_WORD_3 = 8,
> +};
> +
> +/* Definitions of the signal-groups that the built-in signal-activation
> + * code can handle.
> + */
> +enum {
> +     SIG_GROUP_NONE = 0,
> +
> +     /* 2.x PowerPC Processor Unit (PPU) Signal Groups */
> +     SIG_GROUP_PPU_IU1 = 21,
> +     SIG_GROUP_PPU_XU = 22,
> +};
> +
> +/**
> + * rmw_spr
> + *
> + * Read-modify-write for a special-purpose-register.
> + **/
> +#define rmw_spr(spr_id, a_mask, o_mask) \
> +     do { \
> +             u64 value = mfspr(spr_id); \
> +             value &= (u64)(a_mask); \
> +             value |= (u64)(o_mask); \
> +             mtspr((spr_id), value); \
> +     } while (0)
> +
> +/**
> + * rmw_mmio_reg64
> + *
> + * Read-modify-write for a 64-bit MMIO register.
> + **/
> +#define rmw_mmio_reg64(mem, a_mask, o_mask) \
> +     do { \
> +             u64 value = in_be64(&(mem)); \
> +             value &= (u64)(a_mask); \
> +             value |= (u64)(o_mask); \
> +             out_be64(&(mem), value); \
> +     } while (0)
> +
> +/**
> + * rmwb_mmio_reg64
> + *
> + * Set or unset a specified bit within a 64-bit MMIO register.
> + **/
> +#define rmwb_mmio_reg64(mem, bit_num, set_bit) \
> +     rmw_mmio_reg64((mem), ~(1UL << (63 - (bit_num))), \
> +                    ((set_bit) << (63 - (bit_num))))
> +
> +/**
> + * passthru
> + *
> + * Enable or disable passthru mode in all the Cell signal islands.
> + **/
> +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);
> +
> +     if (!ppe_priv_regs || !pmd_regs || !mic_tm_regs) {
> +             PFM_ERR("Error getting Cell PPE, PMD, and MIC "
> +                     "register maps: 0x%p, 0x%p, 0x%p",
> +                     ppe_priv_regs, pmd_regs, mic_tm_regs);
> +             return -EINVAL;
> +     }
> +
> +     rmwb_mmio_reg64(ppe_priv_regs->L2_debug1, 61, enable);
> +     rmwb_mmio_reg64(ppe_priv_regs->ciu_dr1, 5, enable);
> +     rmwb_mmio_reg64(pmd_regs->on_ramp_trace, 39, enable);
> +     rmwb_mmio_reg64(mic_tm_regs->MBL_debug, 20, enable);
> +
> +     return 0;
> +}
> +
> +#define passthru_enable(cpu)  passthru(cpu, 1)
> +#define passthru_disable(cpu) passthru(cpu, 0)
> +
> +static inline void reset_signal_registers(u32 cpu)
> +{
> +     rmw_spr(SPRN_HID1, HID1_RESET_MASK, 0);
> +}
> +
> +/**
> + * celleb_reset_signals
> + *
> + * Non-rtas version of resetting the debug-bus signals.
> + **/
> +static int celleb_reset_signals(u32 cpu)
> +{
> +     int rc;
> +     rc = passthru_disable(cpu);
> +     if (!rc)
> +             reset_signal_registers(cpu);
> +     return rc;
> +}
> +
> +/**
> + * ppu_selection
> + *
> + * Write the HID1 register to connect the specified PPU signal-group to the
> + * debug-bus.
> + **/
> +static int ppu_selection(struct cell_rtas_arg *signal)
> +{
> +     u64 hid1_enable_word = 0;
> +     u64 hid1_enable_mask = 0;
> +
> +     switch (signal->signal_group) {
> +
> +     case SIG_GROUP_PPU_IU1: /* 2.1 PPU Instruction Unit - Group 1 */
> +             switch (signal->bus_word) {
> +             case BUS_WORD_0:
> +                     hid1_enable_mask = PPU_IU1_WORD0_HID1_EN_MASK;
> +                     hid1_enable_word = PPU_IU1_WORD0_HID1_EN_WORD;
> +                     break;
> +             case BUS_WORD_1:
> +                     hid1_enable_mask = PPU_IU1_WORD1_HID1_EN_MASK;
> +                     hid1_enable_word = PPU_IU1_WORD1_HID1_EN_WORD;
> +                     break;
> +             default:
> +                     PFM_ERR("Invalid bus-word (0x%x) for signal-group %d.",
> +                             signal->bus_word, signal->signal_group);
> +                     return -EINVAL;
> +             }
> +             break;
> +
> +     case SIG_GROUP_PPU_XU:  /* 2.2 PPU Execution Unit */
> +             switch (signal->bus_word) {
> +             case BUS_WORD_0:
> +                     hid1_enable_mask = PPU_XU_WORD0_HID1_EN_MASK;
> +                     hid1_enable_word = PPU_XU_WORD0_HID1_EN_WORD;
> +                     break;
> +             case BUS_WORD_1:
> +                     hid1_enable_mask = PPU_XU_WORD1_HID1_EN_MASK;
> +                     hid1_enable_word = PPU_XU_WORD1_HID1_EN_WORD;
> +                     break;
> +             default:
> +                     PFM_ERR("Invalid bus-word (0x%x) for signal-group %d.",
> +                             signal->bus_word, signal->signal_group);
> +                     return -EINVAL;
> +             }
> +             break;
> +
> +     default:
> +             PFM_ERR("Signal-group %d not implemented.",
> +                     signal->signal_group);
> +             return -EINVAL;
> +     }
> +
> +     rmw_spr(SPRN_HID1, hid1_enable_mask, hid1_enable_word);
> +
> +     return 0;
> +}
> +
> +/**
> + * celleb_activate_signals
> + *
> + * Non-rtas version of activating the debug-bus signals.
> + **/
> +static int celleb_activate_signals(struct cell_rtas_arg *signals,
> +                                int num_signals)
> +{
> +     int i, rc;
> +
> +     for (i = 0; i < num_signals; i++) {
> +             switch (signals[i].signal_group) {
> +
> +             /* 2.x PowerPC Processor Unit (PPU) Signal Selection */
> +             case SIG_GROUP_PPU_IU1:
> +             case SIG_GROUP_PPU_XU:
> +                     rc = ppu_selection(signals + i);
> +                     if (rc)
> +                             return rc;
> +                     break;
> +
> +             default:
> +                     PFM_ERR("Signal-group %d not implemented.",
> +                             signals[i].signal_group);
> +                     return -EINVAL;
> +             }
> +     }
> +
> +     rc = passthru_enable(signals[i].cpu);
> +
> +     return rc;
> +}
> +
> +/**
> + * reset_signals
> + *
> + * Call to the firmware (if available) to reset the debug-bus signals.
> + * Otherwise call the built-in version.
> + **/
> +int reset_signals(u32 cpu)
> +{
> +     int rc;
> +
> +     if (machine_is(celleb))
> +             rc = celleb_reset_signals(cpu);
> +     else
> +             rc = rtas_reset_signals(cpu);
> +
> +     return rc;
> +}
> +
> +/**
> + * activate_signals
> + *
> + * Call to the firmware (if available) to activate the debug-bus signals.
> + * Otherwise call the built-in version.
> + **/
> +int activate_signals(struct cell_rtas_arg *signals, int num_signals)
> +{
> +     int rc;
> +
> +     if (machine_is(celleb))
> +             rc = celleb_activate_signals(signals, num_signals);
> +     else
> +             rc = rtas_activate_signals(signals, num_signals);
> +
> +     return rc;
> +}
> +
> +/**
> + *  pfm_cell_pmc_check
> + *
> + * Verify that we are going to write a valid value to the specified PMC.
> + **/
> +int pfm_cell_pmc_check(struct pfm_context *ctx,
> +                    struct pfm_event_set *set,
> +                    struct pfarg_pmc *req)
> +{
> +     u16 cnum, reg_num = req->reg_num;
> +     s16 signal_group = RTAS_SIGNAL_GROUP(req->reg_value);
> +     u8 bus_word = RTAS_BUS_WORD(req->reg_value);
> +
> +     if (reg_num < NR_CTRS || reg_num >= (NR_CTRS * 2)) {
> +             return -EINVAL;
> +     }
> +
> +     switch (signal_group) {
> +     case SIG_GROUP_PPU_IU1:
> +     case SIG_GROUP_PPU_XU:
> +             if ((bus_word != 0) && (bus_word != 1)) {
> +                     PFM_ERR("Invalid bus word (%d) for signal-group %d",
> +                             bus_word, signal_group);
> +                     return -EINVAL;
> +             }
> +             break;
> +     default:
> +             PFM_ERR("Signal-group %d not implemented.", signal_group);
> +             return -EINVAL;
> +     }
> +
> +     for (cnum = NR_CTRS; cnum < (NR_CTRS * 2); cnum++) {
> +             if (test_bit(cnum, cast_ulp(set->used_pmcs)) &&
> +                 bus_word == RTAS_BUS_WORD(set->pmcs[cnum]) &&
> +                 signal_group != RTAS_SIGNAL_GROUP(set->pmcs[cnum])) {
> +                     PFM_ERR("Impossible signal-group combination: "
> +                             "(%u,%u,%d) (%u,%u,%d)",
> +                             reg_num, bus_word, signal_group, cnum,
> +                             RTAS_BUS_WORD(set->pmcs[cnum]),
> +                             RTAS_SIGNAL_GROUP(set->pmcs[cnum]));
> +                     return  -EBUSY;
> +             }
> +     }
> +
> +     return 0;
> +}
> +
>  /**
>   * write_pm07_event
>   *
> @@ -205,10 +507,10 @@ static void write_pm07_event(int cpu, unsigned int ctr, 
> u64 value)
>       signal.signal_group = signal_number / 100;
>       signal.bit = signal_number % 100;
>  
> -     rc = rtas_activate_signals(&signal, 1);
> +     rc = activate_signals(&signal, 1);
>       if (rc) {
>               PFM_WARN("%s(%d, %u, %lu): Error calling "
> -                      "rtas_activate_signal(): %d\n", __FUNCTION__,
> +                      "activate_signals(): %d\n", __FUNCTION__,
>                        cpu, ctr, (unsigned long)value, rc);
>               /* FIX: Could we change this routine to return an error? */
>       }
> @@ -367,9 +669,9 @@ void pfm_cell_restore_pmcs(struct pfm_event_set *set)
>               num_used++;
>       }
>  
> -     rc = rtas_activate_signals(signals, num_used);
> +     rc = activate_signals(signals, num_used);
>       if (rc) {
> -             PFM_WARN("Error calling rtas_activate_signal(): %d\n", rc);
> +             PFM_WARN("Error calling activate_signal(): %d\n", rc);
>               /* FIX: We will also need this routine to be able to return
>                * an error if Stephane agrees to change pfm_arch_write_pmc
>                * to return an error.
> @@ -397,7 +699,7 @@ static int pfm_cell_unload_context(struct pfm_context 
> *ctx,
>                                  struct task_struct *task)
>  {
>       if (task == current || ctx->flags.system) {
> -             rtas_reset_signals(smp_processor_id());
> +             reset_signals(smp_processor_id());
>       }
>       return 0;
>  }
> @@ -412,7 +714,7 @@ static int pfm_cell_unload_context(struct pfm_context 
> *ctx,
>  int pfm_cell_ctxswout_thread(struct task_struct *task,
>                            struct pfm_context *ctx, struct pfm_event_set *set)
>  {
> -     rtas_reset_signals(smp_processor_id());
> +     reset_signals(smp_processor_id());
>       return 0;
>  }
>  
> @@ -614,8 +916,25 @@ static struct pfm_pmu_config pfm_cell_pmu_conf = {
>       .owner = THIS_MODULE,
>  };
>  
> +/**
> + * pfm_cell_platform_probe
> + *
> + * If we're on a system without the firmware rtas call available, set up the
> + * PMC write-checker for all the pmX_event control registers.
> + **/
> +static void pfm_cell_platform_probe(void)
> +{
> +     if (machine_is(celleb)) {
> +             int cnum;
> +             pfm_cell_pmu_conf.pmc_write_check = pfm_cell_pmc_check;
> +             for (cnum = NR_CTRS; cnum < (NR_CTRS * 2); cnum++)
> +                     pfm_cell_pmc_desc[cnum].type |= PFM_REG_WC;
> +     }
> +}
> +
>  static int __init pfm_cell_pmu_init_module(void)
>  {
> +     pfm_cell_platform_probe();
>       return pfm_pmu_register(&pfm_cell_pmu_conf);
>  }
>  
> _______________________________________________
> perfmon mailing list
> [email protected]
> http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/

-- 

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

Reply via email to