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/