Kevin,

Are you planning on resubmitting the hardware buffer format code?

I think the code could be simplified quite a bit using the information
I gave you in my previous E-mail.

Thanks.

On Wed, Sep 05, 2007 at 09:13:09AM -0500, Kevin Corry wrote:
> Add the Cell hardware-sampling module.
> 
> The Cell PMU provides a hardware buffer that can store up to 1024 128-bit
> samples. There are several possible data formats for each sample, based on
> the type of sampling the user selects. These include several types of counter-
> based sampling modes, a few address tracing modes, and a thermal data mode.
> 
> All of these sampling modes are based on a hardware timer. However, this does
> not fit well into the general Perfmon design for the sampling-format modules,
> which is to collect samples based on counter overflows. Therefore, some of
> the sample collection code is "duplicated" in order to deal with the
> restrictions imposed by the Cell PMU. In order to do this, the
> pfm_mask_monitoring() and pfm_get_new_msg() routines in the Perfmon core code
> had to be exported so this module could call them.
> 
> Signed-off-by: Kevin Corry <[EMAIL PROTECTED]>
> Signed-off-by: Carl Love <[EMAIL PROTECTED]>
> ---
> 
>  arch/powerpc/perfmon/Kconfig                |    9 +
>  arch/powerpc/perfmon/Makefile               |    9 -
>  arch/powerpc/perfmon/perfmon_cell.c         |   51 +++-
>  arch/powerpc/perfmon/perfmon_cell_hw_smpl.c |  392 
> +++++++++++++++++++++++++++
>  arch/powerpc/platforms/cell/pmu.c           |    2 
>  include/asm-powerpc/cell-pmu.h              |    5 
>  include/asm-powerpc/perfmon_cell_hw_smpl.h  |  119 ++++++++
>  include/linux/perfmon.h                     |    3 
>  perfmon/perfmon.c                           |    4 
>  perfmon/perfmon_intr.c                      |    3 
>  10 files changed, 588 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/powerpc/perfmon/Kconfig b/arch/powerpc/perfmon/Kconfig
> index ea8a81a..6ef5968 100644
> --- a/arch/powerpc/perfmon/Kconfig
> +++ b/arch/powerpc/perfmon/Kconfig
> @@ -38,4 +38,13 @@ config PERFMON_CELL
>       Enables support for the Cell hardware performance counters.
>       If unsure, say M.
>  
> +config PERFMON_CELL_HW_SMPL
> +     tristate "Support for Cell hardware counter sampling"
> +     depends on PERFMON_CELL
> +     default n
> +     help
> +     Enables support for the Cell hardware counter sampling modes using
> +     the PMU trace-buffer.
> +     If unsure, say M.
> +
>  endmenu
> diff --git a/arch/powerpc/perfmon/Makefile b/arch/powerpc/perfmon/Makefile
> index b1dfc51..ba75eaa 100644
> --- a/arch/powerpc/perfmon/Makefile
> +++ b/arch/powerpc/perfmon/Makefile
> @@ -1,4 +1,5 @@
> -obj-$(CONFIG_PERFMON)                += perfmon.o
> -obj-$(CONFIG_PERFMON_POWER5) += perfmon_power5.o
> -obj-$(CONFIG_PERFMON_PPC32)  += perfmon_ppc32.o
> -obj-$(CONFIG_PERFMON_CELL)   += perfmon_cell.o
> +obj-$(CONFIG_PERFMON)                        += perfmon.o
> +obj-$(CONFIG_PERFMON_POWER5)         += perfmon_power5.o
> +obj-$(CONFIG_PERFMON_PPC32)          += perfmon_ppc32.o
> +obj-$(CONFIG_PERFMON_CELL)           += perfmon_cell.o
> +obj-$(CONFIG_PERFMON_CELL_HW_SMPL)   += perfmon_cell_hw_smpl.o
> diff --git a/arch/powerpc/perfmon/perfmon_cell.c 
> b/arch/powerpc/perfmon/perfmon_cell.c
> index e0a3976..91c6f75 100644
> --- a/arch/powerpc/perfmon/perfmon_cell.c
> +++ b/arch/powerpc/perfmon/perfmon_cell.c
> @@ -29,6 +29,7 @@
>  #include <asm/io.h>
>  #include <asm/rtas.h>
>  #include "../platforms/cell/cbe_regs.h"
> +#include <asm/perfmon_cell_hw_smpl.h>
>  
>  MODULE_AUTHOR("Kevin Corry <[EMAIL PROTECTED]>, "
>             "Carl Love <[EMAIL PROTECTED]>");
> @@ -76,7 +77,6 @@ static struct pfm_regmap_desc pfm_cell_pmc_desc[] = {
>  };
>  #define PFM_PM_NUM_PMCS      ARRAY_SIZE(pfm_cell_pmc_desc)
>  
> -#define CELL_PMC_PM_STATUS 20
>  /*
>   * Mapping from Perfmon logical data counters to Cell hardware counters.
>   */
> @@ -297,11 +297,26 @@ static void pfm_cell_enable_counters(struct pfm_context 
> *ctx,
>   * pfm_cell_disable_counters
>   *
>   * Just need to turn off the global disable bit in pm_control.
> + *
> + * Also, if we're using the hardware-sampling module, we need to empty the
> + * trace-buffer, since it cannot be restored to its current state when this
> + * event-set is enabled again.
>   **/
>  static void pfm_cell_disable_counters(struct pfm_context *ctx,
>                                     struct pfm_event_set *set)
>  {
> +     struct pfm_smpl_fmt *smpl_fmt = ctx->smpl_fmt;
> +
>       cbe_disable_pm(smp_processor_id());
> +
> +     if (smpl_fmt &&
> +         ctx->state != PFM_CTX_MASKED &&
> +         !strcmp(smpl_fmt->fmt_name, PFM_CELL_HW_SMPL_NAME)) {
> +             ctx->ovfl_arg.ovfl_pmd = PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL;
> +             ctx->ovfl_arg.active_set = ctx->active_set->id;
> +             smpl_fmt->fmt_handler(ctx->smpl_addr,
> +                                   &ctx->ovfl_arg, 0, 0, NULL);
> +     }
>  }
>  
>  /**
> @@ -463,7 +478,32 @@ static void handle_trace_buffer_interrupts(unsigned long 
> iip,
>                                          struct pfm_context *ctx,
>                                          u32 pm_status)
>  {
> -     /* FIX: Currently ignoring trace-buffer interrupts. */
> +     struct pfm_smpl_fmt *smpl_fmt;
> +
> +     if (pm_status & CBE_PM_TRACE_BUFFER_FULL_INTR) {
> +             /* The trace-buffer is full. Get the sampling-buffer address
> +              * and call the handler. Need to lock the context here instead
> +              * of in the handler, because the handler can also be called
> +              * by the pfm_cell_disable_counters() routine, which is called
> +              * with the context already locked.
> +              */
> +             smpl_fmt = ctx->smpl_fmt;
> +
> +             if (smpl_fmt &&
> +                 !strcmp(smpl_fmt->fmt_name, PFM_CELL_HW_SMPL_NAME)) {
> +                     ctx->ovfl_arg.ovfl_pmd = PFM_CELL_HW_SMPL_OVFL_PMD;
> +                     ctx->ovfl_arg.active_set = ctx->active_set->id;
> +                     spin_lock(&ctx->lock);
> +                     smpl_fmt->fmt_handler(ctx->smpl_addr, &ctx->ovfl_arg,
> +                                           iip, 0, regs);
> +                     spin_unlock(&ctx->lock);
> +             }
> +     }
> +
> +     /* Currently the trace buffer underflow and interval timer
> +      * interrupts are ignored.
> +      */
> +
>       return;
>  }
>  
> @@ -522,6 +562,13 @@ static void pfm_cell_irq_handler(struct pt_regs *regs, 
> struct pfm_context *ctx)
>               handle_trace_buffer_interrupts(instruction_pointer(regs),
>                                              regs, ctx, last_read_pm_status);
>  
> +     /* If the hardware-sampling module masked monitoring for this context,
> +      * don't re-enable the PMU.
> +      */
> +     if (ctx->state == PFM_CTX_MASKED) {
> +             return;
> +     }
> +
>       /* The interrupt settings is the value written to the pm_status
>        * register. It is saved in the context when the register is
>        * written.
> diff --git a/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c 
> b/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c
> new file mode 100644
> index 0000000..7a47797
> --- /dev/null
> +++ b/arch/powerpc/perfmon/perfmon_cell_hw_smpl.c
> @@ -0,0 +1,392 @@
> +/*
> + * Copyright IBM Corp 2007
> + *
> + * Contributed by Carl Love <[EMAIL PROTECTED]>
> + * and Kevin Corry <[EMAIL PROTECTED]>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of version 2 of the GNU General Public
> + * License as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> + * 02111-1307 USA
> + *
> + *
> + * This file implements the IBM Cell PMU hardware-sampling module.
> + */
> +#include <linux/module.h>
> +#include <linux/perfmon.h>
> +#include <asm/cell-pmu.h>
> +#include <asm/perfmon_cell_hw_smpl.h>
> +
> +MODULE_AUTHOR("Carl Love <[EMAIL PROTECTED]>, "
> +           "Kevin Corry <[EMAIL PROTECTED]>");
> +MODULE_DESCRIPTION("Perfmon2 CELL hardware sampling format");
> +MODULE_LICENSE("GPL");
> +
> +/**
> + * pfm_cell_hw_smpl_validate
> + *
> + * Validate the arguments passed from user-space for creating the
> + * sampling-buffer. The buffer must be large enough to hold the
> + * sampling-buffer header and at least one copy of the trace-buffer.
> + **/
> +static int pfm_cell_hw_smpl_validate(u32 flags, u16 npmds, void *user_arg)
> +{
> +     struct pfm_cell_hw_smpl_arg *smpl_arg = user_arg;
> +
> +     if (!smpl_arg) {
> +             PFM_ERR("No argument passed.");
> +             return -EINVAL;
> +     }
> +
> +     if (smpl_arg->buf_size < PFM_CELL_HW_SMPL_MIN_BUF_SIZE) {
> +             PFM_ERR("Specified buffer size (%lu) too small. "
> +                     "Min size is %lu bytes.",
> +                     smpl_arg->buf_size, PFM_CELL_HW_SMPL_MIN_BUF_SIZE);
> +             return -EINVAL;
> +     }
> +
> +     return 0;
> +}
> +
> +/**
> + * pfm_cell_hw_smpl_get_size
> + *
> + * Tell the Perfmon2 core how large a buffer we need to have allocated, and
> + * it will do the allocation for us. The size of the buffer has already been
> + * validated.
> + **/
> +static int pfm_cell_hw_smpl_get_size(unsigned int flags,
> +                                  void *user_arg, size_t *size)
> +{
> +     struct pfm_cell_hw_smpl_arg *smpl_arg = user_arg;
> +     *size = smpl_arg->buf_size;
> +     return 0;
> +}
> +
> +/**
> + * pfm_cell_hw_smpl_init
> + *
> + * Initialize the start of the sampling-buffer with a header structure.
> + * The buffer has already been allocated by the Perfmon2 core.
> + **/
> +static int pfm_cell_hw_smpl_init(struct pfm_context *ctx, void *smpl_buf,
> +                              u32 flags, u16 npmds, void *user_arg)
> +{
> +     struct pfm_cell_hw_smpl_hdr *smpl_hdr = smpl_buf;
> +     struct pfm_cell_hw_smpl_arg *smpl_arg = user_arg;
> +
> +     smpl_hdr->count = 0;
> +     smpl_hdr->cur_offset = sizeof(*smpl_hdr);
> +     smpl_hdr->overflows = 0;
> +     smpl_hdr->buf_size = smpl_arg->buf_size;
> +     smpl_hdr->version = PFM_CELL_HW_SMPL_VERSION;
> +     smpl_hdr->buf_flags = smpl_arg->buf_flags;
> +
> +     return 0;
> +}
> +
> +/**
> + * pfm_cell_hw_smpl_add_msg
> + *
> + * Add a "sampling-buffer-full" message to the context. A user-space process
> + * can then read() from the file-descriptor to get a copy of the message.
> + **/
> +static int pfm_cell_hw_smpl_add_msg(struct pfm_context *ctx)
> +{
> +     union pfarg_msg *msg;
> +
> +     if (ctx->flags.no_msg) {
> +             /* User-space won't be reading any messages. */
> +             return 0;
> +     }
> +
> +     msg = pfm_get_new_msg(ctx);
> +     if (msg == NULL) {
> +             /* The message queue is full. The user must have called
> +              * pfm_restart(), but didn't extract any messages.
> +              */
> +             PFM_ERR("No notification messages available.");
> +             return -EBUSY;
> +     }
> +
> +     msg->type = PFM_MSG_CELL_HW_SMPL_BUF_FULL;
> +
> +     return 0;
> +}
> +
> +/**
> + * init_entry_header
> + **/
> +static struct pfm_cell_hw_smpl_entry_hdr *
> +init_entry_header(struct pfm_cell_hw_smpl_hdr *buf_hdr,
> +               struct pfm_event_set *set)
> +{
> +     struct pfm_cell_hw_smpl_entry_hdr *ent_hdr;
> +
> +     ent_hdr = (void *)buf_hdr + buf_hdr->cur_offset;
> +     ent_hdr->pid = current->pid;
> +     ent_hdr->tgid = current->tgid;
> +     ent_hdr->cpu = smp_processor_id();
> +     ent_hdr->set = set->id;
> +     ent_hdr->num_samples = 0;
> +     ent_hdr->entry_num = buf_hdr->count;
> +     ent_hdr->pm_interval = 0;
> +
> +     return ent_hdr;
> +}
> +
> +/**
> + * pmds_long_reset
> + *
> + * Reset all in-use PMDs to their "long" reset value. We write to the 
> hardware
> + * counters, so this should be called before "saving" the counters to the
> + * event-set copy.
> + **/
> +static inline void pmds_long_reset(struct pfm_event_set *set, int cpu)
> +{
> +     int i;
> +     for (i = 0; i < NR_CTRS; i++)
> +             if (test_bit(i, cast_ulp(&set->used_pmds)))
> +                     cbe_write_ctr(cpu, i, set->pmds[i].long_reset);
> +}
> +
> +/**
> + * read_trace_buffer
> + *
> + * Read at most 1024 samples from the trace-buffer. Note, samples could
> + * be added to the trace-buffer while it is being read. However, we only
> + * made sure we had space for up to 1024 samples.
> + **/
> +static void read_trace_buffer(struct pfm_cell_hw_smpl_entry_hdr *ent_hdr,
> +                           u64 **trace_buffer_sample)
> +{
> +     int cpu = smp_processor_id();
> +     u32 trace_addr;
> +
> +     *trace_buffer_sample = (u64 *)(ent_hdr + 1);
> +     trace_addr = cbe_read_pm(cpu, trace_address);
> +     while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY) &&
> +            ent_hdr->num_samples < CBE_PM_TRACE_BUF_MAX_COUNT) {
> +             cbe_read_trace_buffer(cpu, *trace_buffer_sample);
> +             *trace_buffer_sample += 2;
> +             ent_hdr->num_samples++;
> +             trace_addr = cbe_read_pm(cpu, trace_address);
> +     }
> +}
> +
> +/**
> + * read_partial_sample
> + *
> + * We are disabling this event-set, and are in the middle of a sampling
> + * interval. When this event set gets re-enabled, the pm_interval will get
> + * reset to its initial value, so we'll lose the counter values from this
> + * incomplete sample. In "count" sampling-mode, we should be able to prevent
> + * this data loss by recording a "partial" sample from the actual counters.
> + * In occurrence and threshold sampling, however, the partial data is not
> + * available, so we'll have to settle for an "empty" sample. In any case,
> + * fill in the current pm_interval value so user-space will know that the 
> last
> + * sample in this entry is partial or empty, and so they will be able to
> + * calculate the percentage-complete for that sample.
> + **/
> +static void read_partial_sample(struct pfm_event_set *set,
> +                             struct pfm_cell_hw_smpl_entry_hdr *ent_hdr,
> +                             u64 **trace_buffer_sample)
> +{
> +     u32 pm_control = set->pmcs[CELL_PMC_PM_CONTROL];
> +     u32 *partial_sample = (u32 *)*trace_buffer_sample;
> +     int i, cpu = smp_processor_id();
> +
> +     if (CBE_PM_TRACE_MODE_GET(pm_control) == CBE_PM_TRACE_MODE_COUNT) {
> +             for (i = 0; i < NR_PHYS_CTRS; i++) {
> +                     partial_sample[i] = cbe_read_phys_ctr(cpu, i);
> +             }
> +     } else {
> +             memset(partial_sample, 0,
> +                    NR_PHYS_CTRS * sizeof(*partial_sample));
> +     }
> +
> +     ent_hdr->pm_interval = cbe_read_pm(cpu, pm_interval);
> +     ent_hdr->num_samples++;
> +     *trace_buffer_sample += 2;
> +
> +     /* In all cases, reset the in-use PMDs to their "long" reset value
> +      * since we've effectively invalidated the data in this interval.
> +      */
> +     pmds_long_reset(set, cpu);
> +}
> +
> +/**
> + * handle_full_buffer
> + **/
> +static int handle_full_buffer(struct pfm_cell_hw_smpl_hdr *buf_hdr,
> +                           struct pfm_context *ctx,
> +                           struct pfm_event_set *set)
> +{
> +     int cpu = smp_processor_id();
> +
> +     /* Increment the number of sampling-buffer overflows. This
> +      * is important for detecting duplicate sets of samples.
> +      */
> +     buf_hdr->overflows++;
> +
> +     /* Reset the PMDs to their "long-reset" value. The hardware counters
> +      * will be saved during the mask-monitoring call, and will be
> +      * restored later when we are unmasked, so we need to be sure the
> +      * counters are set to their correct initial values.
> +      */
> +     pmds_long_reset(set, cpu);
> +
> +     /* Reset the interval timer so we start a whole
> +      * new interval when we get restarted.
> +      */
> +     cbe_write_pm(cpu, pm_interval, set->pmcs[CELL_PMC_PM_INTERVAL]);
> +
> +     /* Mask monitoring until a pfm_restart() occurs. */
> +     pfm_mask_monitoring(ctx, set);
> +     ctx->state = PFM_CTX_MASKED;
> +     ctx->flags.can_restart = 1;
> +
> +     /* Add a message to the context's message queue. */
> +     pfm_cell_hw_smpl_add_msg(ctx);
> +
> +     return -ENOBUFS;
> +}
> +
> +/**
> + * pfm_cell_hw_smpl_handler
> + *
> + * Create a new entry-header in the sampling-buffer and copy the current
> + * contents of the trace-buffer into the sampling-buffer.
> + **/
> +static int pfm_cell_hw_smpl_handler(void *smpl_buf,
> +                                 struct pfm_ovfl_arg *ovfl_arg,
> +                                 unsigned long ip,
> +                                 u64 tstamp,
> +                                 void *data)
> +{
> +     struct pfm_cell_hw_smpl_hdr *buf_hdr = smpl_buf;
> +     struct pfm_cell_hw_smpl_entry_hdr *ent_hdr;
> +     struct pfm_event_set *set;
> +     struct pfm_context *ctx;
> +     u64 *trace_buffer_sample;
> +     u64 free_bytes;
> +
> +     /* If this handler was called due to an actual PMD overflowing, do
> +      * nothing. Only store the contents of the trace-buffer if the trace-
> +      * buffer overflowed or if we're disabling an event-set (during a
> +      * process context-switch or an event-set switch).
> +      */
> +     if (!(ovfl_arg->ovfl_pmd == PFM_CELL_HW_SMPL_OVFL_PMD ||
> +           ovfl_arg->ovfl_pmd == PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL))
> +             return 0;
> +
> +     ctx = __get_cpu_var(pmu_ctx);
> +     set = ctx->active_set;
> +
> +     /* Check if the sampling-buffer is full. This should never happen,
> +      * since we check for a full buffer after adding the new entry.
> +      */
> +     free_bytes = buf_hdr->buf_size - buf_hdr->cur_offset;
> +     if (free_bytes < PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE)
> +             return handle_full_buffer(buf_hdr, ctx, set);
> +
> +     ent_hdr = init_entry_header(buf_hdr, set);
> +
> +     read_trace_buffer(ent_hdr, &trace_buffer_sample);
> +
> +     if (ovfl_arg->ovfl_pmd == PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL &&
> +         ent_hdr->num_samples < CBE_PM_TRACE_BUF_MAX_COUNT) {
> +             read_partial_sample(set, ent_hdr, &trace_buffer_sample);
> +     }
> +
> +     /* Update the sampling-buffer header for the next entry. Since the
> +      * hw_smpl_hdr and hw_smpl_entry_hdr structures are both padded to
> +      * 128-bits, and each trace-buffer sample is 128-bits, we know that
> +      * every buffer entry will start on a 128-bit boundary.
> +      */
> +     if (ent_hdr->num_samples) {
> +             buf_hdr->cur_offset = (void *)trace_buffer_sample -
> +                                   (void *)buf_hdr;
> +             buf_hdr->count++;
> +     }
> +
> +     /* Check the available size in the buffer again so we won't lose the
> +      * next sample entry.
> +      */
> +     free_bytes = buf_hdr->buf_size - buf_hdr->cur_offset;
> +     if (free_bytes < PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE)
> +             return handle_full_buffer(buf_hdr, ctx, set);
> +
> +     return 0;
> +}
> +
> +/**
> + * pfm_cell_hw_smpl_restart
> + *
> + * Reinitialize the sampling-buffer header, effectively deleting all entries
> + * previously stored in the sampling-buffer.
> + *
> + * FIX: What is the "is_active" argument for? It's not used by any of the
> + *      other sampling modules.
> + **/
> +static int pfm_cell_hw_smpl_restart(int is_active,
> +                                 u32 *ovfl_ctrl,
> +                                 void *smpl_buf)
> +{
> +     struct pfm_cell_hw_smpl_hdr *buf_hdr = smpl_buf;
> +
> +     buf_hdr->count = 0;
> +     buf_hdr->cur_offset = sizeof(*buf_hdr);
> +     buf_hdr->overflows = 0;
> +
> +     return 0;
> +}
> +
> +/**
> + * pfm_cell_hw_smpl_exit
> + **/
> +static int pfm_cell_hw_smpl_exit(void *smpl_buf)
> +{
> +     return 0;
> +}
> +
> +/**
> + * cell_hw_smpl_fmt
> + *
> + * Structure to describe the Cell hardware-sampling module to the Perfmon2 
> core.
> + **/
> +static struct pfm_smpl_fmt cell_hw_smpl_fmt = {
> +     .fmt_name = PFM_CELL_HW_SMPL_NAME,
> +     .fmt_arg_size = sizeof(struct pfm_cell_hw_smpl_arg),
> +     .fmt_flags = PFM_FMT_BUILTIN_FLAG,
> +     .fmt_version = PFM_CELL_HW_SMPL_VERSION,
> +     .fmt_validate = pfm_cell_hw_smpl_validate,
> +     .fmt_getsize = pfm_cell_hw_smpl_get_size,
> +     .fmt_init = pfm_cell_hw_smpl_init,
> +     .fmt_handler = pfm_cell_hw_smpl_handler,
> +     .fmt_restart = pfm_cell_hw_smpl_restart,
> +     .fmt_exit = pfm_cell_hw_smpl_exit,
> +     .owner = THIS_MODULE,
> +};
> +
> +static int __init pfm_cell_hw_smpl_init_module(void)
> +{
> +     return pfm_fmt_register(&cell_hw_smpl_fmt);
> +}
> +
> +static void __exit pfm_cell_hw_smpl_exit_module(void)
> +{
> +     pfm_fmt_unregister(&cell_hw_smpl_fmt);
> +}
> +
> +module_init(pfm_cell_hw_smpl_init_module);
> +module_exit(pfm_cell_hw_smpl_exit_module);
> diff --git a/arch/powerpc/platforms/cell/pmu.c 
> b/arch/powerpc/platforms/cell/pmu.c
> index 66ca4b5..e518af7 100644
> --- a/arch/powerpc/platforms/cell/pmu.c
> +++ b/arch/powerpc/platforms/cell/pmu.c
> @@ -213,7 +213,7 @@ u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
>               break;
>  
>       case pm_interval:
> -             READ_SHADOW_REG(val, pm_interval);
> +             READ_MMIO_UPPER32(val, pm_interval);
>               break;
>  
>       case pm_start_stop:
> diff --git a/include/asm-powerpc/cell-pmu.h b/include/asm-powerpc/cell-pmu.h
> index 981db26..aa7416d 100644
> --- a/include/asm-powerpc/cell-pmu.h
> +++ b/include/asm-powerpc/cell-pmu.h
> @@ -41,6 +41,11 @@
>  #define CBE_PM_FREEZE_ALL_CTRS             0x00100000
>  #define CBE_PM_ENABLE_EXT_TRACE            0x00008000
>  
> +#define CBE_PM_TRACE_MODE_NONE             0
> +#define CBE_PM_TRACE_MODE_COUNT            1
> +#define CBE_PM_TRACE_MODE_OCCURRENCE       2
> +#define CBE_PM_TRACE_MODE_THRESHOLD        3
> +
>  /* Macros for the trace_address register. */
>  #define CBE_PM_TRACE_BUF_FULL              0x00000800
>  #define CBE_PM_TRACE_BUF_EMPTY             0x00000400
> diff --git a/include/asm-powerpc/perfmon_cell_hw_smpl.h 
> b/include/asm-powerpc/perfmon_cell_hw_smpl.h
> new file mode 100644
> index 0000000..4927438
> --- /dev/null
> +++ b/include/asm-powerpc/perfmon_cell_hw_smpl.h
> @@ -0,0 +1,119 @@
> +/*
> + * Copyright IBM Corp 2007
> + *
> + * Contributed by Carl Love <[EMAIL PROTECTED]>
> + * and Kevin Corry <[EMAIL PROTECTED]>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of version 2 of the GNU General Public
> + * License as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
> + * 02111-1307 USA
> + */
> +#ifndef __ASM_POWERPC_PERFMON_CELL_HW_SMPL_H__
> +#define __ASM_POWERPC_PERFMON_CELL_HW_SMPL_H__
> +
> +/**
> + * struct pfm_cell_hw_smpl_arg
> + *
> + * @buf_size: Desired size of full sampling-buffer (in bytes).
> + * @buf_flags: Sampling-buffer-specific flags.
> + * @reserved1: Pad to 128-bit boundary.
> + *
> + * Format specific parameters (passed at context creation).
> + **/
> +struct pfm_cell_hw_smpl_arg {
> +     __u64 buf_size;
> +     __u32 buf_flags;
> +     __u32 reserved1;
> +};
> +
> +/**
> + * struct pfm_cell_hw_smpl_hdr
> + *
> + * @count: Number of valid pfm_cell_hw_smpl_entry_hdr's in the 
> sampling-buffer.
> + * @cur_offset: Offset (in bytes) from the top of the sampling-buffer to the
> + *              next available space for a sampling-buffer entry.
> + * @overflows: Number of times the sampling-buffer has filled up.
> + * @buf_size: Total bytes in the sampling-buffer.
> + * @version: Sampling module version.
> + * @buf_flags: Copy of buf_flags from pfm_cell_hw_smpl_arg.
> + * @reserved1: Pad to 128-bit boundary.
> + *
> + * This header is at the beginning of the sampling-buffer returned to the 
> user.
> + * It is directly followed by the first entry header.
> + **/
> +struct pfm_cell_hw_smpl_hdr {
> +     __u64 count;
> +     __u64 cur_offset;
> +     __u64 overflows;
> +     __u64 buf_size;
> +     __u32 version;
> +     __u32 buf_flags;
> +     __u64 reserved1;
> +};
> +
> +/**
> + * struct pfm_cell_hw_smpl_entry_hdr
> + *
> + * @pid: Thread ID.
> + * @tgid: Thread group ID. For NPTL, this is getpid().
> + * @cpu: CPU on which the overflow occurred.
> + * @set: Event-set that was active when the overflow occurred.
> + * @num_samples: Number of 128-bit trace-buffer samples in this entry.
> + * @entry_num: Sequence number of sampling-buffer entries.
> + * @pm_interval: If the last sample in this entry is for a partial time
> + *             interval, this is the value of pm_interval when the partial
> + *             sample was recorded. If the value is zero, there is no partial
> + *             sample at the end of the entry.
> + * @reserved1: Pad to 128-bit boundary.
> + *
> + * The header for each data entry in the sampling-buffer. The entry header
> + * is immediately followed by the contents of the trace-buffer. Each sample 
> in
> + * the trace-buffer is 128 bits wide. The entry header specifies the number
> + * of 128-bit trace-buffer samples that follow the header.
> + **/
> +struct pfm_cell_hw_smpl_entry_hdr {
> +     __u32 pid;
> +     __u32 tgid;
> +     __u32 cpu;
> +     __u32 set;
> +     __u32 num_samples;
> +     __u32 entry_num;
> +     __u32 pm_interval;
> +     __u32 reserved1;
> +};
> +
> +/* The max size of each sampling-buffer entry is the size of the entry header
> + * plus the full size of the trace-buffer.
> + */
> +#define PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE      \
> +                     (sizeof(struct pfm_cell_hw_smpl_entry_hdr) + \
> +                      2 * sizeof(u64) * CBE_PM_TRACE_BUF_MAX_COUNT)
> +
> +/* The sampling-buffer must be at least as large as the sampling-buffer 
> header
> + * and the max size of one sampling-buffer entry.
> + */
> +#define PFM_CELL_HW_SMPL_MIN_BUF_SIZE (sizeof(struct pfm_cell_hw_smpl_hdr) + 
> \
> +                                    PFM_CELL_HW_SMPL_MAX_ENTRY_SIZE)
> +
> +#define PFM_CELL_HW_SMPL_VERSION             1
> +#define PFM_CELL_HW_SMPL_NAME                        "perfmon_cell_hw_smpl"
> +#define PFM_CELL_HW_SMPL_OVFL_PMD            (PFM_MAX_PMDS + 1)
> +#define PFM_CELL_HW_SMPL_OVFL_PMD_PARTIAL    (PFM_MAX_PMDS + 2)
> +#define PFM_MSG_CELL_HW_SMPL_BUF_FULL                99
> +
> +/* Values are indexes into pfm_cell_pmc_desc[] array. */
> +#define CELL_PMC_PM_STATUS                   20
> +#define CELL_PMC_PM_CONTROL                  21
> +#define CELL_PMC_PM_INTERVAL                 22
> +
> +#endif /* __ASM_POWERPC_PERFMON_CELL_HW_SMPL_H__ */
> diff --git a/include/linux/perfmon.h b/include/linux/perfmon.h
> index 631cfca..66f0a44 100644
> --- a/include/linux/perfmon.h
> +++ b/include/linux/perfmon.h
> @@ -593,10 +593,13 @@ void pfm_switch_sets(struct pfm_context *ctx,
>                   int reset_mode,
>                   int no_restart);
>  
> +union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx);
>  void pfm_save_pmds(struct pfm_context *ctx, struct pfm_event_set *set);
>  int pfm_ovfl_notify_user(struct pfm_context *ctx,
>                       struct pfm_event_set *set,
>                       unsigned long ip);
> +void pfm_mask_monitoring(struct pfm_context *ctx,
> +                      struct pfm_event_set *set);
>  
>  int pfm_init_fs(void);
>  
> diff --git a/perfmon/perfmon.c b/perfmon/perfmon.c
> index 6d1b56e..eb7648c 100644
> --- a/perfmon/perfmon.c
> +++ b/perfmon/perfmon.c
> @@ -58,6 +58,7 @@ DEFINE_PER_CPU(struct task_struct *, pmu_owner);
>  DEFINE_PER_CPU(struct pfm_context  *, pmu_ctx);
>  DEFINE_PER_CPU(u64, pmu_activation_number);
>  DEFINE_PER_CPU(struct pfm_stats, pfm_stats);
> +EXPORT_PER_CPU_SYMBOL(pmu_ctx);
>  
>  #define PFM_INVALID_ACTIVATION       ((u64)~0)
>  
> @@ -74,7 +75,7 @@ int perfmon_disabled;       /* >0 if perfmon is disabled */
>   * get a new message slot from the queue. If the queue is full NULL
>   * is returned and monitoring stops.
>   */
> -static union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx)
> +union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx)
>  {
>       int next;
>  
> @@ -95,6 +96,7 @@ static union pfarg_msg *pfm_get_new_msg(struct pfm_context 
> *ctx)
>  
>       return ctx->msgq+next;
>  }
> +EXPORT_SYMBOL(pfm_get_new_msg);
>  
>  void pfm_context_free(struct pfm_context *ctx)
>  {
> diff --git a/perfmon/perfmon_intr.c b/perfmon/perfmon_intr.c
> index ba23be5..f9b7cf9 100644
> --- a/perfmon/perfmon_intr.c
> +++ b/perfmon/perfmon_intr.c
> @@ -40,7 +40,7 @@
>  #include <linux/module.h>
>  #include <linux/random.h>
>  
> -static inline void pfm_mask_monitoring(struct pfm_context *ctx,
> +inline void pfm_mask_monitoring(struct pfm_context *ctx,
>                                      struct pfm_event_set *set)
>  {
>       u64 now;
> @@ -63,6 +63,7 @@ static inline void pfm_mask_monitoring(struct pfm_context 
> *ctx,
>        */
>       set->duration += now - set->duration_start;
>  }
> +EXPORT_SYMBOL(pfm_mask_monitoring);
>  
>  /*
>   * main overflow processing routine.
> _______________________________________________
> 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