Hi Kevin,

Thank you for a lot of comments and modification of our code.
We are checking your patches. It seems to be good so far.
After we finish to check the code and if it works, I will tell you.
(It may be the beginning of next week. Tokyo is struck by a typhoon now.)

Thanks,

-- Takaki Azuma

> -----Original Message-----
> From: [EMAIL PROTECTED] 
> [mailto:[EMAIL PROTECTED] On Behalf Of Kevin Corry
> Sent: Wednesday, September 05, 2007 11:16 PM
> To: [EMAIL PROTECTED]
> Subject: [perfmon] [PATCH] 7/7: Non-RTAS Cell signal routing
> 
> 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/
> 

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

Reply via email to