From: Viresh K. <vir...@li...> - 2021-01-14 12:01:56
|
The previous commit already disabled building oprofile, lets remove the oprofile directory now. Suggested-by: Christoph Hellwig <hc...@in...> Suggested-by: Linus Torvalds <tor...@li...> Signed-off-by: Viresh Kumar <vir...@li...> --- arch/powerpc/oprofile/Makefile | 19 - arch/powerpc/oprofile/backtrace.c | 120 -- arch/powerpc/oprofile/cell/pr_util.h | 110 -- arch/powerpc/oprofile/cell/spu_profiler.c | 248 --- arch/powerpc/oprofile/cell/spu_task_sync.c | 657 -------- arch/powerpc/oprofile/cell/vma_map.c | 279 ---- arch/powerpc/oprofile/common.c | 243 --- arch/powerpc/oprofile/op_model_7450.c | 207 --- arch/powerpc/oprofile/op_model_cell.c | 1709 -------------------- arch/powerpc/oprofile/op_model_fsl_emb.c | 380 ----- arch/powerpc/oprofile/op_model_pa6t.c | 227 --- arch/powerpc/oprofile/op_model_power4.c | 438 ----- 12 files changed, 4637 deletions(-) delete mode 100644 arch/powerpc/oprofile/Makefile delete mode 100644 arch/powerpc/oprofile/backtrace.c delete mode 100644 arch/powerpc/oprofile/cell/pr_util.h delete mode 100644 arch/powerpc/oprofile/cell/spu_profiler.c delete mode 100644 arch/powerpc/oprofile/cell/spu_task_sync.c delete mode 100644 arch/powerpc/oprofile/cell/vma_map.c delete mode 100644 arch/powerpc/oprofile/common.c delete mode 100644 arch/powerpc/oprofile/op_model_7450.c delete mode 100644 arch/powerpc/oprofile/op_model_cell.c delete mode 100644 arch/powerpc/oprofile/op_model_fsl_emb.c delete mode 100644 arch/powerpc/oprofile/op_model_pa6t.c delete mode 100644 arch/powerpc/oprofile/op_model_power4.c diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile deleted file mode 100644 index bb2d94c8cbe6..000000000000 --- a/arch/powerpc/oprofile/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC) - -obj-$(CONFIG_OPROFILE) += oprofile.o - -DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ - oprof.o cpu_buffer.o buffer_sync.o \ - event_buffer.o oprofile_files.o \ - oprofilefs.o oprofile_stats.o \ - timer_int.o ) - -oprofile-y := $(DRIVER_OBJS) common.o backtrace.o -oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \ - cell/spu_profiler.o cell/vma_map.o \ - cell/spu_task_sync.o -oprofile-$(CONFIG_PPC_BOOK3S_64) += op_model_power4.o op_model_pa6t.o -oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o -oprofile-$(CONFIG_PPC_BOOK3S_32) += op_model_7450.o diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c deleted file mode 100644 index 9db7ada79d10..000000000000 --- a/arch/powerpc/oprofile/backtrace.c +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** - * Copyright (C) 2005 Brian Rogan <bc...@co...>, IBM - * -**/ - -#include <linux/time.h> -#include <linux/oprofile.h> -#include <linux/sched.h> -#include <asm/processor.h> -#include <linux/uaccess.h> -#include <linux/compat.h> -#include <asm/oprofile_impl.h> - -#define STACK_SP(STACK) *(STACK) - -#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2) -#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1) - -#ifdef CONFIG_PPC64 -#define STACK_LR(STACK) STACK_LR64(STACK) -#else -#define STACK_LR(STACK) STACK_LR32(STACK) -#endif - -static unsigned int user_getsp32(unsigned int sp, int is_first) -{ - unsigned int stack_frame[2]; - void __user *p = compat_ptr(sp); - - /* - * The most likely reason for this is that we returned -EFAULT, - * which means that we've done all that we can do from - * interrupt context. - */ - if (copy_from_user_nofault(stack_frame, (void __user *)p, - sizeof(stack_frame))) - return 0; - - if (!is_first) - oprofile_add_trace(STACK_LR32(stack_frame)); - - /* - * We do not enforce increasing stack addresses here because - * we may transition to a different stack, eg a signal handler. - */ - return STACK_SP(stack_frame); -} - -#ifdef CONFIG_PPC64 -static unsigned long user_getsp64(unsigned long sp, int is_first) -{ - unsigned long stack_frame[3]; - - if (copy_from_user_nofault(stack_frame, (void __user *)sp, - sizeof(stack_frame))) - return 0; - - if (!is_first) - oprofile_add_trace(STACK_LR64(stack_frame)); - - return STACK_SP(stack_frame); -} -#endif - -static unsigned long kernel_getsp(unsigned long sp, int is_first) -{ - unsigned long *stack_frame = (unsigned long *)sp; - - if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) - return 0; - - if (!is_first) - oprofile_add_trace(STACK_LR(stack_frame)); - - /* - * We do not enforce increasing stack addresses here because - * we might be transitioning from an interrupt stack to a kernel - * stack. validate_sp() is designed to understand this, so just - * use it. - */ - return STACK_SP(stack_frame); -} - -void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth) -{ - unsigned long sp = regs->gpr[1]; - int first_frame = 1; - - /* We ditch the top stackframe so need to loop through an extra time */ - depth += 1; - - if (!user_mode(regs)) { - while (depth--) { - sp = kernel_getsp(sp, first_frame); - if (!sp) - break; - first_frame = 0; - } - } else { -#ifdef CONFIG_PPC64 - if (!is_32bit_task()) { - while (depth--) { - sp = user_getsp64(sp, first_frame); - if (!sp) - break; - first_frame = 0; - } - return; - } -#endif - - while (depth--) { - sp = user_getsp32(sp, first_frame); - if (!sp) - break; - first_frame = 0; - } - } -} diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h deleted file mode 100644 index e198efa9113a..000000000000 --- a/arch/powerpc/oprofile/cell/pr_util.h +++ /dev/null @@ -1,110 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - /* - * Cell Broadband Engine OProfile Support - * - * (C) Copyright IBM Corporation 2006 - * - * Author: Maynard Johnson <may...@us...> - */ - -#ifndef PR_UTIL_H -#define PR_UTIL_H - -#include <linux/cpumask.h> -#include <linux/oprofile.h> -#include <asm/cell-pmu.h> -#include <asm/cell-regs.h> -#include <asm/spu.h> - -/* Defines used for sync_start */ -#define SKIP_GENERIC_SYNC 0 -#define SYNC_START_ERROR -1 -#define DO_GENERIC_SYNC 1 -#define SPUS_PER_NODE 8 -#define DEFAULT_TIMER_EXPIRE (HZ / 10) - -extern struct delayed_work spu_work; -extern int spu_prof_running; - -#define TRACE_ARRAY_SIZE 1024 - -extern spinlock_t oprof_spu_smpl_arry_lck; - -struct spu_overlay_info { /* map of sections within an SPU overlay */ - unsigned int vma; /* SPU virtual memory address from elf */ - unsigned int size; /* size of section from elf */ - unsigned int offset; /* offset of section into elf file */ - unsigned int buf; -}; - -struct vma_to_fileoffset_map { /* map of sections within an SPU program */ - struct vma_to_fileoffset_map *next; /* list pointer */ - unsigned int vma; /* SPU virtual memory address from elf */ - unsigned int size; /* size of section from elf */ - unsigned int offset; /* offset of section into elf file */ - unsigned int guard_ptr; - unsigned int guard_val; - /* - * The guard pointer is an entry in the _ovly_buf_table, - * computed using ovly.buf as the index into the table. Since - * ovly.buf values begin at '1' to reference the first (or 0th) - * entry in the _ovly_buf_table, the computation subtracts 1 - * from ovly.buf. - * The guard value is stored in the _ovly_buf_table entry and - * is an index (starting at 1) back to the _ovly_table entry - * that is pointing at this _ovly_buf_table entry. So, for - * example, for an overlay scenario with one overlay segment - * and two overlay sections: - * - Section 1 points to the first entry of the - * _ovly_buf_table, which contains a guard value - * of '1', referencing the first (index=0) entry of - * _ovly_table. - * - Section 2 points to the second entry of the - * _ovly_buf_table, which contains a guard value - * of '2', referencing the second (index=1) entry of - * _ovly_table. - */ - -}; - -struct spu_buffer { - int last_guard_val; - int ctx_sw_seen; - unsigned long *buff; - unsigned int head, tail; -}; - - -/* The three functions below are for maintaining and accessing - * the vma-to-fileoffset map. - */ -struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu, - unsigned long objectid); -unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map, - unsigned int vma, const struct spu *aSpu, - int *grd_val); -void vma_map_free(struct vma_to_fileoffset_map *map); - -/* - * Entry point for SPU profiling. - * cycles_reset is the SPU_CYCLES count value specified by the user. - */ -int start_spu_profiling_cycles(unsigned int cycles_reset); -void start_spu_profiling_events(void); - -void stop_spu_profiling_cycles(void); -void stop_spu_profiling_events(void); - -/* add the necessary profiling hooks */ -int spu_sync_start(void); - -/* remove the hooks */ -int spu_sync_stop(void); - -/* Record SPU program counter samples to the oprofile event buffer. */ -void spu_sync_buffer(int spu_num, unsigned int *samples, - int num_samples); - -void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset); - -#endif /* PR_UTIL_H */ diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c deleted file mode 100644 index cdf883445a9f..000000000000 --- a/arch/powerpc/oprofile/cell/spu_profiler.c +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Cell Broadband Engine OProfile Support - * - * (C) Copyright IBM Corporation 2006 - * - * Authors: Maynard Johnson <may...@us...> - * Carl Love <ca...@us...> - */ - -#include <linux/hrtimer.h> -#include <linux/smp.h> -#include <linux/slab.h> -#include <asm/cell-pmu.h> -#include <asm/time.h> -#include "pr_util.h" - -#define SCALE_SHIFT 14 - -static u32 *samples; - -/* spu_prof_running is a flag used to indicate if spu profiling is enabled - * or not. It is set by the routines start_spu_profiling_cycles() and - * start_spu_profiling_events(). The flag is cleared by the routines - * stop_spu_profiling_cycles() and stop_spu_profiling_events(). These - * routines are called via global_start() and global_stop() which are called in - * op_powerpc_start() and op_powerpc_stop(). These routines are called once - * per system as a result of the user starting/stopping oprofile. Hence, only - * one CPU per user at a time will be changing the value of spu_prof_running. - * In general, OProfile does not protect against multiple users trying to run - * OProfile at a time. - */ -int spu_prof_running; -static unsigned int profiling_interval; - -#define NUM_SPU_BITS_TRBUF 16 -#define SPUS_PER_TB_ENTRY 4 - -#define SPU_PC_MASK 0xFFFF - -DEFINE_SPINLOCK(oprof_spu_smpl_arry_lck); -static unsigned long oprof_spu_smpl_arry_lck_flags; - -void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset) -{ - unsigned long ns_per_cyc; - - if (!freq_khz) - freq_khz = ppc_proc_freq/1000; - - /* To calculate a timeout in nanoseconds, the basic - * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency). - * To avoid floating point math, we use the scale math - * technique as described in linux/jiffies.h. We use - * a scale factor of SCALE_SHIFT, which provides 4 decimal places - * of precision. This is close enough for the purpose at hand. - * - * The value of the timeout should be small enough that the hw - * trace buffer will not get more than about 1/3 full for the - * maximum user specified (the LFSR value) hw sampling frequency. - * This is to ensure the trace buffer will never fill even if the - * kernel thread scheduling varies under a heavy system load. - */ - - ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz; - profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT; - -} - -/* - * Extract SPU PC from trace buffer entry - */ -static void spu_pc_extract(int cpu, int entry) -{ - /* the trace buffer is 128 bits */ - u64 trace_buffer[2]; - u64 spu_mask; - int spu; - - spu_mask = SPU_PC_MASK; - - /* Each SPU PC is 16 bits; hence, four spus in each of - * the two 64-bit buffer entries that make up the - * 128-bit trace_buffer entry. Process two 64-bit values - * simultaneously. - * trace[0] SPU PC contents are: 0 1 2 3 - * trace[1] SPU PC contents are: 4 5 6 7 - */ - - cbe_read_trace_buffer(cpu, trace_buffer); - - for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) { - /* spu PC trace entry is upper 16 bits of the - * 18 bit SPU program counter - */ - samples[spu * TRACE_ARRAY_SIZE + entry] - = (spu_mask & trace_buffer[0]) << 2; - samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry] - = (spu_mask & trace_buffer[1]) << 2; - - trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF; - trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF; - } -} - -static int cell_spu_pc_collection(int cpu) -{ - u32 trace_addr; - int entry; - - /* process the collected SPU PC for the node */ - - entry = 0; - - trace_addr = cbe_read_pm(cpu, trace_address); - while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) { - /* there is data in the trace buffer to process */ - spu_pc_extract(cpu, entry); - - entry++; - - if (entry >= TRACE_ARRAY_SIZE) - /* spu_samples is full */ - break; - - trace_addr = cbe_read_pm(cpu, trace_address); - } - - return entry; -} - - -static enum hrtimer_restart profile_spus(struct hrtimer *timer) -{ - ktime_t kt; - int cpu, node, k, num_samples, spu_num; - - if (!spu_prof_running) - goto stop; - - for_each_online_cpu(cpu) { - if (cbe_get_hw_thread_id(cpu)) - continue; - - node = cbe_cpu_to_node(cpu); - - /* There should only be one kernel thread at a time processing - * the samples. In the very unlikely case that the processing - * is taking a very long time and multiple kernel threads are - * started to process the samples. Make sure only one kernel - * thread is working on the samples array at a time. The - * sample array must be loaded and then processed for a given - * cpu. The sample array is not per cpu. - */ - spin_lock_irqsave(&oprof_spu_smpl_arry_lck, - oprof_spu_smpl_arry_lck_flags); - num_samples = cell_spu_pc_collection(cpu); - - if (num_samples == 0) { - spin_unlock_irqrestore(&oprof_spu_smpl_arry_lck, - oprof_spu_smpl_arry_lck_flags); - continue; - } - - for (k = 0; k < SPUS_PER_NODE; k++) { - spu_num = k + (node * SPUS_PER_NODE); - spu_sync_buffer(spu_num, - samples + (k * TRACE_ARRAY_SIZE), - num_samples); - } - - spin_unlock_irqrestore(&oprof_spu_smpl_arry_lck, - oprof_spu_smpl_arry_lck_flags); - - } - smp_wmb(); /* insure spu event buffer updates are written */ - /* don't want events intermingled... */ - - kt = profiling_interval; - if (!spu_prof_running) - goto stop; - hrtimer_forward(timer, timer->base->get_time(), kt); - return HRTIMER_RESTART; - - stop: - printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n"); - return HRTIMER_NORESTART; -} - -static struct hrtimer timer; -/* - * Entry point for SPU cycle profiling. - * NOTE: SPU profiling is done system-wide, not per-CPU. - * - * cycles_reset is the count value specified by the user when - * setting up OProfile to count SPU_CYCLES. - */ -int start_spu_profiling_cycles(unsigned int cycles_reset) -{ - ktime_t kt; - - pr_debug("timer resolution: %lu\n", TICK_NSEC); - kt = profiling_interval; - hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer_set_expires(&timer, kt); - timer.function = profile_spus; - - /* Allocate arrays for collecting SPU PC samples */ - samples = kcalloc(SPUS_PER_NODE * TRACE_ARRAY_SIZE, sizeof(u32), - GFP_KERNEL); - - if (!samples) - return -ENOMEM; - - spu_prof_running = 1; - hrtimer_start(&timer, kt, HRTIMER_MODE_REL); - schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE); - - return 0; -} - -/* - * Entry point for SPU event profiling. - * NOTE: SPU profiling is done system-wide, not per-CPU. - * - * cycles_reset is the count value specified by the user when - * setting up OProfile to count SPU_CYCLES. - */ -void start_spu_profiling_events(void) -{ - spu_prof_running = 1; - schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE); - - return; -} - -void stop_spu_profiling_cycles(void) -{ - spu_prof_running = 0; - hrtimer_cancel(&timer); - kfree(samples); - pr_debug("SPU_PROF: stop_spu_profiling_cycles issued\n"); -} - -void stop_spu_profiling_events(void) -{ - spu_prof_running = 0; -} diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c deleted file mode 100644 index 489f993100d5..000000000000 --- a/arch/powerpc/oprofile/cell/spu_task_sync.c +++ /dev/null @@ -1,657 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Cell Broadband Engine OProfile Support - * - * (C) Copyright IBM Corporation 2006 - * - * Author: Maynard Johnson <may...@us...> - */ - -/* The purpose of this file is to handle SPU event task switching - * and to record SPU context information into the OProfile - * event buffer. - * - * Additionally, the spu_sync_buffer function is provided as a helper - * for recoding actual SPU program counter samples to the event buffer. - */ -#include <linux/dcookies.h> -#include <linux/kref.h> -#include <linux/mm.h> -#include <linux/fs.h> -#include <linux/file.h> -#include <linux/module.h> -#include <linux/notifier.h> -#include <linux/numa.h> -#include <linux/oprofile.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include "pr_util.h" - -#define RELEASE_ALL 9999 - -static DEFINE_SPINLOCK(buffer_lock); -static DEFINE_SPINLOCK(cache_lock); -static int num_spu_nodes; -static int spu_prof_num_nodes; - -struct spu_buffer spu_buff[MAX_NUMNODES * SPUS_PER_NODE]; -struct delayed_work spu_work; -static unsigned max_spu_buff; - -static void spu_buff_add(unsigned long int value, int spu) -{ - /* spu buff is a circular buffer. Add entries to the - * head. Head is the index to store the next value. - * The buffer is full when there is one available entry - * in the queue, i.e. head and tail can't be equal. - * That way we can tell the difference between the - * buffer being full versus empty. - * - * ASSUMPTION: the buffer_lock is held when this function - * is called to lock the buffer, head and tail. - */ - int full = 1; - - if (spu_buff[spu].head >= spu_buff[spu].tail) { - if ((spu_buff[spu].head - spu_buff[spu].tail) - < (max_spu_buff - 1)) - full = 0; - - } else if (spu_buff[spu].tail > spu_buff[spu].head) { - if ((spu_buff[spu].tail - spu_buff[spu].head) - > 1) - full = 0; - } - - if (!full) { - spu_buff[spu].buff[spu_buff[spu].head] = value; - spu_buff[spu].head++; - - if (spu_buff[spu].head >= max_spu_buff) - spu_buff[spu].head = 0; - } else { - /* From the user's perspective make the SPU buffer - * size management/overflow look like we are using - * per cpu buffers. The user uses the same - * per cpu parameter to adjust the SPU buffer size. - * Increment the sample_lost_overflow to inform - * the user the buffer size needs to be increased. - */ - oprofile_cpu_buffer_inc_smpl_lost(); - } -} - -/* This function copies the per SPU buffers to the - * OProfile kernel buffer. - */ -static void sync_spu_buff(void) -{ - int spu; - unsigned long flags; - int curr_head; - - for (spu = 0; spu < num_spu_nodes; spu++) { - /* In case there was an issue and the buffer didn't - * get created skip it. - */ - if (spu_buff[spu].buff == NULL) - continue; - - /* Hold the lock to make sure the head/tail - * doesn't change while spu_buff_add() is - * deciding if the buffer is full or not. - * Being a little paranoid. - */ - spin_lock_irqsave(&buffer_lock, flags); - curr_head = spu_buff[spu].head; - spin_unlock_irqrestore(&buffer_lock, flags); - - /* Transfer the current contents to the kernel buffer. - * data can still be added to the head of the buffer. - */ - oprofile_put_buff(spu_buff[spu].buff, - spu_buff[spu].tail, - curr_head, max_spu_buff); - - spin_lock_irqsave(&buffer_lock, flags); - spu_buff[spu].tail = curr_head; - spin_unlock_irqrestore(&buffer_lock, flags); - } - -} - -static void wq_sync_spu_buff(struct work_struct *work) -{ - /* move data from spu buffers to kernel buffer */ - sync_spu_buff(); - - /* only reschedule if profiling is not done */ - if (spu_prof_running) - schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE); -} - -/* Container for caching information about an active SPU task. */ -struct cached_info { - struct vma_to_fileoffset_map *map; - struct spu *the_spu; /* needed to access pointer to local_store */ - struct kref cache_ref; -}; - -static struct cached_info *spu_info[MAX_NUMNODES * 8]; - -static void destroy_cached_info(struct kref *kref) -{ - struct cached_info *info; - - info = container_of(kref, struct cached_info, cache_ref); - vma_map_free(info->map); - kfree(info); - module_put(THIS_MODULE); -} - -/* Return the cached_info for the passed SPU number. - * ATTENTION: Callers are responsible for obtaining the - * cache_lock if needed prior to invoking this function. - */ -static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num) -{ - struct kref *ref; - struct cached_info *ret_info; - - if (spu_num >= num_spu_nodes) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: Invalid index %d into spu info cache\n", - __func__, __LINE__, spu_num); - ret_info = NULL; - goto out; - } - if (!spu_info[spu_num] && the_spu) { - ref = spu_get_profile_private_kref(the_spu->ctx); - if (ref) { - spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref); - kref_get(&spu_info[spu_num]->cache_ref); - } - } - - ret_info = spu_info[spu_num]; - out: - return ret_info; -} - - -/* Looks for cached info for the passed spu. If not found, the - * cached info is created for the passed spu. - * Returns 0 for success; otherwise, -1 for error. - */ -static int -prepare_cached_spu_info(struct spu *spu, unsigned long objectId) -{ - unsigned long flags; - struct vma_to_fileoffset_map *new_map; - int retval = 0; - struct cached_info *info; - - /* We won't bother getting cache_lock here since - * don't do anything with the cached_info that's returned. - */ - info = get_cached_info(spu, spu->number); - - if (info) { - pr_debug("Found cached SPU info.\n"); - goto out; - } - - /* Create cached_info and set spu_info[spu->number] to point to it. - * spu->number is a system-wide value, not a per-node value. - */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: create vma_map failed\n", - __func__, __LINE__); - retval = -ENOMEM; - goto err_alloc; - } - new_map = create_vma_map(spu, objectId); - if (!new_map) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: create vma_map failed\n", - __func__, __LINE__); - retval = -ENOMEM; - goto err_alloc; - } - - pr_debug("Created vma_map\n"); - info->map = new_map; - info->the_spu = spu; - kref_init(&info->cache_ref); - spin_lock_irqsave(&cache_lock, flags); - spu_info[spu->number] = info; - /* Increment count before passing off ref to SPUFS. */ - kref_get(&info->cache_ref); - - /* We increment the module refcount here since SPUFS is - * responsible for the final destruction of the cached_info, - * and it must be able to access the destroy_cached_info() - * function defined in the OProfile module. We decrement - * the module refcount in destroy_cached_info. - */ - try_module_get(THIS_MODULE); - spu_set_profile_private_kref(spu->ctx, &info->cache_ref, - destroy_cached_info); - spin_unlock_irqrestore(&cache_lock, flags); - goto out; - -err_alloc: - kfree(info); -out: - return retval; -} - -/* - * NOTE: The caller is responsible for locking the - * cache_lock prior to calling this function. - */ -static int release_cached_info(int spu_index) -{ - int index, end; - - if (spu_index == RELEASE_ALL) { - end = num_spu_nodes; - index = 0; - } else { - if (spu_index >= num_spu_nodes) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: " - "Invalid index %d into spu info cache\n", - __func__, __LINE__, spu_index); - goto out; - } - end = spu_index + 1; - index = spu_index; - } - for (; index < end; index++) { - if (spu_info[index]) { - kref_put(&spu_info[index]->cache_ref, - destroy_cached_info); - spu_info[index] = NULL; - } - } - -out: - return 0; -} - -/* The source code for fast_get_dcookie was "borrowed" - * from drivers/oprofile/buffer_sync.c. - */ - -/* Optimisation. We can manage without taking the dcookie sem - * because we cannot reach this code without at least one - * dcookie user still being registered (namely, the reader - * of the event buffer). - */ -static inline unsigned long fast_get_dcookie(const struct path *path) -{ - unsigned long cookie; - - if (path->dentry->d_flags & DCACHE_COOKIE) - return (unsigned long)path->dentry; - get_dcookie(path, &cookie); - return cookie; -} - -/* Look up the dcookie for the task's mm->exe_file, - * which corresponds loosely to "application name". Also, determine - * the offset for the SPU ELF object. If computed offset is - * non-zero, it implies an embedded SPU object; otherwise, it's a - * separate SPU binary, in which case we retrieve it's dcookie. - * For the embedded case, we must determine if SPU ELF is embedded - * in the executable application or another file (i.e., shared lib). - * If embedded in a shared lib, we must get the dcookie and return - * that to the caller. - */ -static unsigned long -get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp, - unsigned long *spu_bin_dcookie, - unsigned long spu_ref) -{ - unsigned long app_cookie = 0; - unsigned int my_offset = 0; - struct vm_area_struct *vma; - struct file *exe_file; - struct mm_struct *mm = spu->mm; - - if (!mm) - goto out; - - exe_file = get_mm_exe_file(mm); - if (exe_file) { - app_cookie = fast_get_dcookie(&exe_file->f_path); - pr_debug("got dcookie for %pD\n", exe_file); - fput(exe_file); - } - - mmap_read_lock(mm); - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref) - continue; - my_offset = spu_ref - vma->vm_start; - if (!vma->vm_file) - goto fail_no_image_cookie; - - pr_debug("Found spu ELF at %X(object-id:%lx) for file %pD\n", - my_offset, spu_ref, vma->vm_file); - *offsetp = my_offset; - break; - } - - *spu_bin_dcookie = fast_get_dcookie(&vma->vm_file->f_path); - pr_debug("got dcookie for %pD\n", vma->vm_file); - - mmap_read_unlock(mm); - -out: - return app_cookie; - -fail_no_image_cookie: - mmap_read_unlock(mm); - - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: Cannot find dcookie for SPU binary\n", - __func__, __LINE__); - goto out; -} - - - -/* This function finds or creates cached context information for the - * passed SPU and records SPU context information into the OProfile - * event buffer. - */ -static int process_context_switch(struct spu *spu, unsigned long objectId) -{ - unsigned long flags; - int retval; - unsigned int offset = 0; - unsigned long spu_cookie = 0, app_dcookie; - - retval = prepare_cached_spu_info(spu, objectId); - if (retval) - goto out; - - /* Get dcookie first because a mutex_lock is taken in that - * code path, so interrupts must not be disabled. - */ - app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId); - if (!app_dcookie || !spu_cookie) { - retval = -ENOENT; - goto out; - } - - /* Record context info in event buffer */ - spin_lock_irqsave(&buffer_lock, flags); - spu_buff_add(ESCAPE_CODE, spu->number); - spu_buff_add(SPU_CTX_SWITCH_CODE, spu->number); - spu_buff_add(spu->number, spu->number); - spu_buff_add(spu->pid, spu->number); - spu_buff_add(spu->tgid, spu->number); - spu_buff_add(app_dcookie, spu->number); - spu_buff_add(spu_cookie, spu->number); - spu_buff_add(offset, spu->number); - - /* Set flag to indicate SPU PC data can now be written out. If - * the SPU program counter data is seen before an SPU context - * record is seen, the postprocessing will fail. - */ - spu_buff[spu->number].ctx_sw_seen = 1; - - spin_unlock_irqrestore(&buffer_lock, flags); - smp_wmb(); /* insure spu event buffer updates are written */ - /* don't want entries intermingled... */ -out: - return retval; -} - -/* - * This function is invoked on either a bind_context or unbind_context. - * If called for an unbind_context, the val arg is 0; otherwise, - * it is the object-id value for the spu context. - * The data arg is of type 'struct spu *'. - */ -static int spu_active_notify(struct notifier_block *self, unsigned long val, - void *data) -{ - int retval; - unsigned long flags; - struct spu *the_spu = data; - - pr_debug("SPU event notification arrived\n"); - if (!val) { - spin_lock_irqsave(&cache_lock, flags); - retval = release_cached_info(the_spu->number); - spin_unlock_irqrestore(&cache_lock, flags); - } else { - retval = process_context_switch(the_spu, val); - } - return retval; -} - -static struct notifier_block spu_active = { - .notifier_call = spu_active_notify, -}; - -static int number_of_online_nodes(void) -{ - u32 cpu; u32 tmp; - int nodes = 0; - for_each_online_cpu(cpu) { - tmp = cbe_cpu_to_node(cpu) + 1; - if (tmp > nodes) - nodes++; - } - return nodes; -} - -static int oprofile_spu_buff_create(void) -{ - int spu; - - max_spu_buff = oprofile_get_cpu_buffer_size(); - - for (spu = 0; spu < num_spu_nodes; spu++) { - /* create circular buffers to store the data in. - * use locks to manage accessing the buffers - */ - spu_buff[spu].head = 0; - spu_buff[spu].tail = 0; - - /* - * Create a buffer for each SPU. Can't reliably - * create a single buffer for all spus due to not - * enough contiguous kernel memory. - */ - - spu_buff[spu].buff = kzalloc((max_spu_buff - * sizeof(unsigned long)), - GFP_KERNEL); - - if (!spu_buff[spu].buff) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: oprofile_spu_buff_create " - "failed to allocate spu buffer %d.\n", - __func__, __LINE__, spu); - - /* release the spu buffers that have been allocated */ - while (spu >= 0) { - kfree(spu_buff[spu].buff); - spu_buff[spu].buff = 0; - spu--; - } - return -ENOMEM; - } - } - return 0; -} - -/* The main purpose of this function is to synchronize - * OProfile with SPUFS by registering to be notified of - * SPU task switches. - * - * NOTE: When profiling SPUs, we must ensure that only - * spu_sync_start is invoked and not the generic sync_start - * in drivers/oprofile/oprof.c. A return value of - * SKIP_GENERIC_SYNC or SYNC_START_ERROR will - * accomplish this. - */ -int spu_sync_start(void) -{ - int spu; - int ret = SKIP_GENERIC_SYNC; - int register_ret; - unsigned long flags = 0; - - spu_prof_num_nodes = number_of_online_nodes(); - num_spu_nodes = spu_prof_num_nodes * 8; - INIT_DELAYED_WORK(&spu_work, wq_sync_spu_buff); - - /* create buffer for storing the SPU data to put in - * the kernel buffer. - */ - ret = oprofile_spu_buff_create(); - if (ret) - goto out; - - spin_lock_irqsave(&buffer_lock, flags); - for (spu = 0; spu < num_spu_nodes; spu++) { - spu_buff_add(ESCAPE_CODE, spu); - spu_buff_add(SPU_PROFILING_CODE, spu); - spu_buff_add(num_spu_nodes, spu); - } - spin_unlock_irqrestore(&buffer_lock, flags); - - for (spu = 0; spu < num_spu_nodes; spu++) { - spu_buff[spu].ctx_sw_seen = 0; - spu_buff[spu].last_guard_val = 0; - } - - /* Register for SPU events */ - register_ret = spu_switch_event_register(&spu_active); - if (register_ret) { - ret = SYNC_START_ERROR; - goto out; - } - - pr_debug("spu_sync_start -- running.\n"); -out: - return ret; -} - -/* Record SPU program counter samples to the oprofile event buffer. */ -void spu_sync_buffer(int spu_num, unsigned int *samples, - int num_samples) -{ - unsigned long long file_offset; - unsigned long flags; - int i; - struct vma_to_fileoffset_map *map; - struct spu *the_spu; - unsigned long long spu_num_ll = spu_num; - unsigned long long spu_num_shifted = spu_num_ll << 32; - struct cached_info *c_info; - - /* We need to obtain the cache_lock here because it's - * possible that after getting the cached_info, the SPU job - * corresponding to this cached_info may end, thus resulting - * in the destruction of the cached_info. - */ - spin_lock_irqsave(&cache_lock, flags); - c_info = get_cached_info(NULL, spu_num); - if (!c_info) { - /* This legitimately happens when the SPU task ends before all - * samples are recorded. - * No big deal -- so we just drop a few samples. - */ - pr_debug("SPU_PROF: No cached SPU context " - "for SPU #%d. Dropping samples.\n", spu_num); - goto out; - } - - map = c_info->map; - the_spu = c_info->the_spu; - spin_lock(&buffer_lock); - for (i = 0; i < num_samples; i++) { - unsigned int sample = *(samples+i); - int grd_val = 0; - file_offset = 0; - if (sample == 0) - continue; - file_offset = vma_map_lookup( map, sample, the_spu, &grd_val); - - /* If overlays are used by this SPU application, the guard - * value is non-zero, indicating which overlay section is in - * use. We need to discard samples taken during the time - * period which an overlay occurs (i.e., guard value changes). - */ - if (grd_val && grd_val != spu_buff[spu_num].last_guard_val) { - spu_buff[spu_num].last_guard_val = grd_val; - /* Drop the rest of the samples. */ - break; - } - - /* We must ensure that the SPU context switch has been written - * out before samples for the SPU. Otherwise, the SPU context - * information is not available and the postprocessing of the - * SPU PC will fail with no available anonymous map information. - */ - if (spu_buff[spu_num].ctx_sw_seen) - spu_buff_add((file_offset | spu_num_shifted), - spu_num); - } - spin_unlock(&buffer_lock); -out: - spin_unlock_irqrestore(&cache_lock, flags); -} - - -int spu_sync_stop(void) -{ - unsigned long flags = 0; - int ret; - int k; - - ret = spu_switch_event_unregister(&spu_active); - - if (ret) - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: spu_switch_event_unregister " \ - "returned %d\n", - __func__, __LINE__, ret); - - /* flush any remaining data in the per SPU buffers */ - sync_spu_buff(); - - spin_lock_irqsave(&cache_lock, flags); - ret = release_cached_info(RELEASE_ALL); - spin_unlock_irqrestore(&cache_lock, flags); - - /* remove scheduled work queue item rather then waiting - * for every queued entry to execute. Then flush pending - * system wide buffer to event buffer. - */ - cancel_delayed_work(&spu_work); - - for (k = 0; k < num_spu_nodes; k++) { - spu_buff[k].ctx_sw_seen = 0; - - /* - * spu_sys_buff will be null if there was a problem - * allocating the buffer. Only delete if it exists. - */ - kfree(spu_buff[k].buff); - spu_buff[k].buff = 0; - } - pr_debug("spu_sync_stop -- done.\n"); - return ret; -} - diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c deleted file mode 100644 index 7c4b19cfde88..000000000000 --- a/arch/powerpc/oprofile/cell/vma_map.c +++ /dev/null @@ -1,279 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Cell Broadband Engine OProfile Support - * - * (C) Copyright IBM Corporation 2006 - * - * Author: Maynard Johnson <may...@us...> - */ - -/* The code in this source file is responsible for generating - * vma-to-fileOffset maps for both overlay and non-overlay SPU - * applications. - */ - -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/uaccess.h> -#include <linux/elf.h> -#include <linux/slab.h> -#include "pr_util.h" - - -void vma_map_free(struct vma_to_fileoffset_map *map) -{ - while (map) { - struct vma_to_fileoffset_map *next = map->next; - kfree(map); - map = next; - } -} - -unsigned int -vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma, - const struct spu *aSpu, int *grd_val) -{ - /* - * Default the offset to the physical address + a flag value. - * Addresses of dynamically generated code can't be found in the vma - * map. For those addresses the flagged value will be sent on to - * the user space tools so they can be reported rather than just - * thrown away. - */ - u32 offset = 0x10000000 + vma; - u32 ovly_grd; - - for (; map; map = map->next) { - if (vma < map->vma || vma >= map->vma + map->size) - continue; - - if (map->guard_ptr) { - ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr); - if (ovly_grd != map->guard_val) - continue; - *grd_val = ovly_grd; - } - offset = vma - map->vma + map->offset; - break; - } - - return offset; -} - -static struct vma_to_fileoffset_map * -vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma, - unsigned int size, unsigned int offset, unsigned int guard_ptr, - unsigned int guard_val) -{ - struct vma_to_fileoffset_map *new = kzalloc(sizeof(*new), GFP_KERNEL); - - if (!new) { - printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n", - __func__, __LINE__); - vma_map_free(map); - return NULL; - } - - new->next = map; - new->vma = vma; - new->size = size; - new->offset = offset; - new->guard_ptr = guard_ptr; - new->guard_val = guard_val; - - return new; -} - - -/* Parse SPE ELF header and generate a list of vma_maps. - * A pointer to the first vma_map in the generated list - * of vma_maps is returned. */ -struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu, - unsigned long __spu_elf_start) -{ - static const unsigned char expected[EI_PAD] = { - [EI_MAG0] = ELFMAG0, - [EI_MAG1] = ELFMAG1, - [EI_MAG2] = ELFMAG2, - [EI_MAG3] = ELFMAG3, - [EI_CLASS] = ELFCLASS32, - [EI_DATA] = ELFDATA2MSB, - [EI_VERSION] = EV_CURRENT, - [EI_OSABI] = ELFOSABI_NONE - }; - - int grd_val; - struct vma_to_fileoffset_map *map = NULL; - void __user *spu_elf_start = (void __user *)__spu_elf_start; - struct spu_overlay_info ovly; - unsigned int overlay_tbl_offset = -1; - Elf32_Phdr __user *phdr_start; - Elf32_Shdr __user *shdr_start; - Elf32_Ehdr ehdr; - Elf32_Phdr phdr; - Elf32_Shdr shdr, shdr_str; - Elf32_Sym sym; - int i, j; - char name[32]; - - unsigned int ovly_table_sym = 0; - unsigned int ovly_buf_table_sym = 0; - unsigned int ovly_table_end_sym = 0; - unsigned int ovly_buf_table_end_sym = 0; - struct spu_overlay_info __user *ovly_table; - unsigned int n_ovlys; - - /* Get and validate ELF header. */ - - if (copy_from_user(&ehdr, spu_elf_start, sizeof (ehdr))) - goto fail; - - if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: Unexpected e_ident parsing SPU ELF\n", - __func__, __LINE__); - goto fail; - } - if (ehdr.e_machine != EM_SPU) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: Unexpected e_machine parsing SPU ELF\n", - __func__, __LINE__); - goto fail; - } - if (ehdr.e_type != ET_EXEC) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: Unexpected e_type parsing SPU ELF\n", - __func__, __LINE__); - goto fail; - } - phdr_start = spu_elf_start + ehdr.e_phoff; - shdr_start = spu_elf_start + ehdr.e_shoff; - - /* Traverse program headers. */ - for (i = 0; i < ehdr.e_phnum; i++) { - if (copy_from_user(&phdr, phdr_start + i, sizeof(phdr))) - goto fail; - - if (phdr.p_type != PT_LOAD) - continue; - if (phdr.p_flags & (1 << 27)) - continue; - - map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz, - phdr.p_offset, 0, 0); - if (!map) - goto fail; - } - - pr_debug("SPU_PROF: Created non-overlay maps\n"); - /* Traverse section table and search for overlay-related symbols. */ - for (i = 0; i < ehdr.e_shnum; i++) { - if (copy_from_user(&shdr, shdr_start + i, sizeof(shdr))) - goto fail; - - if (shdr.sh_type != SHT_SYMTAB) - continue; - if (shdr.sh_entsize != sizeof (sym)) - continue; - - if (copy_from_user(&shdr_str, - shdr_start + shdr.sh_link, - sizeof(shdr))) - goto fail; - - if (shdr_str.sh_type != SHT_STRTAB) - goto fail; - - for (j = 0; j < shdr.sh_size / sizeof (sym); j++) { - if (copy_from_user(&sym, spu_elf_start + - shdr.sh_offset + - j * sizeof (sym), - sizeof (sym))) - goto fail; - - if (copy_from_user(name, - spu_elf_start + shdr_str.sh_offset + - sym.st_name, - 20)) - goto fail; - - if (memcmp(name, "_ovly_table", 12) == 0) - ovly_table_sym = sym.st_value; - if (memcmp(name, "_ovly_buf_table", 16) == 0) - ovly_buf_table_sym = sym.st_value; - if (memcmp(name, "_ovly_table_end", 16) == 0) - ovly_table_end_sym = sym.st_value; - if (memcmp(name, "_ovly_buf_table_end", 20) == 0) - ovly_buf_table_end_sym = sym.st_value; - } - } - - /* If we don't have overlays, we're done. */ - if (ovly_table_sym == 0 || ovly_buf_table_sym == 0 - || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) { - pr_debug("SPU_PROF: No overlay table found\n"); - goto out; - } else { - pr_debug("SPU_PROF: Overlay table found\n"); - } - - /* The _ovly_table symbol represents a table with one entry - * per overlay section. The _ovly_buf_table symbol represents - * a table with one entry per overlay region. - * The struct spu_overlay_info gives the structure of the _ovly_table - * entries. The structure of _ovly_table_buf is simply one - * u32 word per entry. - */ - overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym, - aSpu, &grd_val); - if (overlay_tbl_offset > 0x10000000) { - printk(KERN_ERR "SPU_PROF: " - "%s, line %d: Error finding SPU overlay table\n", - __func__, __LINE__); - goto fail; - } - ovly_table = spu_elf_start + overlay_tbl_offset; - - n_ovlys = (ovly_table_end_sym - - ovly_table_sym) / sizeof (ovly); - - /* Traverse overlay table. */ - for (i = 0; i < n_ovlys; i++) { - if (copy_from_user(&ovly, ovly_table + i, sizeof (ovly))) - goto fail; - - /* The ovly.vma/size/offset arguments are analogous to the same - * arguments used above for non-overlay maps. The final two - * args are referred to as the guard pointer and the guard - * value. - * The guard pointer is an entry in the _ovly_buf_table, - * computed using ovly.buf as the index into the table. Since - * ovly.buf values begin at '1' to reference the first (or 0th) - * entry in the _ovly_buf_table, the computation subtracts 1 - * from ovly.buf. - * The guard value is stored in the _ovly_buf_table entry and - * is an index (starting at 1) back to the _ovly_table entry - * that is pointing at this _ovly_buf_table entry. So, for - * example, for an overlay scenario with one overlay segment - * and two overlay sections: - * - Section 1 points to the first entry of the - * _ovly_buf_table, which contains a guard value - * of '1', referencing the first (index=0) entry of - * _ovly_table. - * - Section 2 points to the second entry of the - * _ovly_buf_table, which contains a guard value - * of '2', referencing the second (index=1) entry of - * _ovly_table. - */ - map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset, - ovly_buf_table_sym + (ovly.buf-1) * 4, i+1); - if (!map) - goto fail; - } - goto out; - - fail: - map = NULL; - out: - return map; -} diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c deleted file mode 100644 index 0fb528c2b3a1..000000000000 --- a/arch/powerpc/oprofile/common.c +++ /dev/null @@ -1,243 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * PPC 64 oprofile support: - * Copyright (C) 2004 Anton Blanchard <an...@au...>, IBM - * PPC 32 oprofile support: (based on PPC 64 support) - * Copyright (C) Freescale Semiconductor, Inc 2004 - * Author: Andy Fleming - * - * Based on alpha version. - */ - -#include <linux/oprofile.h> -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <asm/ptrace.h> -#include <asm/pmc.h> -#include <asm/cputable.h> -#include <asm/oprofile_impl.h> -#include <asm/firmware.h> - -static struct op_powerpc_model *model; - -static struct op_counter_config ctr[OP_MAX_COUNTER]; -static struct op_system_config sys; - -static int op_per_cpu_rc; - -static void op_handle_interrupt(struct pt_regs *regs) -{ - model->handle_interrupt(regs, ctr); -} - -static void op_powerpc_cpu_setup(void *dummy) -{ - int ret; - - ret = model->cpu_setup(ctr); - - if (ret != 0) - op_per_cpu_rc = ret; -} - -static int op_powerpc_setup(void) -{ - int err; - - op_per_cpu_rc = 0; - - /* Grab the hardware */ - err = reserve_pmc_hardware(op_handle_interrupt); - if (err) - return err; - - /* Pre-compute the values to stuff in the hardware registers. */ - op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters); - - if (op_per_cpu_rc) - goto out; - - /* Configure the registers on all cpus. If an error occurs on one - * of the cpus, op_per_cpu_rc will be set to the error */ - on_each_cpu(op_powerpc_cpu_setup, NULL, 1); - -out: if (op_per_cpu_rc) { - /* error on setup release the performance counter hardware */ - release_pmc_hardware(); - } - - return op_per_cpu_rc; -} - -static void op_powerpc_shutdown(void) -{ - release_pmc_hardware(); -} - -static void op_powerpc_cpu_start(void *dummy) -{ - /* If any of the cpus have return an error, set the - * global flag to the error so it can be returned - * to the generic OProfile caller. - */ - int ret; - - ret = model->start(ctr); - if (ret != 0) - op_per_cpu_rc = ret; -} - -static int op_powerpc_start(void) -{ - op_per_cpu_rc = 0; - - if (model->global_start) - return model->global_start(ctr); - if (model->start) { - on_each_cpu(op_powerpc_cpu_start, NULL, 1); - return op_per_cpu_rc; - } - return -EIO; /* No start function is defined for this - power architecture */ -} - -static inline void op_powerpc_cpu_stop(void *dummy) -{ - model->stop(); -} - -static void op_powerpc_stop(void) -{ - if (model->stop) - on_each_cpu(op_powerpc_cpu_stop, NULL, 1); - if (model->global_stop) - model->global_stop(); -} - -static int op_powerpc_create_files(struct dentry *root) -{ - int i; - -#ifdef CONFIG_PPC64 - /* - * There is one mmcr0, mmcr1 and mmcra for setting the events for - * all of the counters. - */ - oprofilefs_create_ulong(root, "mmcr0", &sys.mmcr0); - oprofilefs_create_ulong(root, "mmcr1", &sys.mmcr1); - oprofilefs_create_ulong(root, "mmcra", &sys.mmcra); -#ifdef CONFIG_OPROFILE_CELL - /* create a file the user tool can check to see what level of profiling - * support exits with this kernel. Initialize bit mask to indicate - * what support the kernel has: - * bit 0 - Supports SPU event profiling in addition to PPU - * event and cycles; and SPU cycle profiling - * bits 1-31 - Currently unused. - * - * If the file does not exist, then the kernel only supports SPU - * cycle profiling, PPU event and cycle profiling. - */ - oprofilefs_create_ulong(root, "cell_support", &sys.cell_support); - sys.cell_support = 0x1; /* Note, the user OProfile tool must check - * that this bit is set before attempting to - * user SPU event profiling. Older kernels - * will not have this file, hence the user - * tool is not allowed to do SPU event - * profiling on older kernels. Older kernels - * will accept SPU events but collected data - * is garbage. - */ -#endif -#endif - - for (i = 0; i < model->num_counters; ++i) { - struct dentry *dir; - char buf[4]; - - snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(root, buf); - - oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled); - oprofilefs_create_ulong(dir, "event", &ctr[i].event); - oprofilefs_create_ulong(dir, "count", &ctr[i].count); - - /* - * Classic PowerPC doesn't support per-counter - * control like this, but the options are - * expected, so they remain. For Freescale - * Book-E style performance monitors, we do - * support them. - */ - oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel); - oprofilefs_create_ulong(dir, "user", &ctr[i].user); - - oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask); - } - - oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel); - oprofilefs_create_ulong(root, "enable_user", &sys.enable_user); - - /* Default to tracing both kernel and user */ - sys.enable_kernel = 1; - sys.enable_user = 1; - - return 0; -} - -int __init oprofile_arch_init(struct oprofile_operations *ops) -{ - if (!cur_cpu_spec->oprofile_cpu_type) - return -ENODEV; - - switch (cur_cpu_spec->oprofile_type) { -#ifdef CONFIG_PPC_BOOK3S_64 -#ifdef CONFIG_OPROFILE_CELL - case PPC_OPROFILE_CELL: - if (firmware_has_feature(FW_FEATURE_LPAR)) - return -ENODEV; - model = &op_model_cell; - ops->sync_start = model->sync_start; - ops->sync_stop = model->sync_stop; - break; -#endif - case PPC_OPROFILE_POWER4: - model = &op_model_power4; - break; - case PPC_OPROFILE_PA6T: - model = &op_model_pa6t; - break; -#endif -#ifdef CONFIG_PPC_BOOK3S_32 - case PPC_OPROFILE_G4: - model = &op_model_7450; - break; -#endif -#if defined(CONFIG_FSL_EMB_PERFMON) - case PPC_OPROFILE_FSL_EMB: - model = &op_model_fsl_emb; - break; -#endif - default: - return -ENODEV; - } - - model->num_counters = cur_cpu_spec->num_pmcs; - - ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; - ops->create_files = op_powerpc_create_files; - ops->setup = op_powerpc_setup; - ops->shutdown = op_powerpc_shutdown; - ops->start = op_powerpc_start; - ops->stop = op_powerpc_stop; - ops->backtrace = op_powerpc_backtrace; - - printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n", - ops->cpu_type); - - return 0; -} - -void oprofile_arch_exit(void) -{ -} diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c deleted file mode 100644 index 5ebc25188a72..000000000000 --- a/arch/powerpc/oprofile/op_model_7450.c +++ /dev/null @@ -1,207 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/powerpc/oprofile/op_model_7450.c - * - * Freescale 745x/744x oprofile support, based on fsl_booke support - * Copyright (C) 2004 Anton Blanchard <an...@au...>, IBM - * - * Copyright (c) 2004 Freescale Semiconductor, Inc - * - * Author: Andy Fleming - * Maintainer: Kumar Gala <ga...@ke...> - */ - -#include <linux/oprofile.h> -#include <linux/smp.h> -#include <asm/ptrace.h> -#include <asm/processor.h> -#include <asm/cputable.h> -#include <asm/page.h> -#include <asm/pmc.h> -#include <asm/oprofile_impl.h> - -static unsigned long reset_value[OP_MAX_COUNTER]; - -static int oprofile_running; -static u32 mmcr0_val, mmcr1_val, mmcr2_val, num_pmcs; - -#define MMCR0_PMC1_SHIFT 6 -#define MMCR0_PMC2_SHIFT 0 -#define MMCR1_PMC3_SHIFT 27 -#define MMCR1_PMC4_SHIFT 22 -#define MMCR1_PMC5_SHIFT 17 -#define MMCR1_PMC6_SHIFT 11 - -#define mmcr0_event1(event) \ - ((event << MMCR0_PMC1_SHIFT) & MMCR0_PMC1SEL) -#define mmcr0_event2(event) \ - ((event << MMCR0_PMC2_SHIFT) & MMCR0_PMC2SEL) - -#define mmcr1_event3(event) \ - ((event << MMCR1_PMC3_SHIFT) & MMCR1_PMC3SEL) -#define mmcr1_event4(event) \ - ((event << MMCR1_PMC4_SHIFT) & MMCR1_PMC4SEL) -#define mmcr1_event5(event) \ - ((event << MMCR1_PMC5_SHIFT) & MMCR1_PMC5SEL) -#define mmcr1_event6(event) \ - ((event << MMCR1_PMC6_SHIFT) & MMCR1_PMC6SEL) - -#define MMCR0_INIT (MMCR0_FC | MMCR0_FCS | MMCR0_FCP | MMCR0_FCM1 | MMCR0_FCM0) - -/* Unfreezes the counters on this CPU, enables the interrupt, - * enables the counters to trigger the interrupt, and sets the - * counters to only count when the mark bit is not set. - */ -static void pmc_start_ctrs(void) -{ - u32 mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0); - mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE); - - mtspr(SPRN_MMCR0, mmcr0); -} - -/* Disables the counters on this CPU, and freezes them */ -static void pmc_stop_ctrs(void) -{ - u32 mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 |= MMCR0_FC; - mmcr0 &= ~(MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE); - - mtspr(SPRN_MMCR0, mmcr0); -} - -/* Configures the counters on this CPU based on the global - * settings */ -static int fsl7450_cpu_setup(struct op_counter_config *ctr) -{ - /* freeze all counters */ - pmc_stop_ctrs(); - - mtspr(SPRN_MMCR0, mmcr0_val); - mtspr(SPRN_MMCR1, mmcr1_val); - if (num_pmcs > 4) - mtspr(SPRN_MMCR2, mmcr2_val); - - return 0; -} - -/* Configures the global settings for the countes on all CPUs. */ -static int fsl7450_reg_setup(struct op_counter_config *ctr, - struct op_system_config *sys, - int num_ctrs) -{ - int i; - - num_pmcs = num_ctrs; - /* Our counters count up, and "count" refers to - * how much before the next interrupt, and we interrupt - * on overflow. So we calculate the starting value - * which will give us "count" until overflow. - * Then we set the events on the enabled counters */ - for (i = 0; i < num_ctrs; ++i) - reset_value[i] = 0x80000000UL - ctr[i].count; - - /* Set events for Counters 1 & 2 */ - mmcr0_val = MMCR0_INIT | mmcr0_event1(ctr[0].event) - | mmcr0_event2(ctr[1].event); - - /* Setup user/kernel bits */ - if (sys->enable_kernel) - mmcr0_val &= ~(MMCR0_FCS); - - if (sys->enable_user) - mmcr0_val &= ~(MMCR0_FCP); - - /* Set events for Counters 3-6 */ - mmcr1_val = mmcr1_event3(ctr[2].event) - | mmcr1_event4(ctr[3].event); - if (num_ctrs > 4) - mmcr1_val |= mmcr1_event5(ctr[4].event) - | mmcr1_event6(ctr[5].event); - - mmcr2_val = 0; - - return 0; -} - -/* Sets the counters on this CPU to the chosen values, and starts them */ -static int fsl7450_start(struct op_counter_config *ctr) -{ - int i; - - mtmsr(mfmsr() | MSR_PMM); - - for (i = 0; i < num_pmcs; ++i) { - if (ctr[i].enabled) - classic_ctr_write(i, reset_value[i]); - else - classic_ctr_write(i, 0); - } - - /* Clear the freeze bit, and enable the interrupt. - * The counters won't actually start until the rfi clears - * the PMM bit */ - pmc_start_ctrs(); - - oprofile_running = 1; - - return 0; -} - -/* Stop the counters on this CPU */ -static void fsl7450_stop(void) -{ - /* freeze counters */ - pmc_stop_ctrs(); - - oprofile_running = 0; - - mb(); -} - - -/* Handle the interrupt on this CPU, and log a sample for each - * event that triggered the interrupt */ -static void fsl7450_handle_interrupt(struct pt_regs *regs, - struct op_counter_config *ctr) -{ - unsigned long pc; - int is_kernel; - int val; - int i; - - /* set the PMM bit (see comment below) */ - mtmsr(mfmsr() | MSR_PMM); - - pc = mfspr(SPRN_SIAR); - is_kernel = is_kernel_addr(pc); - - for (i = 0; i < num_pmcs; ++i) { - val = classic_ctr_read(i); - if (val < 0) { - if (oprofile_running && ctr[i].enabled) { - oprofile_add_ext_sample(pc, regs, i, is_kernel); - classic_ctr_write(i, reset_value[i]); - } else { - classic_ctr_write(i, 0); - } - } - } - - /* The freeze bit was set by the interrupt. */ - /* Clear the freeze bit, and reenable the interrupt. - * The counters won't actually start until the rfi clears - * the PM/M bit */ - pmc_start_ctrs(); -} - -struct op_powerpc_model op_model_7450= { - .reg_setup = fsl7450_reg_setup, - .cpu_setup = fsl7450_cpu_setup, - .start = fsl7450_start, - .stop = fsl7450_stop, - .handle_interrupt = fsl7450_handle_interrupt, -}; diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c deleted file mode 100644 index 7eb73070b7be..000000000000 --- a/arch/powerpc/oprofile/op_model_cell.c +++ /dev/null @@ -1,1709 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Cell Broadband Engine OProfile Support - * - * (C) Copyright IBM Corporation 2006 - * - * Author: David Erb (dj...@us...) - * Modifications: - * Carl Love <ca...@us...> - * Maynard Johnson <may...@us...> - */ - -#include <linux/cpufreq.h> -#include <linux/delay.h> -#include <linux/jiffies.h> -#include <linux/kthread.h> -#include <linux/oprofile.h> -#include <linux/percpu.h> -#include <linux/smp.h> -#include <linux/spinlock.h> -#include <linux/timer.h> -#include <asm/cell-pmu.h> -#include <asm/cputable.h> -#include <asm/firmware.h> -#include <asm/io.h> -#include <asm/oprofile_impl.h> -#include <asm/processor.h> -#include <asm/prom.h> -#include <asm/ptrace.h> -#include <asm/reg.h> -#include <asm/rtas.h> -#include <asm/cell-regs.h> - -#include "../platforms/cell/interrupt.h" -#include "cell/pr_util.h" - -#define PPU_PROFILING 0 -#define SPU_PROFILING_CYCLES 1 -#define SPU_PROFILING_EVENTS 2 - -#define SPU_EVENT_NUM_START 4100 -#define SPU_EVENT_NUM_STOP 4399 -#define SPU_PROFILE_EVENT_ADDR 4363 /* spu, address trace, decimal */ -#define SPU_PROFILE_EVENT_ADDR_MASK_A 0x146 /* sub unit set to zero */ -#define SPU_PROFILE_EVENT_ADDR_MASK_B 0x186 /* sub unit set to zero */ - -#define NUM_SPUS_PER_NODE 8 -#define SPU_CYCLES_EVENT_NUM 2 /* event number for SPU_CYCLES */ - -#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */ -#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying - * PPU_CYCLES event - */ -#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */ - -#define NUM_THREADS 2 /* number of physical threads in - * physical processor - */ -#define NUM_DEBUG_BUS_WORDS 4 -#define NUM_INPUT_BUS_WORDS 2 - -#define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */ - -/* Minimum HW interval timer setting to send value to trace buffer is 10 cycle. - * To configure counter to send value every N cycles set counter to - * 2^32 - 1 - N. - */ -#define NUM_INTERVAL_CYC 0xFFFFFFFF - 10 - -/* - * spu_cycle_reset is the number of cycles between samples. - * This variable is used for SPU profiling and should ONLY be set - * at the beginning of cell_reg_setup; otherwise, it's read-only. - */ -static unsigned int spu_cycle_reset; -static unsigned int profiling_mode; -static int spu_evnt_phys_spu_indx; - -struct pmc_cntrl_data { - unsigned long vcntr; - unsigned long evnts; - unsigned long masks; - unsigned long enabled; -}; - -/* - * ibm,cbe-perftools rtas parameters - */ -struct pm_signal { - u16 cpu; /* Processor to modify */ - u16 sub_unit; /* hw subunit this applies to (if applicable)*/ - short int signal_group; /* Signal Group to Enable/Disable */ - u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event - * Bus Word(s) (bitmask) - */ - u8 bit; /* Trigger/Event bit (if applicable) */ -}; - -/* - * rtas call arguments - */ -enum { - SUBFUNC_RESET = 1, - SUBFUNC_ACTIVATE = 2, - SUBFUNC_DEACTIVATE = 3, - - PASSTHRU_IGNORE = 0, - PASSTHRU_ENABLE = 1, - PASSTHRU_DISABLE = 2, -}; - -struct pm_cntrl { - u16 enable; - u16 stop_at_max; - u16 trace_mode; - u16 freeze; - u16 count_mode; - u16 spu_addr_trace; - u8 trace_buf_ovflw; -}; - -static struct { - u32 group_control; - u32 debug_bus_control; - struct pm_cntrl pm_cntrl; - u32 pm07_cntrl[NR_PHYS_CTRS]; -} pm_regs; - -#define GET_SUB_UNIT(x) ((x & 0x0000f000) >> 12) -#define GET_BUS_WORD(x) ((x & 0x000000f0) >> 4) -#define GET_BUS_TYPE(x) ((x & 0x00000300) >> 8) -#define GET_POLARITY(x) ((x & 0x00000002) >> 1) -#define GET_COUNT_CYCLES(x) (x & 0x00000001) -#define GET_INPUT_CONTROL(x) ((x & 0x00000004) >> 2) - -static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values); -static unsigned long spu_pm_cnt[MAX_NUMNODES * NUM_SPUS_PER_NODE]; -static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS]; - -/* - * The CELL profiling code makes rtas calls to setup the debug bus to - * route the performance signals. Additionally, SPU profiling requires - * a second rtas call to setup the hardware to capture the SPU PCs. - * The EIO error value is returned if the token lookups or the rtas - * call fail. The EIO error number is the best choice of the existing - * error numbers. The probability of rtas related error is very low. But - * by returning EIO and printing additional information to dmsg the user - * will know that OProfile did not start and dmesg will tell them why. - * OProfile does not support returning errors on Stop. Not a huge issue - * since failure to reset the debug bus or stop the SPU PC collection is - * not a fatel issue. Chances are if the Stop failed, Start doesn't work - * either. - */ - -/* - * Interpetation of hdw_thread: - * 0 - even virtual cpus 0, 2, 4,... - * 1 - odd virtual cpus 1, 3, 5, ... - * - * FIXME: this is strictly wrong, we need to clean this up in a number - * of places. It works for now. -arnd - */ -static u32 hdw_thread; - -stat... [truncated message content] |