Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[CELL] oprofile: add support to OProfile for profiling CELL BE SPUs

From: Maynard Johnson <mpjohn@us.ibm.com>

This patch updates the existing arch/powerpc/oprofile/op_model_cell.c
to add in the SPU profiling capabilities. In addition, a 'cell' subdirectory
was added to arch/powerpc/oprofile to hold Cell-specific SPU profiling code.
Exports spu_set_profile_private_kref and spu_get_profile_private_kref which
are used by OProfile to store private profile information in spufs data
structures.

Also incorporated several fixes from other patches (rrn). Check pointer
returned from kzalloc. Eliminated unnecessary cast. Better error
handling and cleanup in the related area. 64-bit unsigned long parameter
was being demoted to 32-bit unsigned int and eventually promoted back to
unsigned long.

Signed-off-by: Carl Love <carll@us.ibm.com>
Signed-off-by: Maynard Johnson <mpjohn@us.ibm.com>
Signed-off-by: Bob Nelson <rrnelson@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Acked-by: Paul Mackerras <paulus@samba.org>

authored by

Bob Nelson and committed by
Arnd Bergmann
1474855d 36aaccc1

+1829 -134
+2 -1
arch/powerpc/configs/cell_defconfig
··· 1455 1455 # Instrumentation Support 1456 1456 # 1457 1457 CONFIG_PROFILING=y 1458 - CONFIG_OPROFILE=y 1458 + CONFIG_OPROFILE=m 1459 + CONFIG_OPROFILE_CELL=y 1459 1460 # CONFIG_KPROBES is not set 1460 1461 1461 1462 #
+1
arch/powerpc/kernel/time.c
··· 122 122 static long timezone_offset; 123 123 124 124 unsigned long ppc_proc_freq; 125 + EXPORT_SYMBOL(ppc_proc_freq); 125 126 unsigned long ppc_tb_freq; 126 127 127 128 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
+7
arch/powerpc/oprofile/Kconfig
··· 15 15 16 16 If unsure, say N. 17 17 18 + config OPROFILE_CELL 19 + bool "OProfile for Cell Broadband Engine" 20 + depends on (SPU_FS = y && OPROFILE = m) || (SPU_FS = y && OPROFILE = y) || (SPU_FS = m && OPROFILE = m) 21 + default y 22 + help 23 + Profiling of Cell BE SPUs requires special support enabled 24 + by this option.
+3 -1
arch/powerpc/oprofile/Makefile
··· 11 11 timer_int.o ) 12 12 13 13 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o 14 - oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o 14 + oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \ 15 + cell/spu_profiler.o cell/vma_map.o \ 16 + cell/spu_task_sync.o 15 17 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o 16 18 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o 17 19 oprofile-$(CONFIG_6xx) += op_model_7450.o
+97
arch/powerpc/oprofile/cell/pr_util.h
··· 1 + /* 2 + * Cell Broadband Engine OProfile Support 3 + * 4 + * (C) Copyright IBM Corporation 2006 5 + * 6 + * Author: Maynard Johnson <maynardj@us.ibm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * as published by the Free Software Foundation; either version 11 + * 2 of the License, or (at your option) any later version. 12 + */ 13 + 14 + #ifndef PR_UTIL_H 15 + #define PR_UTIL_H 16 + 17 + #include <linux/cpumask.h> 18 + #include <linux/oprofile.h> 19 + #include <asm/cell-pmu.h> 20 + #include <asm/spu.h> 21 + 22 + #include "../../platforms/cell/cbe_regs.h" 23 + 24 + /* Defines used for sync_start */ 25 + #define SKIP_GENERIC_SYNC 0 26 + #define SYNC_START_ERROR -1 27 + #define DO_GENERIC_SYNC 1 28 + 29 + struct spu_overlay_info { /* map of sections within an SPU overlay */ 30 + unsigned int vma; /* SPU virtual memory address from elf */ 31 + unsigned int size; /* size of section from elf */ 32 + unsigned int offset; /* offset of section into elf file */ 33 + unsigned int buf; 34 + }; 35 + 36 + struct vma_to_fileoffset_map { /* map of sections within an SPU program */ 37 + struct vma_to_fileoffset_map *next; /* list pointer */ 38 + unsigned int vma; /* SPU virtual memory address from elf */ 39 + unsigned int size; /* size of section from elf */ 40 + unsigned int offset; /* offset of section into elf file */ 41 + unsigned int guard_ptr; 42 + unsigned int guard_val; 43 + /* 44 + * The guard pointer is an entry in the _ovly_buf_table, 45 + * computed using ovly.buf as the index into the table. Since 46 + * ovly.buf values begin at '1' to reference the first (or 0th) 47 + * entry in the _ovly_buf_table, the computation subtracts 1 48 + * from ovly.buf. 49 + * The guard value is stored in the _ovly_buf_table entry and 50 + * is an index (starting at 1) back to the _ovly_table entry 51 + * that is pointing at this _ovly_buf_table entry. So, for 52 + * example, for an overlay scenario with one overlay segment 53 + * and two overlay sections: 54 + * - Section 1 points to the first entry of the 55 + * _ovly_buf_table, which contains a guard value 56 + * of '1', referencing the first (index=0) entry of 57 + * _ovly_table. 58 + * - Section 2 points to the second entry of the 59 + * _ovly_buf_table, which contains a guard value 60 + * of '2', referencing the second (index=1) entry of 61 + * _ovly_table. 62 + */ 63 + 64 + }; 65 + 66 + /* The three functions below are for maintaining and accessing 67 + * the vma-to-fileoffset map. 68 + */ 69 + struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu, 70 + u64 objectid); 71 + unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map, 72 + unsigned int vma, const struct spu *aSpu, 73 + int *grd_val); 74 + void vma_map_free(struct vma_to_fileoffset_map *map); 75 + 76 + /* 77 + * Entry point for SPU profiling. 78 + * cycles_reset is the SPU_CYCLES count value specified by the user. 79 + */ 80 + int start_spu_profiling(unsigned int cycles_reset); 81 + 82 + void stop_spu_profiling(void); 83 + 84 + 85 + /* add the necessary profiling hooks */ 86 + int spu_sync_start(void); 87 + 88 + /* remove the hooks */ 89 + int spu_sync_stop(void); 90 + 91 + /* Record SPU program counter samples to the oprofile event buffer. */ 92 + void spu_sync_buffer(int spu_num, unsigned int *samples, 93 + int num_samples); 94 + 95 + void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset); 96 + 97 + #endif /* PR_UTIL_H */
+221
arch/powerpc/oprofile/cell/spu_profiler.c
··· 1 + /* 2 + * Cell Broadband Engine OProfile Support 3 + * 4 + * (C) Copyright IBM Corporation 2006 5 + * 6 + * Authors: Maynard Johnson <maynardj@us.ibm.com> 7 + * Carl Love <carll@us.ibm.com> 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License 11 + * as published by the Free Software Foundation; either version 12 + * 2 of the License, or (at your option) any later version. 13 + */ 14 + 15 + #include <linux/hrtimer.h> 16 + #include <linux/smp.h> 17 + #include <linux/slab.h> 18 + #include <asm/cell-pmu.h> 19 + #include "pr_util.h" 20 + 21 + #define TRACE_ARRAY_SIZE 1024 22 + #define SCALE_SHIFT 14 23 + 24 + static u32 *samples; 25 + 26 + static int spu_prof_running; 27 + static unsigned int profiling_interval; 28 + 29 + #define NUM_SPU_BITS_TRBUF 16 30 + #define SPUS_PER_TB_ENTRY 4 31 + #define SPUS_PER_NODE 8 32 + 33 + #define SPU_PC_MASK 0xFFFF 34 + 35 + static DEFINE_SPINLOCK(sample_array_lock); 36 + unsigned long sample_array_lock_flags; 37 + 38 + void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset) 39 + { 40 + unsigned long ns_per_cyc; 41 + 42 + if (!freq_khz) 43 + freq_khz = ppc_proc_freq/1000; 44 + 45 + /* To calculate a timeout in nanoseconds, the basic 46 + * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency). 47 + * To avoid floating point math, we use the scale math 48 + * technique as described in linux/jiffies.h. We use 49 + * a scale factor of SCALE_SHIFT, which provides 4 decimal places 50 + * of precision. This is close enough for the purpose at hand. 51 + * 52 + * The value of the timeout should be small enough that the hw 53 + * trace buffer will not get more then about 1/3 full for the 54 + * maximum user specified (the LFSR value) hw sampling frequency. 55 + * This is to ensure the trace buffer will never fill even if the 56 + * kernel thread scheduling varies under a heavy system load. 57 + */ 58 + 59 + ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz; 60 + profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT; 61 + 62 + } 63 + 64 + /* 65 + * Extract SPU PC from trace buffer entry 66 + */ 67 + static void spu_pc_extract(int cpu, int entry) 68 + { 69 + /* the trace buffer is 128 bits */ 70 + u64 trace_buffer[2]; 71 + u64 spu_mask; 72 + int spu; 73 + 74 + spu_mask = SPU_PC_MASK; 75 + 76 + /* Each SPU PC is 16 bits; hence, four spus in each of 77 + * the two 64-bit buffer entries that make up the 78 + * 128-bit trace_buffer entry. Process two 64-bit values 79 + * simultaneously. 80 + * trace[0] SPU PC contents are: 0 1 2 3 81 + * trace[1] SPU PC contents are: 4 5 6 7 82 + */ 83 + 84 + cbe_read_trace_buffer(cpu, trace_buffer); 85 + 86 + for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) { 87 + /* spu PC trace entry is upper 16 bits of the 88 + * 18 bit SPU program counter 89 + */ 90 + samples[spu * TRACE_ARRAY_SIZE + entry] 91 + = (spu_mask & trace_buffer[0]) << 2; 92 + samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry] 93 + = (spu_mask & trace_buffer[1]) << 2; 94 + 95 + trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF; 96 + trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF; 97 + } 98 + } 99 + 100 + static int cell_spu_pc_collection(int cpu) 101 + { 102 + u32 trace_addr; 103 + int entry; 104 + 105 + /* process the collected SPU PC for the node */ 106 + 107 + entry = 0; 108 + 109 + trace_addr = cbe_read_pm(cpu, trace_address); 110 + while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) { 111 + /* there is data in the trace buffer to process */ 112 + spu_pc_extract(cpu, entry); 113 + 114 + entry++; 115 + 116 + if (entry >= TRACE_ARRAY_SIZE) 117 + /* spu_samples is full */ 118 + break; 119 + 120 + trace_addr = cbe_read_pm(cpu, trace_address); 121 + } 122 + 123 + return entry; 124 + } 125 + 126 + 127 + static enum hrtimer_restart profile_spus(struct hrtimer *timer) 128 + { 129 + ktime_t kt; 130 + int cpu, node, k, num_samples, spu_num; 131 + 132 + if (!spu_prof_running) 133 + goto stop; 134 + 135 + for_each_online_cpu(cpu) { 136 + if (cbe_get_hw_thread_id(cpu)) 137 + continue; 138 + 139 + node = cbe_cpu_to_node(cpu); 140 + 141 + /* There should only be one kernel thread at a time processing 142 + * the samples. In the very unlikely case that the processing 143 + * is taking a very long time and multiple kernel threads are 144 + * started to process the samples. Make sure only one kernel 145 + * thread is working on the samples array at a time. The 146 + * sample array must be loaded and then processed for a given 147 + * cpu. The sample array is not per cpu. 148 + */ 149 + spin_lock_irqsave(&sample_array_lock, 150 + sample_array_lock_flags); 151 + num_samples = cell_spu_pc_collection(cpu); 152 + 153 + if (num_samples == 0) { 154 + spin_unlock_irqrestore(&sample_array_lock, 155 + sample_array_lock_flags); 156 + continue; 157 + } 158 + 159 + for (k = 0; k < SPUS_PER_NODE; k++) { 160 + spu_num = k + (node * SPUS_PER_NODE); 161 + spu_sync_buffer(spu_num, 162 + samples + (k * TRACE_ARRAY_SIZE), 163 + num_samples); 164 + } 165 + 166 + spin_unlock_irqrestore(&sample_array_lock, 167 + sample_array_lock_flags); 168 + 169 + } 170 + smp_wmb(); /* insure spu event buffer updates are written */ 171 + /* don't want events intermingled... */ 172 + 173 + kt = ktime_set(0, profiling_interval); 174 + if (!spu_prof_running) 175 + goto stop; 176 + hrtimer_forward(timer, timer->base->get_time(), kt); 177 + return HRTIMER_RESTART; 178 + 179 + stop: 180 + printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n"); 181 + return HRTIMER_NORESTART; 182 + } 183 + 184 + static struct hrtimer timer; 185 + /* 186 + * Entry point for SPU profiling. 187 + * NOTE: SPU profiling is done system-wide, not per-CPU. 188 + * 189 + * cycles_reset is the count value specified by the user when 190 + * setting up OProfile to count SPU_CYCLES. 191 + */ 192 + int start_spu_profiling(unsigned int cycles_reset) 193 + { 194 + ktime_t kt; 195 + 196 + pr_debug("timer resolution: %lu\n", TICK_NSEC); 197 + kt = ktime_set(0, profiling_interval); 198 + hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 199 + timer.expires = kt; 200 + timer.function = profile_spus; 201 + 202 + /* Allocate arrays for collecting SPU PC samples */ 203 + samples = kzalloc(SPUS_PER_NODE * 204 + TRACE_ARRAY_SIZE * sizeof(u32), GFP_KERNEL); 205 + 206 + if (!samples) 207 + return -ENOMEM; 208 + 209 + spu_prof_running = 1; 210 + hrtimer_start(&timer, kt, HRTIMER_MODE_REL); 211 + 212 + return 0; 213 + } 214 + 215 + void stop_spu_profiling(void) 216 + { 217 + spu_prof_running = 0; 218 + hrtimer_cancel(&timer); 219 + kfree(samples); 220 + pr_debug("SPU_PROF: stop_spu_profiling issued\n"); 221 + }
+484
arch/powerpc/oprofile/cell/spu_task_sync.c
··· 1 + /* 2 + * Cell Broadband Engine OProfile Support 3 + * 4 + * (C) Copyright IBM Corporation 2006 5 + * 6 + * Author: Maynard Johnson <maynardj@us.ibm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * as published by the Free Software Foundation; either version 11 + * 2 of the License, or (at your option) any later version. 12 + */ 13 + 14 + /* The purpose of this file is to handle SPU event task switching 15 + * and to record SPU context information into the OProfile 16 + * event buffer. 17 + * 18 + * Additionally, the spu_sync_buffer function is provided as a helper 19 + * for recoding actual SPU program counter samples to the event buffer. 20 + */ 21 + #include <linux/dcookies.h> 22 + #include <linux/kref.h> 23 + #include <linux/mm.h> 24 + #include <linux/module.h> 25 + #include <linux/notifier.h> 26 + #include <linux/numa.h> 27 + #include <linux/oprofile.h> 28 + #include <linux/spinlock.h> 29 + #include "pr_util.h" 30 + 31 + #define RELEASE_ALL 9999 32 + 33 + static DEFINE_SPINLOCK(buffer_lock); 34 + static DEFINE_SPINLOCK(cache_lock); 35 + static int num_spu_nodes; 36 + int spu_prof_num_nodes; 37 + int last_guard_val[MAX_NUMNODES * 8]; 38 + 39 + /* Container for caching information about an active SPU task. */ 40 + struct cached_info { 41 + struct vma_to_fileoffset_map *map; 42 + struct spu *the_spu; /* needed to access pointer to local_store */ 43 + struct kref cache_ref; 44 + }; 45 + 46 + static struct cached_info *spu_info[MAX_NUMNODES * 8]; 47 + 48 + static void destroy_cached_info(struct kref *kref) 49 + { 50 + struct cached_info *info; 51 + 52 + info = container_of(kref, struct cached_info, cache_ref); 53 + vma_map_free(info->map); 54 + kfree(info); 55 + module_put(THIS_MODULE); 56 + } 57 + 58 + /* Return the cached_info for the passed SPU number. 59 + * ATTENTION: Callers are responsible for obtaining the 60 + * cache_lock if needed prior to invoking this function. 61 + */ 62 + static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num) 63 + { 64 + struct kref *ref; 65 + struct cached_info *ret_info; 66 + 67 + if (spu_num >= num_spu_nodes) { 68 + printk(KERN_ERR "SPU_PROF: " 69 + "%s, line %d: Invalid index %d into spu info cache\n", 70 + __FUNCTION__, __LINE__, spu_num); 71 + ret_info = NULL; 72 + goto out; 73 + } 74 + if (!spu_info[spu_num] && the_spu) { 75 + ref = spu_get_profile_private_kref(the_spu->ctx); 76 + if (ref) { 77 + spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref); 78 + kref_get(&spu_info[spu_num]->cache_ref); 79 + } 80 + } 81 + 82 + ret_info = spu_info[spu_num]; 83 + out: 84 + return ret_info; 85 + } 86 + 87 + 88 + /* Looks for cached info for the passed spu. If not found, the 89 + * cached info is created for the passed spu. 90 + * Returns 0 for success; otherwise, -1 for error. 91 + */ 92 + static int 93 + prepare_cached_spu_info(struct spu *spu, unsigned long objectId) 94 + { 95 + unsigned long flags; 96 + struct vma_to_fileoffset_map *new_map; 97 + int retval = 0; 98 + struct cached_info *info; 99 + 100 + /* We won't bother getting cache_lock here since 101 + * don't do anything with the cached_info that's returned. 102 + */ 103 + info = get_cached_info(spu, spu->number); 104 + 105 + if (info) { 106 + pr_debug("Found cached SPU info.\n"); 107 + goto out; 108 + } 109 + 110 + /* Create cached_info and set spu_info[spu->number] to point to it. 111 + * spu->number is a system-wide value, not a per-node value. 112 + */ 113 + info = kzalloc(sizeof(struct cached_info), GFP_KERNEL); 114 + if (!info) { 115 + printk(KERN_ERR "SPU_PROF: " 116 + "%s, line %d: create vma_map failed\n", 117 + __FUNCTION__, __LINE__); 118 + retval = -ENOMEM; 119 + goto err_alloc; 120 + } 121 + new_map = create_vma_map(spu, objectId); 122 + if (!new_map) { 123 + printk(KERN_ERR "SPU_PROF: " 124 + "%s, line %d: create vma_map failed\n", 125 + __FUNCTION__, __LINE__); 126 + retval = -ENOMEM; 127 + goto err_alloc; 128 + } 129 + 130 + pr_debug("Created vma_map\n"); 131 + info->map = new_map; 132 + info->the_spu = spu; 133 + kref_init(&info->cache_ref); 134 + spin_lock_irqsave(&cache_lock, flags); 135 + spu_info[spu->number] = info; 136 + /* Increment count before passing off ref to SPUFS. */ 137 + kref_get(&info->cache_ref); 138 + 139 + /* We increment the module refcount here since SPUFS is 140 + * responsible for the final destruction of the cached_info, 141 + * and it must be able to access the destroy_cached_info() 142 + * function defined in the OProfile module. We decrement 143 + * the module refcount in destroy_cached_info. 144 + */ 145 + try_module_get(THIS_MODULE); 146 + spu_set_profile_private_kref(spu->ctx, &info->cache_ref, 147 + destroy_cached_info); 148 + spin_unlock_irqrestore(&cache_lock, flags); 149 + goto out; 150 + 151 + err_alloc: 152 + kfree(info); 153 + out: 154 + return retval; 155 + } 156 + 157 + /* 158 + * NOTE: The caller is responsible for locking the 159 + * cache_lock prior to calling this function. 160 + */ 161 + static int release_cached_info(int spu_index) 162 + { 163 + int index, end; 164 + 165 + if (spu_index == RELEASE_ALL) { 166 + end = num_spu_nodes; 167 + index = 0; 168 + } else { 169 + if (spu_index >= num_spu_nodes) { 170 + printk(KERN_ERR "SPU_PROF: " 171 + "%s, line %d: " 172 + "Invalid index %d into spu info cache\n", 173 + __FUNCTION__, __LINE__, spu_index); 174 + goto out; 175 + } 176 + end = spu_index + 1; 177 + index = spu_index; 178 + } 179 + for (; index < end; index++) { 180 + if (spu_info[index]) { 181 + kref_put(&spu_info[index]->cache_ref, 182 + destroy_cached_info); 183 + spu_info[index] = NULL; 184 + } 185 + } 186 + 187 + out: 188 + return 0; 189 + } 190 + 191 + /* The source code for fast_get_dcookie was "borrowed" 192 + * from drivers/oprofile/buffer_sync.c. 193 + */ 194 + 195 + /* Optimisation. We can manage without taking the dcookie sem 196 + * because we cannot reach this code without at least one 197 + * dcookie user still being registered (namely, the reader 198 + * of the event buffer). 199 + */ 200 + static inline unsigned long fast_get_dcookie(struct dentry *dentry, 201 + struct vfsmount *vfsmnt) 202 + { 203 + unsigned long cookie; 204 + 205 + if (dentry->d_cookie) 206 + return (unsigned long)dentry; 207 + get_dcookie(dentry, vfsmnt, &cookie); 208 + return cookie; 209 + } 210 + 211 + /* Look up the dcookie for the task's first VM_EXECUTABLE mapping, 212 + * which corresponds loosely to "application name". Also, determine 213 + * the offset for the SPU ELF object. If computed offset is 214 + * non-zero, it implies an embedded SPU object; otherwise, it's a 215 + * separate SPU binary, in which case we retrieve it's dcookie. 216 + * For the embedded case, we must determine if SPU ELF is embedded 217 + * in the executable application or another file (i.e., shared lib). 218 + * If embedded in a shared lib, we must get the dcookie and return 219 + * that to the caller. 220 + */ 221 + static unsigned long 222 + get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp, 223 + unsigned long *spu_bin_dcookie, 224 + unsigned long spu_ref) 225 + { 226 + unsigned long app_cookie = 0; 227 + unsigned int my_offset = 0; 228 + struct file *app = NULL; 229 + struct vm_area_struct *vma; 230 + struct mm_struct *mm = spu->mm; 231 + 232 + if (!mm) 233 + goto out; 234 + 235 + down_read(&mm->mmap_sem); 236 + 237 + for (vma = mm->mmap; vma; vma = vma->vm_next) { 238 + if (!vma->vm_file) 239 + continue; 240 + if (!(vma->vm_flags & VM_EXECUTABLE)) 241 + continue; 242 + app_cookie = fast_get_dcookie(vma->vm_file->f_dentry, 243 + vma->vm_file->f_vfsmnt); 244 + pr_debug("got dcookie for %s\n", 245 + vma->vm_file->f_dentry->d_name.name); 246 + app = vma->vm_file; 247 + break; 248 + } 249 + 250 + for (vma = mm->mmap; vma; vma = vma->vm_next) { 251 + if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref) 252 + continue; 253 + my_offset = spu_ref - vma->vm_start; 254 + if (!vma->vm_file) 255 + goto fail_no_image_cookie; 256 + 257 + pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n", 258 + my_offset, spu_ref, 259 + vma->vm_file->f_dentry->d_name.name); 260 + *offsetp = my_offset; 261 + break; 262 + } 263 + 264 + *spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry, 265 + vma->vm_file->f_vfsmnt); 266 + pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name); 267 + 268 + up_read(&mm->mmap_sem); 269 + 270 + out: 271 + return app_cookie; 272 + 273 + fail_no_image_cookie: 274 + up_read(&mm->mmap_sem); 275 + 276 + printk(KERN_ERR "SPU_PROF: " 277 + "%s, line %d: Cannot find dcookie for SPU binary\n", 278 + __FUNCTION__, __LINE__); 279 + goto out; 280 + } 281 + 282 + 283 + 284 + /* This function finds or creates cached context information for the 285 + * passed SPU and records SPU context information into the OProfile 286 + * event buffer. 287 + */ 288 + static int process_context_switch(struct spu *spu, unsigned long objectId) 289 + { 290 + unsigned long flags; 291 + int retval; 292 + unsigned int offset = 0; 293 + unsigned long spu_cookie = 0, app_dcookie; 294 + 295 + retval = prepare_cached_spu_info(spu, objectId); 296 + if (retval) 297 + goto out; 298 + 299 + /* Get dcookie first because a mutex_lock is taken in that 300 + * code path, so interrupts must not be disabled. 301 + */ 302 + app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId); 303 + if (!app_dcookie || !spu_cookie) { 304 + retval = -ENOENT; 305 + goto out; 306 + } 307 + 308 + /* Record context info in event buffer */ 309 + spin_lock_irqsave(&buffer_lock, flags); 310 + add_event_entry(ESCAPE_CODE); 311 + add_event_entry(SPU_CTX_SWITCH_CODE); 312 + add_event_entry(spu->number); 313 + add_event_entry(spu->pid); 314 + add_event_entry(spu->tgid); 315 + add_event_entry(app_dcookie); 316 + add_event_entry(spu_cookie); 317 + add_event_entry(offset); 318 + spin_unlock_irqrestore(&buffer_lock, flags); 319 + smp_wmb(); /* insure spu event buffer updates are written */ 320 + /* don't want entries intermingled... */ 321 + out: 322 + return retval; 323 + } 324 + 325 + /* 326 + * This function is invoked on either a bind_context or unbind_context. 327 + * If called for an unbind_context, the val arg is 0; otherwise, 328 + * it is the object-id value for the spu context. 329 + * The data arg is of type 'struct spu *'. 330 + */ 331 + static int spu_active_notify(struct notifier_block *self, unsigned long val, 332 + void *data) 333 + { 334 + int retval; 335 + unsigned long flags; 336 + struct spu *the_spu = data; 337 + 338 + pr_debug("SPU event notification arrived\n"); 339 + if (!val) { 340 + spin_lock_irqsave(&cache_lock, flags); 341 + retval = release_cached_info(the_spu->number); 342 + spin_unlock_irqrestore(&cache_lock, flags); 343 + } else { 344 + retval = process_context_switch(the_spu, val); 345 + } 346 + return retval; 347 + } 348 + 349 + static struct notifier_block spu_active = { 350 + .notifier_call = spu_active_notify, 351 + }; 352 + 353 + static int number_of_online_nodes(void) 354 + { 355 + u32 cpu; u32 tmp; 356 + int nodes = 0; 357 + for_each_online_cpu(cpu) { 358 + tmp = cbe_cpu_to_node(cpu) + 1; 359 + if (tmp > nodes) 360 + nodes++; 361 + } 362 + return nodes; 363 + } 364 + 365 + /* The main purpose of this function is to synchronize 366 + * OProfile with SPUFS by registering to be notified of 367 + * SPU task switches. 368 + * 369 + * NOTE: When profiling SPUs, we must ensure that only 370 + * spu_sync_start is invoked and not the generic sync_start 371 + * in drivers/oprofile/oprof.c. A return value of 372 + * SKIP_GENERIC_SYNC or SYNC_START_ERROR will 373 + * accomplish this. 374 + */ 375 + int spu_sync_start(void) 376 + { 377 + int k; 378 + int ret = SKIP_GENERIC_SYNC; 379 + int register_ret; 380 + unsigned long flags = 0; 381 + 382 + spu_prof_num_nodes = number_of_online_nodes(); 383 + num_spu_nodes = spu_prof_num_nodes * 8; 384 + 385 + spin_lock_irqsave(&buffer_lock, flags); 386 + add_event_entry(ESCAPE_CODE); 387 + add_event_entry(SPU_PROFILING_CODE); 388 + add_event_entry(num_spu_nodes); 389 + spin_unlock_irqrestore(&buffer_lock, flags); 390 + 391 + /* Register for SPU events */ 392 + register_ret = spu_switch_event_register(&spu_active); 393 + if (register_ret) { 394 + ret = SYNC_START_ERROR; 395 + goto out; 396 + } 397 + 398 + for (k = 0; k < (MAX_NUMNODES * 8); k++) 399 + last_guard_val[k] = 0; 400 + pr_debug("spu_sync_start -- running.\n"); 401 + out: 402 + return ret; 403 + } 404 + 405 + /* Record SPU program counter samples to the oprofile event buffer. */ 406 + void spu_sync_buffer(int spu_num, unsigned int *samples, 407 + int num_samples) 408 + { 409 + unsigned long long file_offset; 410 + unsigned long flags; 411 + int i; 412 + struct vma_to_fileoffset_map *map; 413 + struct spu *the_spu; 414 + unsigned long long spu_num_ll = spu_num; 415 + unsigned long long spu_num_shifted = spu_num_ll << 32; 416 + struct cached_info *c_info; 417 + 418 + /* We need to obtain the cache_lock here because it's 419 + * possible that after getting the cached_info, the SPU job 420 + * corresponding to this cached_info may end, thus resulting 421 + * in the destruction of the cached_info. 422 + */ 423 + spin_lock_irqsave(&cache_lock, flags); 424 + c_info = get_cached_info(NULL, spu_num); 425 + if (!c_info) { 426 + /* This legitimately happens when the SPU task ends before all 427 + * samples are recorded. 428 + * No big deal -- so we just drop a few samples. 429 + */ 430 + pr_debug("SPU_PROF: No cached SPU contex " 431 + "for SPU #%d. Dropping samples.\n", spu_num); 432 + goto out; 433 + } 434 + 435 + map = c_info->map; 436 + the_spu = c_info->the_spu; 437 + spin_lock(&buffer_lock); 438 + for (i = 0; i < num_samples; i++) { 439 + unsigned int sample = *(samples+i); 440 + int grd_val = 0; 441 + file_offset = 0; 442 + if (sample == 0) 443 + continue; 444 + file_offset = vma_map_lookup( map, sample, the_spu, &grd_val); 445 + 446 + /* If overlays are used by this SPU application, the guard 447 + * value is non-zero, indicating which overlay section is in 448 + * use. We need to discard samples taken during the time 449 + * period which an overlay occurs (i.e., guard value changes). 450 + */ 451 + if (grd_val && grd_val != last_guard_val[spu_num]) { 452 + last_guard_val[spu_num] = grd_val; 453 + /* Drop the rest of the samples. */ 454 + break; 455 + } 456 + 457 + add_event_entry(file_offset | spu_num_shifted); 458 + } 459 + spin_unlock(&buffer_lock); 460 + out: 461 + spin_unlock_irqrestore(&cache_lock, flags); 462 + } 463 + 464 + 465 + int spu_sync_stop(void) 466 + { 467 + unsigned long flags = 0; 468 + int ret = spu_switch_event_unregister(&spu_active); 469 + if (ret) { 470 + printk(KERN_ERR "SPU_PROF: " 471 + "%s, line %d: spu_switch_event_unregister returned %d\n", 472 + __FUNCTION__, __LINE__, ret); 473 + goto out; 474 + } 475 + 476 + spin_lock_irqsave(&cache_lock, flags); 477 + ret = release_cached_info(RELEASE_ALL); 478 + spin_unlock_irqrestore(&cache_lock, flags); 479 + out: 480 + pr_debug("spu_sync_stop -- done.\n"); 481 + return ret; 482 + } 483 + 484 +
+287
arch/powerpc/oprofile/cell/vma_map.c
··· 1 + /* 2 + * Cell Broadband Engine OProfile Support 3 + * 4 + * (C) Copyright IBM Corporation 2006 5 + * 6 + * Author: Maynard Johnson <maynardj@us.ibm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * as published by the Free Software Foundation; either version 11 + * 2 of the License, or (at your option) any later version. 12 + */ 13 + 14 + /* The code in this source file is responsible for generating 15 + * vma-to-fileOffset maps for both overlay and non-overlay SPU 16 + * applications. 17 + */ 18 + 19 + #include <linux/mm.h> 20 + #include <linux/string.h> 21 + #include <linux/uaccess.h> 22 + #include <linux/elf.h> 23 + #include "pr_util.h" 24 + 25 + 26 + void vma_map_free(struct vma_to_fileoffset_map *map) 27 + { 28 + while (map) { 29 + struct vma_to_fileoffset_map *next = map->next; 30 + kfree(map); 31 + map = next; 32 + } 33 + } 34 + 35 + unsigned int 36 + vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma, 37 + const struct spu *aSpu, int *grd_val) 38 + { 39 + /* 40 + * Default the offset to the physical address + a flag value. 41 + * Addresses of dynamically generated code can't be found in the vma 42 + * map. For those addresses the flagged value will be sent on to 43 + * the user space tools so they can be reported rather than just 44 + * thrown away. 45 + */ 46 + u32 offset = 0x10000000 + vma; 47 + u32 ovly_grd; 48 + 49 + for (; map; map = map->next) { 50 + if (vma < map->vma || vma >= map->vma + map->size) 51 + continue; 52 + 53 + if (map->guard_ptr) { 54 + ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr); 55 + if (ovly_grd != map->guard_val) 56 + continue; 57 + *grd_val = ovly_grd; 58 + } 59 + offset = vma - map->vma + map->offset; 60 + break; 61 + } 62 + 63 + return offset; 64 + } 65 + 66 + static struct vma_to_fileoffset_map * 67 + vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma, 68 + unsigned int size, unsigned int offset, unsigned int guard_ptr, 69 + unsigned int guard_val) 70 + { 71 + struct vma_to_fileoffset_map *new = 72 + kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL); 73 + if (!new) { 74 + printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n", 75 + __FUNCTION__, __LINE__); 76 + vma_map_free(map); 77 + return NULL; 78 + } 79 + 80 + new->next = map; 81 + new->vma = vma; 82 + new->size = size; 83 + new->offset = offset; 84 + new->guard_ptr = guard_ptr; 85 + new->guard_val = guard_val; 86 + 87 + return new; 88 + } 89 + 90 + 91 + /* Parse SPE ELF header and generate a list of vma_maps. 92 + * A pointer to the first vma_map in the generated list 93 + * of vma_maps is returned. */ 94 + struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu, 95 + unsigned long spu_elf_start) 96 + { 97 + static const unsigned char expected[EI_PAD] = { 98 + [EI_MAG0] = ELFMAG0, 99 + [EI_MAG1] = ELFMAG1, 100 + [EI_MAG2] = ELFMAG2, 101 + [EI_MAG3] = ELFMAG3, 102 + [EI_CLASS] = ELFCLASS32, 103 + [EI_DATA] = ELFDATA2MSB, 104 + [EI_VERSION] = EV_CURRENT, 105 + [EI_OSABI] = ELFOSABI_NONE 106 + }; 107 + 108 + int grd_val; 109 + struct vma_to_fileoffset_map *map = NULL; 110 + struct spu_overlay_info ovly; 111 + unsigned int overlay_tbl_offset = -1; 112 + unsigned long phdr_start, shdr_start; 113 + Elf32_Ehdr ehdr; 114 + Elf32_Phdr phdr; 115 + Elf32_Shdr shdr, shdr_str; 116 + Elf32_Sym sym; 117 + int i, j; 118 + char name[32]; 119 + 120 + unsigned int ovly_table_sym = 0; 121 + unsigned int ovly_buf_table_sym = 0; 122 + unsigned int ovly_table_end_sym = 0; 123 + unsigned int ovly_buf_table_end_sym = 0; 124 + unsigned long ovly_table; 125 + unsigned int n_ovlys; 126 + 127 + /* Get and validate ELF header. */ 128 + 129 + if (copy_from_user(&ehdr, (void *) spu_elf_start, sizeof (ehdr))) 130 + goto fail; 131 + 132 + if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) { 133 + printk(KERN_ERR "SPU_PROF: " 134 + "%s, line %d: Unexpected e_ident parsing SPU ELF\n", 135 + __FUNCTION__, __LINE__); 136 + goto fail; 137 + } 138 + if (ehdr.e_machine != EM_SPU) { 139 + printk(KERN_ERR "SPU_PROF: " 140 + "%s, line %d: Unexpected e_machine parsing SPU ELF\n", 141 + __FUNCTION__, __LINE__); 142 + goto fail; 143 + } 144 + if (ehdr.e_type != ET_EXEC) { 145 + printk(KERN_ERR "SPU_PROF: " 146 + "%s, line %d: Unexpected e_type parsing SPU ELF\n", 147 + __FUNCTION__, __LINE__); 148 + goto fail; 149 + } 150 + phdr_start = spu_elf_start + ehdr.e_phoff; 151 + shdr_start = spu_elf_start + ehdr.e_shoff; 152 + 153 + /* Traverse program headers. */ 154 + for (i = 0; i < ehdr.e_phnum; i++) { 155 + if (copy_from_user(&phdr, 156 + (void *) (phdr_start + i * sizeof(phdr)), 157 + sizeof(phdr))) 158 + goto fail; 159 + 160 + if (phdr.p_type != PT_LOAD) 161 + continue; 162 + if (phdr.p_flags & (1 << 27)) 163 + continue; 164 + 165 + map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz, 166 + phdr.p_offset, 0, 0); 167 + if (!map) 168 + goto fail; 169 + } 170 + 171 + pr_debug("SPU_PROF: Created non-overlay maps\n"); 172 + /* Traverse section table and search for overlay-related symbols. */ 173 + for (i = 0; i < ehdr.e_shnum; i++) { 174 + if (copy_from_user(&shdr, 175 + (void *) (shdr_start + i * sizeof(shdr)), 176 + sizeof(shdr))) 177 + goto fail; 178 + 179 + if (shdr.sh_type != SHT_SYMTAB) 180 + continue; 181 + if (shdr.sh_entsize != sizeof (sym)) 182 + continue; 183 + 184 + if (copy_from_user(&shdr_str, 185 + (void *) (shdr_start + shdr.sh_link * 186 + sizeof(shdr)), 187 + sizeof(shdr))) 188 + goto fail; 189 + 190 + if (shdr_str.sh_type != SHT_STRTAB) 191 + goto fail;; 192 + 193 + for (j = 0; j < shdr.sh_size / sizeof (sym); j++) { 194 + if (copy_from_user(&sym, (void *) (spu_elf_start + 195 + shdr.sh_offset + j * 196 + sizeof (sym)), 197 + sizeof (sym))) 198 + goto fail; 199 + 200 + if (copy_from_user(name, (void *) 201 + (spu_elf_start + shdr_str.sh_offset + 202 + sym.st_name), 203 + 20)) 204 + goto fail; 205 + 206 + if (memcmp(name, "_ovly_table", 12) == 0) 207 + ovly_table_sym = sym.st_value; 208 + if (memcmp(name, "_ovly_buf_table", 16) == 0) 209 + ovly_buf_table_sym = sym.st_value; 210 + if (memcmp(name, "_ovly_table_end", 16) == 0) 211 + ovly_table_end_sym = sym.st_value; 212 + if (memcmp(name, "_ovly_buf_table_end", 20) == 0) 213 + ovly_buf_table_end_sym = sym.st_value; 214 + } 215 + } 216 + 217 + /* If we don't have overlays, we're done. */ 218 + if (ovly_table_sym == 0 || ovly_buf_table_sym == 0 219 + || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) { 220 + pr_debug("SPU_PROF: No overlay table found\n"); 221 + goto out; 222 + } else { 223 + pr_debug("SPU_PROF: Overlay table found\n"); 224 + } 225 + 226 + /* The _ovly_table symbol represents a table with one entry 227 + * per overlay section. The _ovly_buf_table symbol represents 228 + * a table with one entry per overlay region. 229 + * The struct spu_overlay_info gives the structure of the _ovly_table 230 + * entries. The structure of _ovly_table_buf is simply one 231 + * u32 word per entry. 232 + */ 233 + overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym, 234 + aSpu, &grd_val); 235 + if (overlay_tbl_offset < 0) { 236 + printk(KERN_ERR "SPU_PROF: " 237 + "%s, line %d: Error finding SPU overlay table\n", 238 + __FUNCTION__, __LINE__); 239 + goto fail; 240 + } 241 + ovly_table = spu_elf_start + overlay_tbl_offset; 242 + 243 + n_ovlys = (ovly_table_end_sym - 244 + ovly_table_sym) / sizeof (ovly); 245 + 246 + /* Traverse overlay table. */ 247 + for (i = 0; i < n_ovlys; i++) { 248 + if (copy_from_user(&ovly, (void *) 249 + (ovly_table + i * sizeof (ovly)), 250 + sizeof (ovly))) 251 + goto fail; 252 + 253 + /* The ovly.vma/size/offset arguments are analogous to the same 254 + * arguments used above for non-overlay maps. The final two 255 + * args are referred to as the guard pointer and the guard 256 + * value. 257 + * The guard pointer is an entry in the _ovly_buf_table, 258 + * computed using ovly.buf as the index into the table. Since 259 + * ovly.buf values begin at '1' to reference the first (or 0th) 260 + * entry in the _ovly_buf_table, the computation subtracts 1 261 + * from ovly.buf. 262 + * The guard value is stored in the _ovly_buf_table entry and 263 + * is an index (starting at 1) back to the _ovly_table entry 264 + * that is pointing at this _ovly_buf_table entry. So, for 265 + * example, for an overlay scenario with one overlay segment 266 + * and two overlay sections: 267 + * - Section 1 points to the first entry of the 268 + * _ovly_buf_table, which contains a guard value 269 + * of '1', referencing the first (index=0) entry of 270 + * _ovly_table. 271 + * - Section 2 points to the second entry of the 272 + * _ovly_buf_table, which contains a guard value 273 + * of '2', referencing the second (index=1) entry of 274 + * _ovly_table. 275 + */ 276 + map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset, 277 + ovly_buf_table_sym + (ovly.buf-1) * 4, i+1); 278 + if (!map) 279 + goto fail; 280 + } 281 + goto out; 282 + 283 + fail: 284 + map = NULL; 285 + out: 286 + return map; 287 + }
+42 -9
arch/powerpc/oprofile/common.c
··· 29 29 static struct op_counter_config ctr[OP_MAX_COUNTER]; 30 30 static struct op_system_config sys; 31 31 32 + static int op_per_cpu_rc; 33 + 32 34 static void op_handle_interrupt(struct pt_regs *regs) 33 35 { 34 36 model->handle_interrupt(regs, ctr); ··· 38 36 39 37 static void op_powerpc_cpu_setup(void *dummy) 40 38 { 41 - model->cpu_setup(ctr); 39 + int ret; 40 + 41 + ret = model->cpu_setup(ctr); 42 + 43 + if (ret != 0) 44 + op_per_cpu_rc = ret; 42 45 } 43 46 44 47 static int op_powerpc_setup(void) 45 48 { 46 49 int err; 50 + 51 + op_per_cpu_rc = 0; 47 52 48 53 /* Grab the hardware */ 49 54 err = reserve_pmc_hardware(op_handle_interrupt); ··· 58 49 return err; 59 50 60 51 /* Pre-compute the values to stuff in the hardware registers. */ 61 - model->reg_setup(ctr, &sys, model->num_counters); 52 + op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters); 62 53 63 - /* Configure the registers on all cpus. */ 54 + if (op_per_cpu_rc) 55 + goto out; 56 + 57 + /* Configure the registers on all cpus. If an error occurs on one 58 + * of the cpus, op_per_cpu_rc will be set to the error */ 64 59 on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1); 65 60 66 - return 0; 61 + out: if (op_per_cpu_rc) { 62 + /* error on setup release the performance counter hardware */ 63 + release_pmc_hardware(); 64 + } 65 + 66 + return op_per_cpu_rc; 67 67 } 68 68 69 69 static void op_powerpc_shutdown(void) ··· 82 64 83 65 static void op_powerpc_cpu_start(void *dummy) 84 66 { 85 - model->start(ctr); 67 + /* If any of the cpus have return an error, set the 68 + * global flag to the error so it can be returned 69 + * to the generic OProfile caller. 70 + */ 71 + int ret; 72 + 73 + ret = model->start(ctr); 74 + if (ret != 0) 75 + op_per_cpu_rc = ret; 86 76 } 87 77 88 78 static int op_powerpc_start(void) 89 79 { 80 + op_per_cpu_rc = 0; 81 + 90 82 if (model->global_start) 91 - model->global_start(ctr); 92 - if (model->start) 83 + return model->global_start(ctr); 84 + if (model->start) { 93 85 on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1); 94 - return 0; 86 + return op_per_cpu_rc; 87 + } 88 + return -EIO; /* No start function is defined for this 89 + power architecture */ 95 90 } 96 91 97 92 static inline void op_powerpc_cpu_stop(void *dummy) ··· 178 147 179 148 switch (cur_cpu_spec->oprofile_type) { 180 149 #ifdef CONFIG_PPC64 181 - #ifdef CONFIG_PPC_CELL_NATIVE 150 + #ifdef CONFIG_OPROFILE_CELL 182 151 case PPC_OPROFILE_CELL: 183 152 if (firmware_has_feature(FW_FEATURE_LPAR)) 184 153 return -ENODEV; 185 154 model = &op_model_cell; 155 + ops->sync_start = model->sync_start; 156 + ops->sync_stop = model->sync_stop; 186 157 break; 187 158 #endif 188 159 case PPC_OPROFILE_RS64:
+10 -4
arch/powerpc/oprofile/op_model_7450.c
··· 81 81 82 82 /* Configures the counters on this CPU based on the global 83 83 * settings */ 84 - static void fsl7450_cpu_setup(struct op_counter_config *ctr) 84 + static int fsl7450_cpu_setup(struct op_counter_config *ctr) 85 85 { 86 86 /* freeze all counters */ 87 87 pmc_stop_ctrs(); ··· 89 89 mtspr(SPRN_MMCR0, mmcr0_val); 90 90 mtspr(SPRN_MMCR1, mmcr1_val); 91 91 mtspr(SPRN_MMCR2, mmcr2_val); 92 + 93 + return 0; 92 94 } 93 95 94 96 #define NUM_CTRS 6 95 97 96 98 /* Configures the global settings for the countes on all CPUs. */ 97 - static void fsl7450_reg_setup(struct op_counter_config *ctr, 99 + static int fsl7450_reg_setup(struct op_counter_config *ctr, 98 100 struct op_system_config *sys, 99 101 int num_ctrs) 100 102 { ··· 128 126 | mmcr1_event6(ctr[5].event); 129 127 130 128 mmcr2_val = 0; 129 + 130 + return 0; 131 131 } 132 132 133 133 /* Sets the counters on this CPU to the chosen values, and starts them */ 134 - static void fsl7450_start(struct op_counter_config *ctr) 134 + static int fsl7450_start(struct op_counter_config *ctr) 135 135 { 136 136 int i; 137 137 ··· 152 148 pmc_start_ctrs(); 153 149 154 150 oprofile_running = 1; 151 + 152 + return 0; 155 153 } 156 154 157 155 /* Stop the counters on this CPU */ ··· 199 193 /* The freeze bit was set by the interrupt. */ 200 194 /* Clear the freeze bit, and reenable the interrupt. 201 195 * The counters won't actually start until the rfi clears 202 - * the PMM bit */ 196 + * the PM/M bit */ 203 197 pmc_start_ctrs(); 204 198 } 205 199
+528 -81
arch/powerpc/oprofile/op_model_cell.c
··· 5 5 * 6 6 * Author: David Erb (djerb@us.ibm.com) 7 7 * Modifications: 8 - * Carl Love <carll@us.ibm.com> 9 - * Maynard Johnson <maynardj@us.ibm.com> 8 + * Carl Love <carll@us.ibm.com> 9 + * Maynard Johnson <maynardj@us.ibm.com> 10 10 * 11 11 * This program is free software; you can redistribute it and/or 12 12 * modify it under the terms of the GNU General Public License ··· 38 38 39 39 #include "../platforms/cell/interrupt.h" 40 40 #include "../platforms/cell/cbe_regs.h" 41 + #include "cell/pr_util.h" 42 + 43 + static void cell_global_stop_spu(void); 44 + 45 + /* 46 + * spu_cycle_reset is the number of cycles between samples. 47 + * This variable is used for SPU profiling and should ONLY be set 48 + * at the beginning of cell_reg_setup; otherwise, it's read-only. 49 + */ 50 + static unsigned int spu_cycle_reset; 51 + 52 + #define NUM_SPUS_PER_NODE 8 53 + #define SPU_CYCLES_EVENT_NUM 2 /* event number for SPU_CYCLES */ 41 54 42 55 #define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */ 43 - #define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying 44 - * PPU_CYCLES event 45 - */ 46 - #define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */ 56 + #define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying 57 + * PPU_CYCLES event 58 + */ 59 + #define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */ 47 60 48 61 #define NUM_THREADS 2 /* number of physical threads in 49 62 * physical processor ··· 64 51 #define NUM_TRACE_BUS_WORDS 4 65 52 #define NUM_INPUT_BUS_WORDS 2 66 53 54 + #define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */ 67 55 68 56 struct pmc_cntrl_data { 69 57 unsigned long vcntr; ··· 76 62 /* 77 63 * ibm,cbe-perftools rtas parameters 78 64 */ 79 - 80 65 struct pm_signal { 81 66 u16 cpu; /* Processor to modify */ 82 - u16 sub_unit; /* hw subunit this applies to (if applicable) */ 83 - short int signal_group; /* Signal Group to Enable/Disable */ 67 + u16 sub_unit; /* hw subunit this applies to (if applicable)*/ 68 + short int signal_group; /* Signal Group to Enable/Disable */ 84 69 u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event 85 70 * Bus Word(s) (bitmask) 86 71 */ ··· 125 112 126 113 static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS]; 127 114 128 - /* Interpetation of hdw_thread: 115 + /* 116 + * The CELL profiling code makes rtas calls to setup the debug bus to 117 + * route the performance signals. Additionally, SPU profiling requires 118 + * a second rtas call to setup the hardware to capture the SPU PCs. 119 + * The EIO error value is returned if the token lookups or the rtas 120 + * call fail. The EIO error number is the best choice of the existing 121 + * error numbers. The probability of rtas related error is very low. But 122 + * by returning EIO and printing additional information to dmsg the user 123 + * will know that OProfile did not start and dmesg will tell them why. 124 + * OProfile does not support returning errors on Stop. Not a huge issue 125 + * since failure to reset the debug bus or stop the SPU PC collection is 126 + * not a fatel issue. Chances are if the Stop failed, Start doesn't work 127 + * either. 128 + */ 129 + 130 + /* 131 + * Interpetation of hdw_thread: 129 132 * 0 - even virtual cpus 0, 2, 4,... 130 133 * 1 - odd virtual cpus 1, 3, 5, ... 134 + * 135 + * FIXME: this is strictly wrong, we need to clean this up in a number 136 + * of places. It works for now. -arnd 131 137 */ 132 138 static u32 hdw_thread; 133 139 134 140 static u32 virt_cntr_inter_mask; 135 141 static struct timer_list timer_virt_cntr; 136 142 137 - /* pm_signal needs to be global since it is initialized in 143 + /* 144 + * pm_signal needs to be global since it is initialized in 138 145 * cell_reg_setup at the time when the necessary information 139 146 * is available. 140 147 */ 141 148 static struct pm_signal pm_signal[NR_PHYS_CTRS]; 142 - static int pm_rtas_token; 149 + static int pm_rtas_token; /* token for debug bus setup call */ 150 + static int spu_rtas_token; /* token for SPU cycle profiling */ 143 151 144 152 static u32 reset_value[NR_PHYS_CTRS]; 145 153 static int num_counters; ··· 181 147 { 182 148 u64 paddr = __pa(address); 183 149 184 - return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru, 185 - paddr >> 32, paddr & 0xffffffff, length); 150 + return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, 151 + passthru, paddr >> 32, paddr & 0xffffffff, length); 186 152 } 187 153 188 154 static void pm_rtas_reset_signals(u32 node) ··· 190 156 int ret; 191 157 struct pm_signal pm_signal_local; 192 158 193 - /* The debug bus is being set to the passthru disable state. 194 - * However, the FW still expects atleast one legal signal routing 195 - * entry or it will return an error on the arguments. If we don't 196 - * supply a valid entry, we must ignore all return values. Ignoring 197 - * all return values means we might miss an error we should be 198 - * concerned about. 159 + /* 160 + * The debug bus is being set to the passthru disable state. 161 + * However, the FW still expects atleast one legal signal routing 162 + * entry or it will return an error on the arguments. If we don't 163 + * supply a valid entry, we must ignore all return values. Ignoring 164 + * all return values means we might miss an error we should be 165 + * concerned about. 199 166 */ 200 167 201 168 /* fw expects physical cpu #. */ ··· 210 175 &pm_signal_local, 211 176 sizeof(struct pm_signal)); 212 177 213 - if (ret) 178 + if (unlikely(ret)) 179 + /* 180 + * Not a fatal error. For Oprofile stop, the oprofile 181 + * functions do not support returning an error for 182 + * failure to stop OProfile. 183 + */ 214 184 printk(KERN_WARNING "%s: rtas returned: %d\n", 215 185 __FUNCTION__, ret); 216 186 } 217 187 218 - static void pm_rtas_activate_signals(u32 node, u32 count) 188 + static int pm_rtas_activate_signals(u32 node, u32 count) 219 189 { 220 190 int ret; 221 191 int i, j; 222 192 struct pm_signal pm_signal_local[NR_PHYS_CTRS]; 223 193 224 - /* There is no debug setup required for the cycles event. 194 + /* 195 + * There is no debug setup required for the cycles event. 225 196 * Note that only events in the same group can be used. 226 197 * Otherwise, there will be conflicts in correctly routing 227 198 * the signals on the debug bus. It is the responsiblity ··· 254 213 pm_signal_local, 255 214 i * sizeof(struct pm_signal)); 256 215 257 - if (ret) 216 + if (unlikely(ret)) { 258 217 printk(KERN_WARNING "%s: rtas returned: %d\n", 259 218 __FUNCTION__, ret); 219 + return -EIO; 220 + } 260 221 } 222 + 223 + return 0; 261 224 } 262 225 263 226 /* ··· 305 260 pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity); 306 261 pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control); 307 262 308 - /* Some of the islands signal selection is based on 64 bit words. 263 + /* 264 + * Some of the islands signal selection is based on 64 bit words. 309 265 * The debug bus words are 32 bits, the input words to the performance 310 266 * counters are defined as 32 bits. Need to convert the 64 bit island 311 267 * specification to the appropriate 32 input bit and bus word for the 312 - * performance counter event selection. See the CELL Performance 268 + * performance counter event selection. See the CELL Performance 313 269 * monitoring signals manual and the Perf cntr hardware descriptions 314 270 * for the details. 315 271 */ ··· 344 298 input_bus[j] = i; 345 299 pm_regs.group_control |= 346 300 (i << (31 - i)); 301 + 347 302 break; 348 303 } 349 304 } ··· 356 309 357 310 static void write_pm_cntrl(int cpu) 358 311 { 359 - /* Oprofile will use 32 bit counters, set bits 7:10 to 0 312 + /* 313 + * Oprofile will use 32 bit counters, set bits 7:10 to 0 360 314 * pmregs.pm_cntrl is a global 361 315 */ 362 316 ··· 374 326 if (pm_regs.pm_cntrl.freeze == 1) 375 327 val |= CBE_PM_FREEZE_ALL_CTRS; 376 328 377 - /* Routine set_count_mode must be called previously to set 329 + /* 330 + * Routine set_count_mode must be called previously to set 378 331 * the count mode based on the user selection of user and kernel. 379 332 */ 380 333 val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode); ··· 385 336 static inline void 386 337 set_count_mode(u32 kernel, u32 user) 387 338 { 388 - /* The user must specify user and kernel if they want them. If 339 + /* 340 + * The user must specify user and kernel if they want them. If 389 341 * neither is specified, OProfile will count in hypervisor mode. 390 342 * pm_regs.pm_cntrl is a global 391 343 */ ··· 414 364 415 365 /* 416 366 * Oprofile is expected to collect data on all CPUs simultaneously. 417 - * However, there is one set of performance counters per node. There are 367 + * However, there is one set of performance counters per node. There are 418 368 * two hardware threads or virtual CPUs on each node. Hence, OProfile must 419 369 * multiplex in time the performance counter collection on the two virtual 420 370 * CPUs. The multiplexing of the performance counters is done by this ··· 427 377 * pair of per-cpu arrays is used for storing the previous and next 428 378 * pmc values for a given node. 429 379 * NOTE: We use the per-cpu variable to improve cache performance. 380 + * 381 + * This routine will alternate loading the virtual counters for 382 + * virtual CPUs 430 383 */ 431 384 static void cell_virtual_cntr(unsigned long data) 432 385 { 433 - /* This routine will alternate loading the virtual counters for 434 - * virtual CPUs 435 - */ 436 386 int i, prev_hdw_thread, next_hdw_thread; 437 387 u32 cpu; 438 388 unsigned long flags; 439 389 440 - /* Make sure that the interrupt_hander and 441 - * the virt counter are not both playing with 442 - * the counters on the same node. 390 + /* 391 + * Make sure that the interrupt_hander and the virt counter are 392 + * not both playing with the counters on the same node. 443 393 */ 444 394 445 395 spin_lock_irqsave(&virt_cntr_lock, flags); ··· 450 400 hdw_thread = 1 ^ hdw_thread; 451 401 next_hdw_thread = hdw_thread; 452 402 453 - for (i = 0; i < num_counters; i++) 454 - /* There are some per thread events. Must do the 403 + /* 404 + * There are some per thread events. Must do the 455 405 * set event, for the thread that is being started 456 406 */ 407 + for (i = 0; i < num_counters; i++) 457 408 set_pm_event(i, 458 409 pmc_cntrl[next_hdw_thread][i].evnts, 459 410 pmc_cntrl[next_hdw_thread][i].masks); 460 411 461 - /* The following is done only once per each node, but 412 + /* 413 + * The following is done only once per each node, but 462 414 * we need cpu #, not node #, to pass to the cbe_xxx functions. 463 415 */ 464 416 for_each_online_cpu(cpu) { 465 417 if (cbe_get_hw_thread_id(cpu)) 466 418 continue; 467 419 468 - /* stop counters, save counter values, restore counts 420 + /* 421 + * stop counters, save counter values, restore counts 469 422 * for previous thread 470 423 */ 471 424 cbe_disable_pm(cpu); ··· 481 428 == 0xFFFFFFFF) 482 429 /* If the cntr value is 0xffffffff, we must 483 430 * reset that to 0xfffffff0 when the current 484 - * thread is restarted. This will generate a 431 + * thread is restarted. This will generate a 485 432 * new interrupt and make sure that we never 486 433 * restore the counters to the max value. If 487 434 * the counters were restored to the max value, ··· 497 444 next_hdw_thread)[i]); 498 445 } 499 446 500 - /* Switch to the other thread. Change the interrupt 447 + /* 448 + * Switch to the other thread. Change the interrupt 501 449 * and control regs to be scheduled on the CPU 502 450 * corresponding to the thread to execute. 503 451 */ 504 452 for (i = 0; i < num_counters; i++) { 505 453 if (pmc_cntrl[next_hdw_thread][i].enabled) { 506 - /* There are some per thread events. 454 + /* 455 + * There are some per thread events. 507 456 * Must do the set event, enable_cntr 508 457 * for each cpu. 509 458 */ ··· 537 482 } 538 483 539 484 /* This function is called once for all cpus combined */ 540 - static void 541 - cell_reg_setup(struct op_counter_config *ctr, 542 - struct op_system_config *sys, int num_ctrs) 485 + static int cell_reg_setup(struct op_counter_config *ctr, 486 + struct op_system_config *sys, int num_ctrs) 543 487 { 544 488 int i, j, cpu; 489 + spu_cycle_reset = 0; 490 + 491 + if (ctr[0].event == SPU_CYCLES_EVENT_NUM) { 492 + spu_cycle_reset = ctr[0].count; 493 + 494 + /* 495 + * Each node will need to make the rtas call to start 496 + * and stop SPU profiling. Get the token once and store it. 497 + */ 498 + spu_rtas_token = rtas_token("ibm,cbe-spu-perftools"); 499 + 500 + if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) { 501 + printk(KERN_ERR 502 + "%s: rtas token ibm,cbe-spu-perftools unknown\n", 503 + __FUNCTION__); 504 + return -EIO; 505 + } 506 + } 545 507 546 508 pm_rtas_token = rtas_token("ibm,cbe-perftools"); 547 - if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) { 548 - printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n", 509 + 510 + /* 511 + * For all events excetp PPU CYCLEs, each node will need to make 512 + * the rtas cbe-perftools call to setup and reset the debug bus. 513 + * Make the token lookup call once and store it in the global 514 + * variable pm_rtas_token. 515 + */ 516 + if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) { 517 + printk(KERN_ERR 518 + "%s: rtas token ibm,cbe-perftools unknown\n", 549 519 __FUNCTION__); 550 - goto out; 520 + return -EIO; 551 521 } 552 522 553 523 num_counters = num_ctrs; ··· 600 520 per_cpu(pmc_values, j)[i] = 0; 601 521 } 602 522 603 - /* Setup the thread 1 events, map the thread 0 event to the 523 + /* 524 + * Setup the thread 1 events, map the thread 0 event to the 604 525 * equivalent thread 1 event. 605 526 */ 606 527 for (i = 0; i < num_ctrs; ++i) { ··· 625 544 for (i = 0; i < NUM_INPUT_BUS_WORDS; i++) 626 545 input_bus[i] = 0xff; 627 546 628 - /* Our counters count up, and "count" refers to 547 + /* 548 + * Our counters count up, and "count" refers to 629 549 * how much before the next interrupt, and we interrupt 630 - * on overflow. So we calculate the starting value 550 + * on overflow. So we calculate the starting value 631 551 * which will give us "count" until overflow. 632 552 * Then we set the events on the enabled counters. 633 553 */ ··· 651 569 for (i = 0; i < num_counters; ++i) { 652 570 per_cpu(pmc_values, cpu)[i] = reset_value[i]; 653 571 } 654 - out: 655 - ; 572 + 573 + return 0; 656 574 } 657 575 576 + 577 + 658 578 /* This function is called once for each cpu */ 659 - static void cell_cpu_setup(struct op_counter_config *cntr) 579 + static int cell_cpu_setup(struct op_counter_config *cntr) 660 580 { 661 581 u32 cpu = smp_processor_id(); 662 582 u32 num_enabled = 0; 663 583 int i; 664 584 585 + if (spu_cycle_reset) 586 + return 0; 587 + 665 588 /* There is one performance monitor per processor chip (i.e. node), 666 589 * so we only need to perform this function once per node. 667 590 */ 668 591 if (cbe_get_hw_thread_id(cpu)) 669 - goto out; 670 - 671 - if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) { 672 - printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n", 673 - __FUNCTION__); 674 - goto out; 675 - } 592 + return 0; 676 593 677 594 /* Stop all counters */ 678 595 cbe_disable_pm(cpu); ··· 690 609 } 691 610 } 692 611 693 - pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled); 694 - out: 695 - ; 612 + /* 613 + * The pm_rtas_activate_signals will return -EIO if the FW 614 + * call failed. 615 + */ 616 + return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled); 696 617 } 697 618 698 - static void cell_global_start(struct op_counter_config *ctr) 619 + #define ENTRIES 303 620 + #define MAXLFSR 0xFFFFFF 621 + 622 + /* precomputed table of 24 bit LFSR values */ 623 + static int initial_lfsr[] = { 624 + 8221349, 12579195, 5379618, 10097839, 7512963, 7519310, 3955098, 10753424, 625 + 15507573, 7458917, 285419, 2641121, 9780088, 3915503, 6668768, 1548716, 626 + 4885000, 8774424, 9650099, 2044357, 2304411, 9326253, 10332526, 4421547, 627 + 3440748, 10179459, 13332843, 10375561, 1313462, 8375100, 5198480, 6071392, 628 + 9341783, 1526887, 3985002, 1439429, 13923762, 7010104, 11969769, 4547026, 629 + 2040072, 4025602, 3437678, 7939992, 11444177, 4496094, 9803157, 10745556, 630 + 3671780, 4257846, 5662259, 13196905, 3237343, 12077182, 16222879, 7587769, 631 + 14706824, 2184640, 12591135, 10420257, 7406075, 3648978, 11042541, 15906893, 632 + 11914928, 4732944, 10695697, 12928164, 11980531, 4430912, 11939291, 2917017, 633 + 6119256, 4172004, 9373765, 8410071, 14788383, 5047459, 5474428, 1737756, 634 + 15967514, 13351758, 6691285, 8034329, 2856544, 14394753, 11310160, 12149558, 635 + 7487528, 7542781, 15668898, 12525138, 12790975, 3707933, 9106617, 1965401, 636 + 16219109, 12801644, 2443203, 4909502, 8762329, 3120803, 6360315, 9309720, 637 + 15164599, 10844842, 4456529, 6667610, 14924259, 884312, 6234963, 3326042, 638 + 15973422, 13919464, 5272099, 6414643, 3909029, 2764324, 5237926, 4774955, 639 + 10445906, 4955302, 5203726, 10798229, 11443419, 2303395, 333836, 9646934, 640 + 3464726, 4159182, 568492, 995747, 10318756, 13299332, 4836017, 8237783, 641 + 3878992, 2581665, 11394667, 5672745, 14412947, 3159169, 9094251, 16467278, 642 + 8671392, 15230076, 4843545, 7009238, 15504095, 1494895, 9627886, 14485051, 643 + 8304291, 252817, 12421642, 16085736, 4774072, 2456177, 4160695, 15409741, 644 + 4902868, 5793091, 13162925, 16039714, 782255, 11347835, 14884586, 366972, 645 + 16308990, 11913488, 13390465, 2958444, 10340278, 1177858, 1319431, 10426302, 646 + 2868597, 126119, 5784857, 5245324, 10903900, 16436004, 3389013, 1742384, 647 + 14674502, 10279218, 8536112, 10364279, 6877778, 14051163, 1025130, 6072469, 648 + 1988305, 8354440, 8216060, 16342977, 13112639, 3976679, 5913576, 8816697, 649 + 6879995, 14043764, 3339515, 9364420, 15808858, 12261651, 2141560, 5636398, 650 + 10345425, 10414756, 781725, 6155650, 4746914, 5078683, 7469001, 6799140, 651 + 10156444, 9667150, 10116470, 4133858, 2121972, 1124204, 1003577, 1611214, 652 + 14304602, 16221850, 13878465, 13577744, 3629235, 8772583, 10881308, 2410386, 653 + 7300044, 5378855, 9301235, 12755149, 4977682, 8083074, 10327581, 6395087, 654 + 9155434, 15501696, 7514362, 14520507, 15808945, 3244584, 4741962, 9658130, 655 + 14336147, 8654727, 7969093, 15759799, 14029445, 5038459, 9894848, 8659300, 656 + 13699287, 8834306, 10712885, 14753895, 10410465, 3373251, 309501, 9561475, 657 + 5526688, 14647426, 14209836, 5339224, 207299, 14069911, 8722990, 2290950, 658 + 3258216, 12505185, 6007317, 9218111, 14661019, 10537428, 11731949, 9027003, 659 + 6641507, 9490160, 200241, 9720425, 16277895, 10816638, 1554761, 10431375, 660 + 7467528, 6790302, 3429078, 14633753, 14428997, 11463204, 3576212, 2003426, 661 + 6123687, 820520, 9992513, 15784513, 5778891, 6428165, 8388607 662 + }; 663 + 664 + /* 665 + * The hardware uses an LFSR counting sequence to determine when to capture 666 + * the SPU PCs. An LFSR sequence is like a puesdo random number sequence 667 + * where each number occurs once in the sequence but the sequence is not in 668 + * numerical order. The SPU PC capture is done when the LFSR sequence reaches 669 + * the last value in the sequence. Hence the user specified value N 670 + * corresponds to the LFSR number that is N from the end of the sequence. 671 + * 672 + * To avoid the time to compute the LFSR, a lookup table is used. The 24 bit 673 + * LFSR sequence is broken into four ranges. The spacing of the precomputed 674 + * values is adjusted in each range so the error between the user specifed 675 + * number (N) of events between samples and the actual number of events based 676 + * on the precomputed value will be les then about 6.2%. Note, if the user 677 + * specifies N < 2^16, the LFSR value that is 2^16 from the end will be used. 678 + * This is to prevent the loss of samples because the trace buffer is full. 679 + * 680 + * User specified N Step between Index in 681 + * precomputed values precomputed 682 + * table 683 + * 0 to 2^16-1 ---- 0 684 + * 2^16 to 2^16+2^19-1 2^12 1 to 128 685 + * 2^16+2^19 to 2^16+2^19+2^22-1 2^15 129 to 256 686 + * 2^16+2^19+2^22 to 2^24-1 2^18 257 to 302 687 + * 688 + * 689 + * For example, the LFSR values in the second range are computed for 2^16, 690 + * 2^16+2^12, ... , 2^19-2^16, 2^19 and stored in the table at indicies 691 + * 1, 2,..., 127, 128. 692 + * 693 + * The 24 bit LFSR value for the nth number in the sequence can be 694 + * calculated using the following code: 695 + * 696 + * #define size 24 697 + * int calculate_lfsr(int n) 698 + * { 699 + * int i; 700 + * unsigned int newlfsr0; 701 + * unsigned int lfsr = 0xFFFFFF; 702 + * unsigned int howmany = n; 703 + * 704 + * for (i = 2; i < howmany + 2; i++) { 705 + * newlfsr0 = (((lfsr >> (size - 1 - 0)) & 1) ^ 706 + * ((lfsr >> (size - 1 - 1)) & 1) ^ 707 + * (((lfsr >> (size - 1 - 6)) & 1) ^ 708 + * ((lfsr >> (size - 1 - 23)) & 1))); 709 + * 710 + * lfsr >>= 1; 711 + * lfsr = lfsr | (newlfsr0 << (size - 1)); 712 + * } 713 + * return lfsr; 714 + * } 715 + */ 716 + 717 + #define V2_16 (0x1 << 16) 718 + #define V2_19 (0x1 << 19) 719 + #define V2_22 (0x1 << 22) 720 + 721 + static int calculate_lfsr(int n) 699 722 { 700 - u32 cpu; 723 + /* 724 + * The ranges and steps are in powers of 2 so the calculations 725 + * can be done using shifts rather then divide. 726 + */ 727 + int index; 728 + 729 + if ((n >> 16) == 0) 730 + index = 0; 731 + else if (((n - V2_16) >> 19) == 0) 732 + index = ((n - V2_16) >> 12) + 1; 733 + else if (((n - V2_16 - V2_19) >> 22) == 0) 734 + index = ((n - V2_16 - V2_19) >> 15 ) + 1 + 128; 735 + else if (((n - V2_16 - V2_19 - V2_22) >> 24) == 0) 736 + index = ((n - V2_16 - V2_19 - V2_22) >> 18 ) + 1 + 256; 737 + else 738 + index = ENTRIES-1; 739 + 740 + /* make sure index is valid */ 741 + if ((index > ENTRIES) || (index < 0)) 742 + index = ENTRIES-1; 743 + 744 + return initial_lfsr[index]; 745 + } 746 + 747 + static int pm_rtas_activate_spu_profiling(u32 node) 748 + { 749 + int ret, i; 750 + struct pm_signal pm_signal_local[NR_PHYS_CTRS]; 751 + 752 + /* 753 + * Set up the rtas call to configure the debug bus to 754 + * route the SPU PCs. Setup the pm_signal for each SPU 755 + */ 756 + for (i = 0; i < NUM_SPUS_PER_NODE; i++) { 757 + pm_signal_local[i].cpu = node; 758 + pm_signal_local[i].signal_group = 41; 759 + /* spu i on word (i/2) */ 760 + pm_signal_local[i].bus_word = 1 << i / 2; 761 + /* spu i */ 762 + pm_signal_local[i].sub_unit = i; 763 + pm_signal_local[i].bit = 63; 764 + } 765 + 766 + ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE, 767 + PASSTHRU_ENABLE, pm_signal_local, 768 + (NUM_SPUS_PER_NODE 769 + * sizeof(struct pm_signal))); 770 + 771 + if (unlikely(ret)) { 772 + printk(KERN_WARNING "%s: rtas returned: %d\n", 773 + __FUNCTION__, ret); 774 + return -EIO; 775 + } 776 + 777 + return 0; 778 + } 779 + 780 + #ifdef CONFIG_CPU_FREQ 781 + static int 782 + oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data) 783 + { 784 + int ret = 0; 785 + struct cpufreq_freqs *frq = data; 786 + if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) || 787 + (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) || 788 + (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) 789 + set_spu_profiling_frequency(frq->new, spu_cycle_reset); 790 + return ret; 791 + } 792 + 793 + static struct notifier_block cpu_freq_notifier_block = { 794 + .notifier_call = oprof_cpufreq_notify 795 + }; 796 + #endif 797 + 798 + static int cell_global_start_spu(struct op_counter_config *ctr) 799 + { 800 + int subfunc; 801 + unsigned int lfsr_value; 802 + int cpu; 803 + int ret; 804 + int rtas_error; 805 + unsigned int cpu_khzfreq = 0; 806 + 807 + /* The SPU profiling uses time-based profiling based on 808 + * cpu frequency, so if configured with the CPU_FREQ 809 + * option, we should detect frequency changes and react 810 + * accordingly. 811 + */ 812 + #ifdef CONFIG_CPU_FREQ 813 + ret = cpufreq_register_notifier(&cpu_freq_notifier_block, 814 + CPUFREQ_TRANSITION_NOTIFIER); 815 + if (ret < 0) 816 + /* this is not a fatal error */ 817 + printk(KERN_ERR "CPU freq change registration failed: %d\n", 818 + ret); 819 + 820 + else 821 + cpu_khzfreq = cpufreq_quick_get(smp_processor_id()); 822 + #endif 823 + 824 + set_spu_profiling_frequency(cpu_khzfreq, spu_cycle_reset); 825 + 826 + for_each_online_cpu(cpu) { 827 + if (cbe_get_hw_thread_id(cpu)) 828 + continue; 829 + 830 + /* 831 + * Setup SPU cycle-based profiling. 832 + * Set perf_mon_control bit 0 to a zero before 833 + * enabling spu collection hardware. 834 + */ 835 + cbe_write_pm(cpu, pm_control, 0); 836 + 837 + if (spu_cycle_reset > MAX_SPU_COUNT) 838 + /* use largest possible value */ 839 + lfsr_value = calculate_lfsr(MAX_SPU_COUNT-1); 840 + else 841 + lfsr_value = calculate_lfsr(spu_cycle_reset); 842 + 843 + /* must use a non zero value. Zero disables data collection. */ 844 + if (lfsr_value == 0) 845 + lfsr_value = calculate_lfsr(1); 846 + 847 + lfsr_value = lfsr_value << 8; /* shift lfsr to correct 848 + * register location 849 + */ 850 + 851 + /* debug bus setup */ 852 + ret = pm_rtas_activate_spu_profiling(cbe_cpu_to_node(cpu)); 853 + 854 + if (unlikely(ret)) { 855 + rtas_error = ret; 856 + goto out; 857 + } 858 + 859 + 860 + subfunc = 2; /* 2 - activate SPU tracing, 3 - deactivate */ 861 + 862 + /* start profiling */ 863 + ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc, 864 + cbe_cpu_to_node(cpu), lfsr_value); 865 + 866 + if (unlikely(ret != 0)) { 867 + printk(KERN_ERR 868 + "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n", 869 + __FUNCTION__, ret); 870 + rtas_error = -EIO; 871 + goto out; 872 + } 873 + } 874 + 875 + rtas_error = start_spu_profiling(spu_cycle_reset); 876 + if (rtas_error) 877 + goto out_stop; 878 + 879 + oprofile_running = 1; 880 + return 0; 881 + 882 + out_stop: 883 + cell_global_stop_spu(); /* clean up the PMU/debug bus */ 884 + out: 885 + return rtas_error; 886 + } 887 + 888 + static int cell_global_start_ppu(struct op_counter_config *ctr) 889 + { 890 + u32 cpu, i; 701 891 u32 interrupt_mask = 0; 702 - u32 i; 703 892 704 893 /* This routine gets called once for the system. 705 894 * There is one performance monitor per node, so we ··· 1002 651 oprofile_running = 1; 1003 652 smp_wmb(); 1004 653 1005 - /* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being 1006 - * executed which manipulates the PMU. We start the "virtual counter" 654 + /* 655 + * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being 656 + * executed which manipulates the PMU. We start the "virtual counter" 1007 657 * here so that we do not need to synchronize access to the PMU in 1008 658 * the above for-loop. 1009 659 */ 1010 660 start_virt_cntrs(); 661 + 662 + return 0; 1011 663 } 1012 664 1013 - static void cell_global_stop(void) 665 + static int cell_global_start(struct op_counter_config *ctr) 666 + { 667 + if (spu_cycle_reset) 668 + return cell_global_start_spu(ctr); 669 + else 670 + return cell_global_start_ppu(ctr); 671 + } 672 + 673 + /* 674 + * Note the generic OProfile stop calls do not support returning 675 + * an error on stop. Hence, will not return an error if the FW 676 + * calls fail on stop. Failure to reset the debug bus is not an issue. 677 + * Failure to disable the SPU profiling is not an issue. The FW calls 678 + * to enable the performance counters and debug bus will work even if 679 + * the hardware was not cleanly reset. 680 + */ 681 + static void cell_global_stop_spu(void) 682 + { 683 + int subfunc, rtn_value; 684 + unsigned int lfsr_value; 685 + int cpu; 686 + 687 + oprofile_running = 0; 688 + 689 + #ifdef CONFIG_CPU_FREQ 690 + cpufreq_unregister_notifier(&cpu_freq_notifier_block, 691 + CPUFREQ_TRANSITION_NOTIFIER); 692 + #endif 693 + 694 + for_each_online_cpu(cpu) { 695 + if (cbe_get_hw_thread_id(cpu)) 696 + continue; 697 + 698 + subfunc = 3; /* 699 + * 2 - activate SPU tracing, 700 + * 3 - deactivate 701 + */ 702 + lfsr_value = 0x8f100000; 703 + 704 + rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL, 705 + subfunc, cbe_cpu_to_node(cpu), 706 + lfsr_value); 707 + 708 + if (unlikely(rtn_value != 0)) { 709 + printk(KERN_ERR 710 + "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n", 711 + __FUNCTION__, rtn_value); 712 + } 713 + 714 + /* Deactivate the signals */ 715 + pm_rtas_reset_signals(cbe_cpu_to_node(cpu)); 716 + } 717 + 718 + stop_spu_profiling(); 719 + } 720 + 721 + static void cell_global_stop_ppu(void) 1014 722 { 1015 723 int cpu; 1016 724 1017 - /* This routine will be called once for the system. 725 + /* 726 + * This routine will be called once for the system. 1018 727 * There is one performance monitor per node, so we 1019 728 * only need to perform this function once per node. 1020 729 */ ··· 1098 687 } 1099 688 } 1100 689 1101 - static void 1102 - cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr) 690 + static void cell_global_stop(void) 691 + { 692 + if (spu_cycle_reset) 693 + cell_global_stop_spu(); 694 + else 695 + cell_global_stop_ppu(); 696 + } 697 + 698 + static void cell_handle_interrupt(struct pt_regs *regs, 699 + struct op_counter_config *ctr) 1103 700 { 1104 701 u32 cpu; 1105 702 u64 pc; ··· 1118 699 1119 700 cpu = smp_processor_id(); 1120 701 1121 - /* Need to make sure the interrupt handler and the virt counter 702 + /* 703 + * Need to make sure the interrupt handler and the virt counter 1122 704 * routine are not running at the same time. See the 1123 705 * cell_virtual_cntr() routine for additional comments. 1124 706 */ 1125 707 spin_lock_irqsave(&virt_cntr_lock, flags); 1126 708 1127 - /* Need to disable and reenable the performance counters 709 + /* 710 + * Need to disable and reenable the performance counters 1128 711 * to get the desired behavior from the hardware. This 1129 712 * is hardware specific. 1130 713 */ ··· 1135 714 1136 715 interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu); 1137 716 1138 - /* If the interrupt mask has been cleared, then the virt cntr 717 + /* 718 + * If the interrupt mask has been cleared, then the virt cntr 1139 719 * has cleared the interrupt. When the thread that generated 1140 720 * the interrupt is restored, the data count will be restored to 1141 721 * 0xffffff0 to cause the interrupt to be regenerated. ··· 1154 732 } 1155 733 } 1156 734 1157 - /* The counters were frozen by the interrupt. 735 + /* 736 + * The counters were frozen by the interrupt. 1158 737 * Reenable the interrupt and restart the counters. 1159 738 * If there was a race between the interrupt handler and 1160 - * the virtual counter routine. The virutal counter 739 + * the virtual counter routine. The virutal counter 1161 740 * routine may have cleared the interrupts. Hence must 1162 741 * use the virt_cntr_inter_mask to re-enable the interrupts. 1163 742 */ 1164 743 cbe_enable_pm_interrupts(cpu, hdw_thread, 1165 744 virt_cntr_inter_mask); 1166 745 1167 - /* The writes to the various performance counters only writes 1168 - * to a latch. The new values (interrupt setting bits, reset 746 + /* 747 + * The writes to the various performance counters only writes 748 + * to a latch. The new values (interrupt setting bits, reset 1169 749 * counter value etc.) are not copied to the actual registers 1170 750 * until the performance monitor is enabled. In order to get 1171 751 * this to work as desired, the permormance monitor needs to ··· 1179 755 spin_unlock_irqrestore(&virt_cntr_lock, flags); 1180 756 } 1181 757 758 + /* 759 + * This function is called from the generic OProfile 760 + * driver. When profiling PPUs, we need to do the 761 + * generic sync start; otherwise, do spu_sync_start. 762 + */ 763 + static int cell_sync_start(void) 764 + { 765 + if (spu_cycle_reset) 766 + return spu_sync_start(); 767 + else 768 + return DO_GENERIC_SYNC; 769 + } 770 + 771 + static int cell_sync_stop(void) 772 + { 773 + if (spu_cycle_reset) 774 + return spu_sync_stop(); 775 + else 776 + return 1; 777 + } 778 + 1182 779 struct op_powerpc_model op_model_cell = { 1183 780 .reg_setup = cell_reg_setup, 1184 781 .cpu_setup = cell_cpu_setup, 1185 782 .global_start = cell_global_start, 1186 783 .global_stop = cell_global_stop, 784 + .sync_start = cell_sync_start, 785 + .sync_stop = cell_sync_stop, 1187 786 .handle_interrupt = cell_handle_interrupt, 1188 787 };
+8 -3
arch/powerpc/oprofile/op_model_fsl_booke.c
··· 244 244 mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3)); 245 245 } 246 246 247 - static void fsl_booke_cpu_setup(struct op_counter_config *ctr) 247 + static int fsl_booke_cpu_setup(struct op_counter_config *ctr) 248 248 { 249 249 int i; 250 250 ··· 258 258 259 259 set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel); 260 260 } 261 + 262 + return 0; 261 263 } 262 264 263 - static void fsl_booke_reg_setup(struct op_counter_config *ctr, 265 + static int fsl_booke_reg_setup(struct op_counter_config *ctr, 264 266 struct op_system_config *sys, 265 267 int num_ctrs) 266 268 { ··· 278 276 for (i = 0; i < num_counters; ++i) 279 277 reset_value[i] = 0x80000000UL - ctr[i].count; 280 278 279 + return 0; 281 280 } 282 281 283 - static void fsl_booke_start(struct op_counter_config *ctr) 282 + static int fsl_booke_start(struct op_counter_config *ctr) 284 283 { 285 284 int i; 286 285 ··· 311 308 312 309 pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(), 313 310 mfpmr(PMRN_PMGC0)); 311 + 312 + return 0; 314 313 } 315 314 316 315 static void fsl_booke_stop(void)
+9 -3
arch/powerpc/oprofile/op_model_pa6t.c
··· 89 89 90 90 91 91 /* precompute the values to stuff in the hardware registers */ 92 - static void pa6t_reg_setup(struct op_counter_config *ctr, 92 + static int pa6t_reg_setup(struct op_counter_config *ctr, 93 93 struct op_system_config *sys, 94 94 int num_ctrs) 95 95 { ··· 135 135 pr_debug("reset_value for pmc%u inited to 0x%lx\n", 136 136 pmc, reset_value[pmc]); 137 137 } 138 + 139 + return 0; 138 140 } 139 141 140 142 /* configure registers on this cpu */ 141 - static void pa6t_cpu_setup(struct op_counter_config *ctr) 143 + static int pa6t_cpu_setup(struct op_counter_config *ctr) 142 144 { 143 145 u64 mmcr0 = mmcr0_val; 144 146 u64 mmcr1 = mmcr1_val; ··· 156 154 mfspr(SPRN_PA6T_MMCR0)); 157 155 pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(), 158 156 mfspr(SPRN_PA6T_MMCR1)); 157 + 158 + return 0; 159 159 } 160 160 161 - static void pa6t_start(struct op_counter_config *ctr) 161 + static int pa6t_start(struct op_counter_config *ctr) 162 162 { 163 163 int i; 164 164 ··· 178 174 oprofile_running = 1; 179 175 180 176 pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0); 177 + 178 + return 0; 181 179 } 182 180 183 181 static void pa6t_stop(void)
+8 -3
arch/powerpc/oprofile/op_model_power4.c
··· 32 32 static u64 mmcr1_val; 33 33 static u64 mmcra_val; 34 34 35 - static void power4_reg_setup(struct op_counter_config *ctr, 35 + static int power4_reg_setup(struct op_counter_config *ctr, 36 36 struct op_system_config *sys, 37 37 int num_ctrs) 38 38 { ··· 60 60 mmcr0_val &= ~MMCR0_PROBLEM_DISABLE; 61 61 else 62 62 mmcr0_val |= MMCR0_PROBLEM_DISABLE; 63 + 64 + return 0; 63 65 } 64 66 65 67 extern void ppc64_enable_pmcs(void); ··· 86 84 return 0; 87 85 } 88 86 89 - static void power4_cpu_setup(struct op_counter_config *ctr) 87 + static int power4_cpu_setup(struct op_counter_config *ctr) 90 88 { 91 89 unsigned int mmcr0 = mmcr0_val; 92 90 unsigned long mmcra = mmcra_val; ··· 113 111 mfspr(SPRN_MMCR1)); 114 112 dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(), 115 113 mfspr(SPRN_MMCRA)); 114 + 115 + return 0; 116 116 } 117 117 118 - static void power4_start(struct op_counter_config *ctr) 118 + static int power4_start(struct op_counter_config *ctr) 119 119 { 120 120 int i; 121 121 unsigned int mmcr0; ··· 152 148 oprofile_running = 1; 153 149 154 150 dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0); 151 + return 0; 155 152 } 156 153 157 154 static void power4_stop(void)
+7 -3
arch/powerpc/oprofile/op_model_rs64.c
··· 88 88 89 89 static int num_counters; 90 90 91 - static void rs64_reg_setup(struct op_counter_config *ctr, 91 + static int rs64_reg_setup(struct op_counter_config *ctr, 92 92 struct op_system_config *sys, 93 93 int num_ctrs) 94 94 { ··· 100 100 reset_value[i] = 0x80000000UL - ctr[i].count; 101 101 102 102 /* XXX setup user and kernel profiling */ 103 + return 0; 103 104 } 104 105 105 - static void rs64_cpu_setup(struct op_counter_config *ctr) 106 + static int rs64_cpu_setup(struct op_counter_config *ctr) 106 107 { 107 108 unsigned int mmcr0; 108 109 ··· 126 125 mfspr(SPRN_MMCR0)); 127 126 dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(), 128 127 mfspr(SPRN_MMCR1)); 128 + 129 + return 0; 129 130 } 130 131 131 - static void rs64_start(struct op_counter_config *ctr) 132 + static int rs64_start(struct op_counter_config *ctr) 132 133 { 133 134 int i; 134 135 unsigned int mmcr0; ··· 158 155 mtspr(SPRN_MMCR0, mmcr0); 159 156 160 157 dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0); 158 + return 0; 161 159 } 162 160 163 161 static void rs64_stop(void)
+20
arch/powerpc/platforms/cell/spufs/context.c
··· 22 22 23 23 #include <linux/fs.h> 24 24 #include <linux/mm.h> 25 + #include <linux/module.h> 25 26 #include <linux/slab.h> 26 27 #include <asm/atomic.h> 27 28 #include <asm/spu.h> ··· 82 81 spu_fini_csa(&ctx->csa); 83 82 if (ctx->gang) 84 83 spu_gang_remove_ctx(ctx->gang, ctx); 84 + if (ctx->prof_priv_kref) 85 + kref_put(ctx->prof_priv_kref, ctx->prof_priv_release); 85 86 BUG_ON(!list_empty(&ctx->rq)); 86 87 atomic_dec(&nr_spu_contexts); 87 88 kfree(ctx); ··· 188 185 189 186 spu_release(ctx); 190 187 } 188 + 189 + void spu_set_profile_private_kref(struct spu_context *ctx, 190 + struct kref *prof_info_kref, 191 + void ( * prof_info_release) (struct kref *kref)) 192 + { 193 + ctx->prof_priv_kref = prof_info_kref; 194 + ctx->prof_priv_release = prof_info_release; 195 + } 196 + EXPORT_SYMBOL_GPL(spu_set_profile_private_kref); 197 + 198 + void *spu_get_profile_private_kref(struct spu_context *ctx) 199 + { 200 + return ctx->prof_priv_kref; 201 + } 202 + EXPORT_SYMBOL_GPL(spu_get_profile_private_kref); 203 + 204 +
+3 -1
arch/powerpc/platforms/cell/spufs/sched.c
··· 274 274 ctx->spu = spu; 275 275 ctx->ops = &spu_hw_ops; 276 276 spu->pid = current->pid; 277 + spu->tgid = current->tgid; 277 278 spu_associate_mm(spu, ctx->owner); 278 279 spu->ibox_callback = spufs_ibox_callback; 279 280 spu->wbox_callback = spufs_wbox_callback; ··· 457 456 spu->dma_callback = NULL; 458 457 spu_associate_mm(spu, NULL); 459 458 spu->pid = 0; 459 + spu->tgid = 0; 460 460 ctx->ops = &spu_backing_ops; 461 461 spu->flags = 0; 462 462 spu->ctx = NULL; ··· 739 737 } 740 738 741 739 /** 742 - * spu_yield - yield a physical spu if others are waiting 740 + * spu_yield - yield a physical spu if others are waiting 743 741 * @ctx: spu context to yield 744 742 * 745 743 * Check if there is a higher priority context waiting and if yes
+2
arch/powerpc/platforms/cell/spufs/spufs.h
··· 85 85 86 86 struct list_head gang_list; 87 87 struct spu_gang *gang; 88 + struct kref *prof_priv_kref; 89 + void ( * prof_priv_release) (struct kref *kref); 88 90 89 91 /* owner thread */ 90 92 pid_t tid;
+2 -1
drivers/oprofile/buffer_sync.c
··· 26 26 #include <linux/profile.h> 27 27 #include <linux/module.h> 28 28 #include <linux/fs.h> 29 + #include <linux/oprofile.h> 29 30 #include <linux/sched.h> 30 - 31 + 31 32 #include "oprofile_stats.h" 32 33 #include "event_buffer.h" 33 34 #include "cpu_buffer.h"
+1 -19
drivers/oprofile/event_buffer.h
··· 19 19 20 20 /* wake up the process sleeping on the event file */ 21 21 void wake_up_buffer_waiter(void); 22 - 23 - /* Each escaped entry is prefixed by ESCAPE_CODE 24 - * then one of the following codes, then the 25 - * relevant data. 26 - */ 27 - #define ESCAPE_CODE ~0UL 28 - #define CTX_SWITCH_CODE 1 29 - #define CPU_SWITCH_CODE 2 30 - #define COOKIE_SWITCH_CODE 3 31 - #define KERNEL_ENTER_SWITCH_CODE 4 32 - #define KERNEL_EXIT_SWITCH_CODE 5 33 - #define MODULE_LOADED_CODE 6 34 - #define CTX_TGID_CODE 7 35 - #define TRACE_BEGIN_CODE 8 36 - #define TRACE_END_CODE 9 37 - 22 + 38 23 #define INVALID_COOKIE ~0UL 39 24 #define NO_COOKIE 0UL 40 25 41 - /* add data to the event buffer */ 42 - void add_event_entry(unsigned long data); 43 - 44 26 extern const struct file_operations event_buffer_fops; 45 27 46 28 /* mutex between sync_cpu_buffers() and the
+28
drivers/oprofile/oprof.c
··· 53 53 * us missing task deaths and eventually oopsing 54 54 * when trying to process the event buffer. 55 55 */ 56 + if (oprofile_ops.sync_start) { 57 + int sync_ret = oprofile_ops.sync_start(); 58 + switch (sync_ret) { 59 + case 0: 60 + goto post_sync; 61 + case 1: 62 + goto do_generic; 63 + case -1: 64 + goto out3; 65 + default: 66 + goto out3; 67 + } 68 + } 69 + do_generic: 56 70 if ((err = sync_start())) 57 71 goto out3; 58 72 73 + post_sync: 59 74 is_setup = 1; 60 75 mutex_unlock(&start_mutex); 61 76 return 0; ··· 133 118 void oprofile_shutdown(void) 134 119 { 135 120 mutex_lock(&start_mutex); 121 + if (oprofile_ops.sync_stop) { 122 + int sync_ret = oprofile_ops.sync_stop(); 123 + switch (sync_ret) { 124 + case 0: 125 + goto post_sync; 126 + case 1: 127 + goto do_generic; 128 + default: 129 + goto post_sync; 130 + } 131 + } 132 + do_generic: 136 133 sync_stop(); 134 + post_sync: 137 135 if (oprofile_ops.shutdown) 138 136 oprofile_ops.shutdown(); 139 137 is_setup = 0;
+6 -4
include/asm-powerpc/oprofile_impl.h
··· 39 39 40 40 /* Per-arch configuration */ 41 41 struct op_powerpc_model { 42 - void (*reg_setup) (struct op_counter_config *, 42 + int (*reg_setup) (struct op_counter_config *, 43 43 struct op_system_config *, 44 44 int num_counters); 45 - void (*cpu_setup) (struct op_counter_config *); 46 - void (*start) (struct op_counter_config *); 47 - void (*global_start) (struct op_counter_config *); 45 + int (*cpu_setup) (struct op_counter_config *); 46 + int (*start) (struct op_counter_config *); 47 + int (*global_start) (struct op_counter_config *); 48 48 void (*stop) (void); 49 49 void (*global_stop) (void); 50 + int (*sync_start)(void); 51 + int (*sync_stop)(void); 50 52 void (*handle_interrupt) (struct pt_regs *, 51 53 struct op_counter_config *); 52 54 int num_counters;
+15
include/asm-powerpc/spu.h
··· 138 138 struct spu_runqueue *rq; 139 139 unsigned long long timestamp; 140 140 pid_t pid; 141 + pid_t tgid; 141 142 int class_0_pending; 142 143 spinlock_t register_lock; 143 144 ··· 217 216 /* Calls from the memory management to the SPU */ 218 217 struct mm_struct; 219 218 extern void spu_flush_all_slbs(struct mm_struct *mm); 219 + 220 + /* This interface allows a profiler (e.g., OProfile) to store a ref 221 + * to spu context information that it creates. This caching technique 222 + * avoids the need to recreate this information after a save/restore operation. 223 + * 224 + * Assumes the caller has already incremented the ref count to 225 + * profile_info; then spu_context_destroy must call kref_put 226 + * on prof_info_kref. 227 + */ 228 + void spu_set_profile_private_kref(struct spu_context *ctx, 229 + struct kref *prof_info_kref, 230 + void ( * prof_info_release) (struct kref *kref)); 231 + 232 + void *spu_get_profile_private_kref(struct spu_context *ctx); 220 233 221 234 /* system callbacks from the SPU */ 222 235 struct spu_syscall_block {
+1
include/linux/dcookies.h
··· 12 12 13 13 #ifdef CONFIG_PROFILING 14 14 15 + #include <linux/dcache.h> 15 16 #include <linux/types.h> 16 17 17 18 struct dcookie_user;
+2 -1
include/linux/elf-em.h
··· 20 20 #define EM_PARISC 15 /* HPPA */ 21 21 #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ 22 22 #define EM_PPC 20 /* PowerPC */ 23 - #define EM_PPC64 21 /* PowerPC64 */ 23 + #define EM_PPC64 21 /* PowerPC64 */ 24 + #define EM_SPU 23 /* Cell BE SPU */ 24 25 #define EM_SH 42 /* SuperH */ 25 26 #define EM_SPARCV9 43 /* SPARC v9 64-bit */ 26 27 #define EM_IA_64 50 /* HP/Intel IA-64 */
+35
include/linux/oprofile.h
··· 17 17 #include <linux/spinlock.h> 18 18 #include <asm/atomic.h> 19 19 20 + /* Each escaped entry is prefixed by ESCAPE_CODE 21 + * then one of the following codes, then the 22 + * relevant data. 23 + * These #defines live in this file so that arch-specific 24 + * buffer sync'ing code can access them. 25 + */ 26 + #define ESCAPE_CODE ~0UL 27 + #define CTX_SWITCH_CODE 1 28 + #define CPU_SWITCH_CODE 2 29 + #define COOKIE_SWITCH_CODE 3 30 + #define KERNEL_ENTER_SWITCH_CODE 4 31 + #define KERNEL_EXIT_SWITCH_CODE 5 32 + #define MODULE_LOADED_CODE 6 33 + #define CTX_TGID_CODE 7 34 + #define TRACE_BEGIN_CODE 8 35 + #define TRACE_END_CODE 9 36 + #define XEN_ENTER_SWITCH_CODE 10 37 + #define SPU_PROFILING_CODE 11 38 + #define SPU_CTX_SWITCH_CODE 12 39 + 20 40 struct super_block; 21 41 struct dentry; 22 42 struct file_operations; ··· 55 35 int (*start)(void); 56 36 /* Stop delivering interrupts. */ 57 37 void (*stop)(void); 38 + /* Arch-specific buffer sync functions. 39 + * Return value = 0: Success 40 + * Return value = -1: Failure 41 + * Return value = 1: Run generic sync function 42 + */ 43 + int (*sync_start)(void); 44 + int (*sync_stop)(void); 45 + 58 46 /* Initiate a stack backtrace. Optional. */ 59 47 void (*backtrace)(struct pt_regs * const regs, unsigned int depth); 60 48 /* CPU identification string. */ ··· 82 54 * One-time exit/cleanup for the arch. 83 55 */ 84 56 void oprofile_arch_exit(void); 57 + 58 + /** 59 + * Add data to the event buffer. 60 + * The data passed is free-form, but typically consists of 61 + * file offsets, dcookies, context information, and ESCAPE codes. 62 + */ 63 + void add_event_entry(unsigned long data); 85 64 86 65 /** 87 66 * Add a sample. This may be called from any context. Pass